Piped comanda o desempenho no Linux embarcado

3

Recentemente, compramos uma solução de software para integrar em um dispositivo que estamos desenvolvendo. Há muito o que precisamos para modificar e adaptar às nossas necessidades, então hoje eu estava passando por parte do código para ver o que precisaria mudar e o que quer que fosse e comecei a pensar em algo.

Analisando alguns dos scripts, vi algumas linhas que chamaram minha atenção. Por exemplo, um era algo assim:

cat file | grep ^field | head -n1 | sed 's/:/ /' | awk '{print $1}'

Isso pareceu um pouco bobo quando você pode fazer tudo facilmente com uma única chamada para awk , talvez algo como:

awk -F':' '/^field/ {print $1; exit}' file

Depois disso, comecei a prestar mais atenção a isso e encontrei muitas situações semelhantes. Algumas não me interessam porque são executadas durante a inicialização. Outros, por outro lado, são chamados com bastante frequência.

Isso significa que tenho scripts gerando processos em todos os lugares para tarefas que podem ser realizadas com muito menos. Agora, o que eu realmente comecei a imaginar ... será que a tubulação começa a prejudicar o desempenho em algum momento? Particularmente, se houver uma alternativa menos " canalizada ".

Tenha em mente que estou executando um Linux embarcado em uma plataforma com muito menos recursos que um PC real. Embora para o bem da questão, talvez isso não importe.

    
por elpato 02.02.2016 / 23:31

2 respostas

2

Às vezes, é mais fácil criar um perfil:

Eu criei um arquivo de entrada de amostra:

aaaaa:bbbbb:ccccc
aaaaa:bbbbb:ccccc
aaaaa:bbbbb:ccccc
aaaaa:bbbbb:ccccc
field:bbbbb:ccccc
aaaaa:bbbbb:ccccc
aaaaa:bbbbb:ccccc
aaaaa:bbbbb:ccccc
aaaaa:bbbbb:ccccc

script de shell 'a.sh':

#!/bin/bash
for i in 'seq 1 1000'; do
        cat test.dat | grep ^field | head -n1 | sed 's/:/ /' | awk '{print $1}' >/dev/null
done

script de shell 'b.sh':

#!/bin/bash
for i in 'seq 1 1000'; do
        awk -F':' '/^field/ {print $1; exit}' test.dat >/dev/null
done

Perfil:

time ./a.sh
real    0m10.253s
user    0m5.526s
sys 0m8.668s

time ./b.sh
real    0m3.274s
user    0m1.288s
sys 0m1.783s

(Isso foi feito no meu antigo amado MacBook 2008, Intel Core 2 Duo de 2,4 GHz)

Então, obviamente, sua versão é muitas vezes mais rápida. No entanto, esses são os tempos para 1000 invocações. Dependendo da frequência em que esse código de shell é executado, você pode economizar apenas alguns milissegundos.

    
por 03.02.2016 / 00:34
1

O desempenho é complicado. A única maneira de ter certeza é fazer benchmark em um sistema real com uma carga real.

Piping vários utilitários definitivamente tem um custo. Comparado com as operações de string, esse custo é muito alto. No entanto, se a quantidade de dados for grande o suficiente, uma solução de canal pode ser mais rápida, pois pode permitir que ferramentas especializadas realizem seu trabalho mais rapidamente e permitir processamento de dados paralelo (se a máquina for multicore e houver processamento útil suficiente) ser feito em paralelo para que valha a pena). Mas se a quantidade de dados é pequena, o custo para iniciar os programas é predominante. O ponto em que o fator dominante muda é muito dependente do sistema e do cenário de uso.

De um modo geral, quanto mais versátil for uma ferramenta, mais lenta ela é. Portanto, se você tiver uma tarefa que grep ou head possa fazer, geralmente sed também poderá fazê-lo, mas não tão rápido; e awk será ainda mais lento. Esta é apenas uma regra geral; Se você procurar, poderá encontrar implementações específicas e cargas de trabalho específicas, nas quais o awk ou o sed superam outras ferramentas. O volume de dados tem que ser suficientemente alto para que a diferença seja observável.

Para pequenos volumes de dados, o número de startups de processos é o custo dominante. De um modo geral, quanto mais versátil for uma ferramenta, mais lenta será a inicialização. O lançamento de várias ferramentas tem um custo de desempenho em si, porque significa que mais código precisa ser carregado na memória. No entanto, se você usar o BusyBox, onde todas as ferramentas estão agrupadas em um único executável, esse aspecto será minimizado.

A partir de

cat file | grep ^field | head -n1 | sed 's/:/ /' | awk '{print $1}'

a invocação de cat é inútil e não pode ajudar no desempenho. Usar grep ^field | head -n1 | sed 's/:/ /' pode ter uma pequena vantagem se o volume de dados for muito grande, mas na maioria dos cenários eu esperaria

<file sed -n '/^field/ { s/:/ /p; q; }'

ser mais rápido porque evita ter que esperar por vários processos.

Quanto à invocação do awk, simplesmente não é necessário aqui. Se não houver dois pontos iniciais, o comando é equivalente a

<file sed -n '/^field/ { s/:.*//p; q; }'

ou, se grep provar ter uma vantagem,

<file grep '^field' | sed -e 's/:.*//' -e 'q'

E se houver dois pontos iniciais, apenas adicione s/^::*// no início do comando sed .

    
por 03.02.2016 / 02:14