Temporização estável para scripts de shell?

4

Os tempos de execução dos scripts variam bastante. Eu gostaria de encontrar um time-function similar como o timeit do Matlab, descrito aqui .

Por exemplo, estou avaliando esses comandos aqui sobre a contagem rápida de correspondências, executando time LC_ALL=C grep -ao CDA r328_0002.raw | wc -l no loop

---------------------------------------------
Events      real        user        sys
----------- ----------- ----------- ---------
40          0m0.044s    0m0.042s    0m0.005s
40          0m0.064s    0m0.062s    0m0.005s
40          0m0.046s    0m0.044s    0m0.005s
40          0m0.043s    0m0.042s    0m0.005s
40          0m0.047s    0m0.044s    0m0.005s
---------------------------------------------

Table: Events when Macbook Air 2013-Mid in Power Supply. 

---------------------------------------------
Events      real        user        sys
----------- ----------- ----------- ---------
40          0m0.056s    0m0.041s    0m0.011s
40          0m0.060s    0m0.047s    0m0.008s
40          0m0.041s    0m0.039s    0m0.006s
40          0m0.046s    0m0.044s    0m0.006s
40          0m0.047s    0m0.045s    0m0.006s
---------------------------------------------

Table: Events when Macbook Air in Battery Supply, 6h later.  

onde você vê o tempo real varia de 0,044s a 0,064s, o tempo de usuário de 0,042s a 0,062s, enquanto o tempo de sys se mantém bastante estável a 0,005s. Minha ideia em tempo

  • iterar o comando primeiro 1k antes do tempo
  • faça o tempo 10 vezes e faça a média e o desvio padrão

Stout para / dev / nul

Esta ideia está no comentário do lcd047, executando time LC_ALL=C ggrep -ao CDA r328_0002.raw >/dev/null no loop

--------------------------------------------
real            user            sys
--------------  --------------  ------------
0m0.006s        0m0.003s        0m0.002s
0m0.006s        0m0.003s        0m0.002s
0m0.006s        0m0.003s        0m0.002s
0m0.008s        0m0.003s        0m0.003s
0m0.006s        0m0.003s        0m0.002s
0m0.005s        0m0.002s        0m0.002s
0m0.006s        0m0.002s        0m0.002s
0m0.009s        0m0.003s        0m0.003s
0m0.007s        0m0.003s        0m0.003s
0m0.006s        0m0.003s        0m0.002s
0m0.006s        0m0.003s        0m0.002s
0m0.008s        0m0.003s        0m0.003s
--------------------------------------------

Table: Events when Macbook Air 2013-Mid in Battery Supply. 

Acho que esses tempos podem ser ainda mais aprimorados ao manter o laptop na fonte de alimentação e manter menos programas ativados.

Como você pode sincronizar scripts de shell de forma estável?

    
por Léo Léopold Hertz 준영 01.07.2015 / 07:49

2 respostas

6

A resposta é: você não pode! Linux não é um sistema em tempo real. A idéia do UNIX e, portanto, do Linux, também é fornecer tempos mínimos de resposta, enquanto o sistema é compartilhado entre vários usuários e processos do sistema. Dependendo de quando você inicia o comando, talvez seja necessário aguardar que um processo importante do sistema forneça sua parcela de tempo do processador. Além disso, o sistema de arquivos pode armazenar em buffer o arquivo que você leu no disco, mas, eventualmente, esse buffer do sistema de arquivos falha ao carregar os dados do cache, quando outro processo em seu sistema o ocupa. Geralmente, o tempo que um processo precisa em um sistema Linux depende da entropia circundante da máquina, onde quer que ela esteja localizada no tempo e no espaço do universo.

Você precisará de um sistema em tempo real e, especialmente, de comandos ajustados em tempo real e uma quantidade específica de recursos reservados apenas para você. Você pode chegar perto disso com novos recursos CGROUP dos kernels mais recentes, onde você pode reservar um processador, uma parte da memória e um reflexo do sistema de arquivos subjacente para o seu ambiente.

Um dos principais problemas de temporização no seu exemplo é a maneira como o grep e o wc lêem as entradas. Você pode tornar o tempo mais estável quando copiar seu arquivo em um ramfs e trabalhar lá.

    
por 01.07.2015 / 10:23
4

Para começar, você precisa entender que os shell scripts são apenas um atalho conveniente para digitar os comandos. Toda vez que você ou um script chama grep , você não está chamando uma primitiva integrada; você está pedindo ao shell para procurar um programa chamado grep e iniciá-lo como um novo processo. A criação de um novo processo e a execução do primeiro bit de código é provavelmente a coisa menos previsível que você pode fazer em qualquer ambiente que não esteja ajustado para a previsibilidade. Esse será o caso de qualquer computador que esteja executando um sistema operacional que não seja em tempo real. Os detalhes de por que isso seria forrageiro para metade de uma classe semestral em sistemas operacionais, mas posso dar um exemplo ou dois que ilustrem por que seus esforços para medir com precisão as execuções completas do programa não produzirão os resultados consistentes que você pensa eles deveriam.

A primeira coisa que a maioria dos programas faz quando recebe a CPU pela primeira vez é gerar uma falha de página para que o código de primeira página possa ser carregado. Se uma dúzia de outros programas estiverem fazendo E / S no mesmo dispositivo em que o código mora, o tempo que as páginas do seu programa demoram para carregar depende de quão longe estão as solicitações na fila do dispositivo. Você pode pensar que seu programa de teste está funcionando sozinho, mas eu apostaria dólares em donuts que não é. (Também vale a pena mencionar que grep é um programa pesado de I / O, então quanto tempo leva para ler a entrada varia por muitas das mesmas razões.)

Muitos sistemas operacionais tomam medidas para evitar que cópias redundantes do mesmo código permaneçam ao mesmo tempo, como uma maneira de reduzir o consumo de memória e aumentar o desempenho. Isso significa que, se você iniciar grep e houver outro grep em execução com sua primeira página já residente, a falha de página mencionada nunca acontecerá e todo esse esforço será ignorado. Isso diminui o tempo de execução do relógio de parede.

No momento em que você começa a fazer um timeit no MATLAB, o processo do MATLAB já está em execução e é provável que ele tenha passado pelos aros necessários para carregar sua função antes de invocá-la repetidamente. A invocação acontece com bastante rapidez porque é apenas uma chamada interna. Embora também haja muitos fatores que afetariam o tempo que leva timeit para ser executado, eles se aplicam igualmente a qualquer outra coisa.

Dito isso, acho que a verdadeira razão para o que você está vendo é que a comparação não é do mesmo jeito.

O time(1) do Unix executa o programa sendo testado exatamente uma vez, onde o timeit do MATLAB multiplicou a função que você está testando várias vezes e retorna a mediana dos resultados. A documentação sugere que as funções timeit e tic e toc não devem ser usadas juntas, o que sugere que as últimas são usadas pela primeira. Os documentos para tic e toc recomendam que, se você tiver um código que seja executado em menos de 0,1 segundo, execute-o várias vezes e calcule uma média. O que eu tomo disso é que o tempo do MATLAB é duas ordens de grandeza menos preciso do que o de time(1) e se destina mais a verificar quanto tempo você pode se livrar das funções de longa duração. Isso e a combinação da média e da mediana, dada amostras suficientes, empurram muita variação para um resultado bastante consistente.

    
por 30.12.2016 / 19:24