O yes do GNU é mais rápido que o yes do BusyBox?
14/01/2026
Olá a todos! Como vão? Espero que estejam bem. Outro dia eu estava investigando o comportamento dos comandos do Linux, o que me levou a notar que o yes do GNU é mais rápido que em outras implementações, como o BusyBox ou o BSD.
O que é o yes?
O comando yes é um utilitário extremamente simples: imprime repetidamente uma string (por padrão y) até que o processo seja interrompido ou a saída falhe. Apesar de sua simplicidade funcional e de seu uso reduzido pela evolução dos programas de terminal, existem implementações com filosofias muito diferentes, como as do GNU coreutils e do BusyBox.
Desta vez, vou conduzir um experimento prático para comparar ambas as implementações, analisando os resultados obtidos e concluindo se a complexidade do yes do GNU se justifica para o uso no mundo real.
Descrição do experimento
Foram realizados dois tipos de testes:
Teste de desempenho bruto (sem terminal)
/bin/yes | pv > /dev/null
busybox yes | pv > /dev/null
/bin/yesé a implementação do GNU, enquantobusybox yesé a implementação do BusyBox.
Esse teste mede quantos dados cada implementação consegue gerar quando a saída não é limitada por um dispositivo lento (como um terminal), mas sim por um pipe e pelo kernel.
Teste prático (saída no terminal)
(sleep 10 && pkill /bin/yes) & /bin/yes
(sleep 10 && pkill busybox) & busybox yes
Neste teste, ambos os comandos escrevem diretamente no terminal por 10 segundos. Conta-se o número aproximado de linhas geradas e observa-se o consumo de memória.
Resultados
Desempenho bruto
Saída do terminal:
ItsZariep@PC~-> /bin/yes | pv > /dev/null
37.7GiB 0:00:10 [3.96GiB/s] [<=>]
ItsZariep@PC~-> busybox yes | pv > /dev/null
991MiB 0:00:07 [99.0MiB/s] [<=>]
yesdo GNU: vários GiB/s (≈ 3-4 GiB/s)yesdo BusyBox: vários MiB/s (≈ 100 MiB/s)
A diferença é de várias ordens de grandeza.
Teste prático no terminal
yesdo GNU: ~50.120linhas em 10 segundosyesdo BusyBox: ~49.994linhas em 10 segundos
As linhas foram contadas com precisão graças ao
tmux.
A diferença é pequena e quase imperceptível.
Uso de RAM
Segundo o htop, top e btop:
yesdo BusyBox:570 KiB(0,5 MiB)yesdo GNU:5900 KiB(5 MiB)
yesdo GNU: aproximadamente 10× mais memória que oyesdo BusyBox.
Análise técnica
Por que o yes do GNU é tão rápido em pipes
O yes do GNU:
Segundo o código-fonte do GNU coreutils, especificamente:
/* If a larger buffer was allocated, fill it by repeating the buffer
contents. */
size_t copysize = bufused;
for (size_t copies = bufalloc / copysize; --copies;)
{
memcpy (buf + bufused, buf, copysize);
bufused += copysize;
}
- Constrói um buffer grande (dezenas de KiB) contendo várias repetições da saída.
- Usa
writediretamente. - Reduz drasticamente o número de chamadas de sistema ao armazenar em buffer repetições do “y”.
Isso permite um uso extremamente eficiente do kernel e da largura de banda de memória, ao custo de usar mais memória.
Por que o yes do BusyBox é “mais lento”
O yes do BusyBox:
Segundo o código-fonte do BusyBox no GitHub:
do {
pp = argv;
while (1) {
fputs_stdout(*pp);
if (!*++pp)
break;
putchar(' ');
}
} while (putchar('\n') != EOF);
- Usa
stdio(putchar,fputs). - Escreve apenas alguns bytes por iteração.
- Realiza muitas operações de alto nível.
Isso introduz sobrecarga no espaço do usuário e limita o desempenho máximo, apesar de usar menos memória.
O terminal como gargalo
Quando a saída vai para o terminal:
- Renderização
- Gerenciamento do scrollback
- Line discipline
limitam a velocidade a alguns milhares de linhas por segundo. Nesse cenário, nenhuma das otimizações do yes do GNU oferece uma vantagem significativa. (Usar um terminal acelerado como o Kitty também não faz muita diferença; os testes usaram Alacritty, foot e qterminal.)
O yes do GNU é superdimensionado?
Do ponto de vista prático:
- A maioria dos usos do
yesé interativa ou de curta duração. - O terminal domina o custo geral.
- O maior uso de memória não traz benefícios visíveis.
Da filosofia do GNU coreutils:
- O
yesdeve ser o mais eficiente possível. - Ele nunca deve se tornar o gargalo.
- Deve ter bom desempenho mesmo em benchmarks sintéticos ou extremos.
Ambas as posições são consistentes com seus respectivos objetivos.
Outras implementações
BSD
int
main(int argc, char *argv[])
{
if (argc > 1)
for (;;)
puts(argv[1]);
else
for (;;)
puts("y");
}
- É mais simples que o BusyBox e tem desempenho relativamente parecido.
- Usa
putsque, embora tenha um buffer interno no BSD, é mais lento e ainda resulta em mais chamadas de sistema.
UUtils
fn prepare_buffer(buf: &mut Vec<u8>) {
if buf.len() * 2 > BUF_SIZE {
return;
}
assert!(!buf.is_empty());
let line_len = buf.len();
let target_size = line_len * (BUF_SIZE / line_len);
while buf.len() < target_size {
let to_copy = std::cmp::min(target_size - buf.len(), buf.len());
debug_assert_eq!(to_copy % line_len, 0);
buf.extend_from_within(..to_copy);
}
}
- É um port bastante fiel da implementação do GNU.
- Em vez de imprimir
"y"a cada iteração, imprime blocos de 16 KB de uma só vez usandostdout.write_all(bytes). - Deveria ser ainda mais rápido em benchmarks sintéticos.
Resultados
Para o uso cotidiano, o yes do BusyBox é suficiente, mais simples e mais eficiente em memória.
O yes do GNU, embora claramente superdimensionado para o caso de uso típico, alcança seu objetivo de maximizar o desempenho em cenários ideais, como pipes rápidos ou testes de estresse.
O experimento demonstra que uma implementação “melhor” depende do contexto: desempenho teórico máximo versus simplicidade e adequação ao mundo real.
Conclusão
Para o yes em cenários do mundo real, a implementação do GNU poderia ser considerada excessiva.
Mas essa complexidade não é um erro; é, antes, uma consequência direta de uma filosofia de projeto diferente.


