Programa SIGNIFICAMENTE mais lento quando usado a partir do TTY

4

Então eu tenho um programa escrito em C ++.

Ele pode me dizer quanto tempo demorou para fazer todos os cálculos e faz um cálculo muito pesado e multi-thread.

Acabei de notar que, se eu executar o programa exatamente na mesma máquina, demora cerca de 20-21 segundos para fazer todos os cálculos, se iniciado a partir do TTY, e apenas 0,2 segundos, se eu iniciá-lo a partir do terminal GNOME .

O que está causando isso? É literalmente o mesmo arquivo na mesma máquina.

    
por Mac B 13.01.2017 / 19:04

1 resposta

5

Alguma teoria de fundo

Bem, o que você trabalha depois de CTRL + ALT + F1 e do Terminal GNOME são diferentes implementações do mesmo conceito: emulando um terminal chamado de tela cheia.

A primeira coisa é chamada de terminal virtual (VT) no Linux, ou geralmente apenas "console". Ele usa um modo de vídeo "somente de texto" especial ainda fornecido pelas placas de vídeo de hardware nas plataformas compatíveis com x86 (ou seja, aquelas da herança "IBM PC"). Este último é um aplicativo GUI.

Ambos fornecem aplicativos que executam com a ajuda deles / delas um jogo de instalações tal aplicação espera de "um dispositivo terminal" (mais detalhes e mais ponteiros— aqui ).

O problema em questão

OK, agora vamos para a lentidão percebida.

Tenho certeza que o ponto crucial do seu problema é que o seu programa faz a chamada E / S de "bloqueio". Isto é, cada vez que você faz algo como

std::cout << "Hello, world" << endl;

em seu código, primeiro o código da biblioteca padrão C ++ vinculada ao seu aplicativo entra em ação e processa a saída das coisas enviadas para o fluxo indicado.

Após determinado processamento (e mais comumente algum armazenamento em buffer), esses dados precisam, na verdade, deixar o processo em execução de seu programa e obter realmente a saída para qualquer mídia para a qual seus programas enviam sua saída. No Linux (e em outros sistemas compatíveis com Unix), isso requer chamar o kernel - por meio de uma chamada de sistema dedicada (ou syscall para o short) chamada write() .

Portanto, o stdlib do C ++ finalmente faz com que write() syscall e aguarde que ele seja concluído - isto é, ele aguarda o kernel dizer "OK, o receptor dos dados disse que o adquiriu".

Como você pode deduzir, o receptor dos dados que seu programa produz é o terminal (emulador) rodando seu programa - um Linux VT ou uma instância do GNOME Terminal em seus testes. (A imagem completa é mais complicada, pois o kernel não envia os dados direito em um emulador de terminal em execução, mas não vamos complicar a descrição.)

E assim a velocidade com que write() syscall completa depende muito da rapidez com que o receptor dos dados lida com isso! No seu caso, o GNOME Terminal é mais rápido.

Meu ponto strong é que o driver do VT renderiza todos os dados que estão sendo enviados, rola-os, etc., enquanto o Terminal do GNOME otimiza rajadas de dados de entrada, renderizando apenas a parte final (o que se encaixa no tamanho da tela do terminal) e coloca o resto no chamado "scroll buffer" que a maioria dos emuladores de terminal GUI tem.

Os tópicos a serem feitos

A coisa crucial para levar isso é que assim que seu programa executa qualquer E / S junto com cálculos, e você mede a velocidade de cálculo dos programas usando o temporizador "relógio de parede", você normalmente pode medir a velocidade dessa E / S, não a velocidade de cálculos.

Note que E / S é complicado: seu processo pode ser preempted pelo SO quando ele está prestes a aguardar algum recurso de E / S para disponível para gravação - como disco rígido.

Portanto, a maneira certa de medir o desempenho "bruto" de cálculos é ter algum recurso em seu programa para desabilitar todo o I / O. Se isso não for possível ou for muito feio para implementar, pelo menos tente direcionando toda a saída para um chamado "dispositivo nulo", /dev/null , executando seu programa como

$ ./program >/dev/null

O dispositivo nulo simplesmente descarta todos os dados passados para ele. Então, sim, ainda cada rodada de E / S realizada pelo stdlib do C ++ atingirá o kernel mas pelo menos você terá uma velocidade de escrita quase constante (e quase instantânea).

Se você precisar de ambas as medidas e os dados gerados, considere a criação de um chamado disco RAM e redirecione a saída para um arquivo localizado lá.

Mais um sobre medição: note que mesmo em um sistema aparentemente inativo rodando um sistema operacional (como seu Ubuntu ou qualquer outro), a CPU nunca dorme - sempre há algumas tarefas fazendo coisas em segundo plano. Isso significa que medir o desempenho da computação mesmo sem qualquer E / S ou com uma E / S de "desativação" (conforme explicado acima) ainda produzirá resultados diferentes em cada execução.

Para compensar isso, um bom benchmarking significa executar seu cálculo com os mesmos dados de entrada vários milhares de vezes e calcular a média dos resultados em relação ao número de execuções.

    
por 14.01.2017 / 13:22