 |
Analisando e comparando seis diferentes implementações do comando sed |
Em abriu deste ano eu escrevi o artigo
minised: Um sed melhor do que o sed. sed é um comando que como seu próprio nome sugere (
Stream
EDitor), serve para editar/alterar as informações que são exibidas em sua tela (observação que deve ser feita é que arquivos acessados através do sed não são modificados, apenas a forma como as informações são exibidas; a não ser que as informações exibidas sejam redirecionadas ao arquivo de origem). sed Foi um dos primeiros comandos desenvolvidos para o Unix para processamento de dados e, conforme o
e-mail de lançamento do kernel Linux 0.02 "intitulado Códigos livres de kernel parecido com minix para AT-386" no grupo
comp.os.minix, é descrito que sed também foi um dos primeiros comandos a ser utilizado pelo Linux:
"Ainda está na versão 0.02 (+1 (muito pequeno) patch já), mas executei com sucesso bash/gcc/gnu-make/gnu-sed/compress nele."
O gnu-sed é a implementação utilizada na maioria das distribuições Linux porém, como existem diferentes implementações do mesmo comando (assim como existem diferentes implementações de todos os comandos e de todas as ferramentas), eu resolvi analisar e comparar ao menos seis delas apresentando aqui neste artigo os resultados de cada uma.
- Licença
- Tamanho do binário
- Recursos disponíveis
- descrição de ajuda
- Desempenho
- bugs
Para os testes eu utilizei o terminal de comandos
zsh por proporcionar melhores informações (inclusive uso de
CPU por padrão) e devido o Bash por vezes já ter apresentado bugs que não podem nos garantir confiabilidade nos resultados
(leia mais sobre os bugs que encontrei no bash clicando aqui). Em conjunto eu utilizei o comando
time.
 |
Diferença de exibição de resultados do comando time entre os terminais de comando bash e zsh. |
Fiz uso dos materiais públicos
aurelio,
the mouseless Dev que
possui até mesmo um mapa mental muito interessante, o manual gnu-sed e os próprios arquivos de testes disponibilizados pelos próprios comandos.
Ao final de cada teste, eu irei classificar uma ou mais implementações como vencedores e na conclusão do artigo eu irei classificar da primeira a terceira colocação a partir da que proporcionar a maior quantidade de vantagens. Agora vamos partir para o arrebento.
LICENÇAS
Neste primeiro tópico eu analiso quais as licenças adotadas por cada implementação levando em conta que cada licença proporciona vantagens e desvantagens. Parece um assunto irrelevante, mas trata-se de algo que pode afetar fortemente todo o mercado, todo um ecossistema e automaticamente você (se hoje o busybox estivesse sob GPLv3, provavelmente você nem teria um roteador em sua casa).
 |
Licenças adotadas por cada implementação do comando |
O
sbase e o
9base estão sob
MIT (9base sob
MIT/X Consortium License); o minised foi disponibilizado sob GPL a partir da
versão 1.13 e passou a ser disponibilizado sob
BSD-like a partir da
versão 1.14 em diante com o consentimento de Eric Raymond. O toybox está sob a
clausula zero BSD (0-BSD) criada por
Rob Landley que na verdade trata-se de uma
Domínio Publico apenas sob o nome de BSD (com a aprovação dos próprios membros dos BSDs).
VENCEDOR: Com exceção da GPL (
que possui tendência natural a declínio), todos as demais licenças são muito boas. O busybox_SED ainda pode levar alguma vantagem com a GPLv2 por não ser incompatível com o kernel Linux e ser menos negativamente impactante que a GPLv3.
TAMANHO DOS BINÁRIOS
Tenha em mente que, quanto menor o binário, melhor é em todos os sentidos (segurança, desempenho, modularidade e portabilidade). Códigos menores se tornam mais fáceis de manter e serem atualizados.
Como mencionado no site do projeto embutils (que infelizmente não entrou para nossa lista), o userland dos Unix geralmente é composto de comandos dos BSDs e do projeto gnu. Na época que surgiram, as técnicas de desenvolvimento eram diferentes; os projetos focavam somente em
recurso, mas não na otimização do tamanho.
 |
Passe o cursor sobre a imagem para ler a tradução |
Para certos dispositivos como embarcados e até mesmo para o processo de boot, binários tão grandes são simplesmente inviáveis. E parece não fazer sentido, mas mesmo em ambientes como desktop, servidores e até supercomputadores, binários menores também são extremamente importantes pois assim o sistema ocupa menos espaço tanto em memória RAM quanto em dispositivo de armazenamento (óbvio; quanto menor espaço o sistema operacional ocupar, melhor é), é carregado mais rápido pela cache L2 por exemplo e deixa a carga do processador mais livre.
Há ressalvas a serem feitas durante as avaliações como sua ligação se dinâmica ou estática, quais bibliotecas foram utilizadas, qual compilador e com quais flags e assim por diante. As ressalvas foram feitas em asteriscos (*).
 |
Tamanho de cada implementação do comandos sed. |
*Relembrando aqui que menor significa melhor
**Eu compilei o minised estaticamente a
dietlibc.
***Consta no site do busybox que o busybox_SED possui 89K; porém, após baixar, seu tamanho final é de 92K (também likado estaticamente.
Baixe aqui para conferir).
**** Eu compilei o sed do toybox dinamicamente para que pudéssemos saber o seu real tamanho.
VENCEDOR: Neste caso eu deixo três colocados. O toybox sed em primeiro com apenas 36k; o minised em segundo com apenas 44k, e o sbase sed em terceiro com 56K.
.png) |
Comparação de tamanhos entre minised linkado estaticamente e toybox sed linkado dinamicamente |
Você deve estar se perguntando se não seria injusto sendo que o toybox foi ligado dinamicamente enquanto quer o minised estaticamente. E a resposta é que o minised, mesmo ligado dinamicamente, é maior do que toybox sed. Confiram os resultados na imagem abaixo.
.jpg) |
Reparem a quantidade de comandos dentro do toybox 0.8.7 em apenas 716k (sendo um deles, o comando sed que está selecionado nesta imagem). |
RECURSOS
É agora que constataremos se o tamanho dos binários fazem jus à quantidade de recursos. Reforçando o que foi dito no tópico anterior, quanto menor o binário, melhor é porém, não vai adiantar muito o binário ser pequeno e enxuto se não conter os recursos necessários para a sua adoção.
Além do mais, esse é um ponto extremamente importante pois uma regra histórica que não falha é que, mesmo que um programa contenha certos bugs, mas possui os recursos que as pessoas querem (ou precisam), elas aceitam conviver com tais bugs. Tudo uma questão de prós e contras; além do que os bugs podem ser corrigidos ao longo do tempo (ou não, vai saber a complexidade).
Podemos dizer que neste tópico o gnu-sed dispensa explicações pois um ponto forte das ferramentas do gnu (não por total mérito seu) mas que é mal divulgado pelo próprio projeto é exatamente a parte de recursos possuindo até mesmo extensões próprias. OK para o gnu-sed.
No arquivo
BUG do minised é descrito
"Focarão nas conformidades POSIX e pequeno tamanho - extensões do GNU sed provavelmente não serão aceitas". O minised possui um diretório chamado
tests que após compilá-lo, podemos executar o
script run, conforme descrito em seu arquivo
Makefile (
cd tests; ./run ../minised) ou bastando executar o comando
make check que se encarregará de fazer esse trabalho (realizando o total de
68 testes). Um dos testes falha (especificamente o
empty-lhs), mas como descrito no próprio resultado, essa falha é intencional.
 |
Testes disponibilizados pelo próprio minised |
O toybox também disponibiliza seus próprios arquivos de teste também dentro do diretório tests. No total, ele realiza 91 testes com o toybox sed.
 |
Teste disponibilizados pelo próprio toybox |
O toybox sed possui uma lista dentro do seu próprio código fonte com algumas pequenas pendências a serem ajustados como "fazer y// lidar com delimitadores unicode, lidar com retorno de erro a partir do emit(), error_msg/exit consistentemente", "Qual a coisa certa a se fazer com -i quando escrever as falhas? Skip ou next?". Eu considero uma lista baixa; lógico que prefiro ver estas questões sanadas, mas são consideráveis.
Eu não encontrei algumas pendências tanto no sbase quanto no 9base e não foram ruim nos testes.
VENCEDOR: Empate geral. Em todos os testes que eu realizei, todas as implementações conseguiram processar com sucesso.
DESCRIÇÃO DE AJUDA
Descrições de ajuda (--help e manpages) assim como as licenças, parecem ser irrelevantes, porém pense no seguinte cenário; você está administrando o seu sistema, precisa consultar uma opção e sabe que tal comando não possui opção de ajuda. Até aí, tudo bem, basta consultar a manpage... Certo?...
A resposta é... depende de qual distribuição estamos falando. Distribuições como
Alpine Linux ou
Porteus não possuem manpages por padrão. E se de repente você não possui acesso a internet? O que você faz?...
Do que adiante um programa conter todos os recursos necessários sendo que não vem com as informações de como utilizá-los? Seria o mesmo que uma TV não acompanhar manual de instruções. Alias, eu já vi empresas adotarem uma certa distribuição devido a facilidade em encontrar informações e soluções de problemas. Então, por mais que pareça algo irrelevante, descrições de ajuda é algo extremamente importante.
E aqui vamos nós para a nossa analise. O minised, apesar de possuir uma boa
manpage, não possui a opção
--help por padrão. Eu acredito que poderia possuir ao menos uma leve descrição assim no sbase e no 9base. Ou melhor, assim como o busybox_SED; enxuta e explicativa.
 |
Descrição de ajuda do minised e do sbase sed |
 |
descrição de ajuda do busybox sed |
O gnu-sed e o toybox sed são os que melhores implementam tais descrições. Aqui eu postei apenas uma porção de toda a descrição de ambos.
 |
Descrição de ajuda do gnu-sed
|
 |
Descrição de ajuda do toybox sed
|
VENCEDOR: Empate entre o toybox sed e o gnu-sed
POSSÍVEIS BUGS
Já que falamos de recursos, agora vamos tratar de... bugs. O que é uma parte um pouco complicada de se tratar já que difícil constatar a real quantidade de bugs de um programa. Como todos sabem, há relatos de bugs que só foram encontrados mais uma década após sua existência. O bug estava lá mas só foi detectado dois de tanto tempo.
Por exemplo, no arquivo BUGS do minised é descrito como não havendo a necessidade de regressão até o momento; porém, como puderam acompanhar no inicio, vale ressaltar que sua base de código é bem pequena (o que é muito vantajoso). Apesar disso, eu encontrei apenas dois comentários de FIXME
nos códigos sedcomp.c e sedexec.c (/* FIXME: scan for the brace end */ e /* FIXME: lastep becomes start */
).
O mesmo ocorre no toybox sed (tendo sua base de código ainda menor que do minised). A primeira versão do sed no toybox surgiu na versão 0.5.1 (em Novembro de 2014). De lá para cá, poucos bugs foram encontrados (total de 11 bugs encontrados e corrigidos desde então. Um deles pode ser conferido clicando aqui) e poucos deles eram críticos. O minised teve 12 correções desde a versão 1.3 que podem ser lidos em seu README.
No código do sbase sed existem 20 comentários com o dizer FIXME. Estes comentários descrevem correcções que ainda são necessárias. Foi difícil encontrar algo relacionado ao 9base sed, há sim correções ocorrendo e podem ser conferidas no próprio git do plan9port (clicando aqui), mas não é uma lista fácil de encontrar (muito menos especificamente de seu sed).
VENCEDOR: Com excessão do gnu-sed, todos os demais apresentaram baixa quantidade de bugs.
DESEMPENHO
E por fim, a parte que a galera vai para delírio: benchmarks... Parece que a galera pira com essa palavra. Aqui eu considerei analisar tanto o uso de CPU quanto o tempo para a concluir as operações. E obtivemos os seguintes resultados:
Estranhamente tanto o gnu-sed, o sbase sed, o 9base sed e o busybox_SED se comportam da mesma forma. eles sempre se mantêm na margem de 86-89% de uso de CPU, nunca a menos nem a mais do que isso. Mas não devemos analisar unicamente o uso de CPU pois, de certo forma, isso pode significar tanto algo bom quanto algo ruim; tudo vai depender muito da situação.
Reparem um exemplo disso na imagem abaixo onde fiz uma analise entre o minised e o gnu-sed sendo eles separados pela faixa azul. Enquanto o gnu-sed manteve o uso de 89% de CPU, o minised desta vez fez uso de 106%. Apesar do uso de CPU do minised ter sido mais alto, o mimised concluiu sua operação em 120ms enquanto que o gnu-sed concluiu a mesma operação em 284ms.
 |
Comparação de uso de CPU e tempo de conclusão entre minised e gnu-sed |
Para que o gnu-sed, sbase sed, 9base sed e o busybox_SED consigam concluir as operações no mesmo tempo que o minised, seria necessário que utilizassem entre 136,17% a 161,87% a mais de CPU além dos 89% já utilizado. O que totalizaria entre 225,17% a 250,87% de uso de CPU.
VENCEDOR: Empate entre o minised (utilizando entre 61% - 76% de CPU porém, com menor tempo de execução) e toybox sed (utilizando entre 50% - 76% de CPU, algumas vezes atingindo 88%). Os demais ficam entre 86% a 89% de uso de CPU e o mesmo tempo de execução.
CONCLUSÃO
O primeiro lugar fica para o toybox sed com 6 pontos. O minised em segundo com 5 pontos perdendo apenas na descrição de ajuda apesar que possui uma boa manpage. Então poderíamos declarar empate entre os dois já que o minised possui desempenho melhor do que o toybox sed.
O segundo lugar ficaria empatado entre o busybox_SED com quatro ponto (tamanho, recursos, descrição de ajuda e poucos bugs) e o sbase sed (licença, tamanho, recursos e poucos bugs). O 9base sed teve três pontos (licença, recursos e bugs) e o gnu-sed apenas dois pontos (recursos e descrição de ajuda).
 |
Conclusão da analise das implementações do sed |
Existem outras implementações ou comandos semelhantes como é o caso do comando
sd , mas não nos interessa para este artigo.
 |
sd é um comando que pode substituir find, sed e awk. |