Rust no Linux: Um caso de amor e ódio

Rust e Linux: um caso de amor e ódio
Rust no Linux: um caso de amor e ódio

 É incrível como funciona o emocional do pessoal apaixonado por software livre. Se não estão 
decretando empresas como inimigas mortais, ou abominando o systemd ou criticando o btrfs, eles estão exaltando o projeto gnu como único e absoluto, o ZFS como sistema de arquivos indestrutível e insuperável, acreditando que o FreeBSD é superior a qualquer outro sistema operacional (eu já recebi vídeo assim hein, UFRS) e agora a bola da vez é dizer que a linguagem Rust irá substituir a linguagem C. E o argumento por traz de tudo isso é que a linguagem Rust trabalha melhor com gerenciamento de memória e... só.


 De lá para cá vimos noticias de que o Google anunciou em Abril de 2021 que está trabalhando para reescrever o user space do Android na linguagem RustNo dia 18 de Setembro de 2020, Rob Landley já havia escrito que "a empresa Google provavelmente vai reescrever por completo todas as coisas de baixo nível do Android em Rust nos próximos dez ou vinte anos". O que pode acarretar na completa substituição do toybox ou ter que portar o toybox para a linguagem Rust (algo que Rob Landley não tem um grande interesse).

 Os desenvolvedores do kernel queriam adicionar suporte a linguagem Rust no kernel e, apesar de Linus ter sido resistente quanto a ideia e até mesmo ameaçar os desenvolvedores que fizessem isso, o kernel passou a ter suporte a Rust como segunda linguagem... O motivo é até simples, para atrair novos desenvolvedores para o kernel Linux.

 A Microsoft também  anunciou que planeja reescrever partes do kernel do Windows em Rusta equipe do projeto Tor passou a trabalhar na implementação do Arti (um Tor escrito na linguagem Rust) devido Rust trabalhar melhor com os protocolos tor do que a linguagem CPostgresML anunciou em Setembro de 2022 que estaria migrando para a linguagem Rust na versão 2.0 por apresentar melhor desempenho do que SQL, PLpgSQL, Python e Numpy em suas ferramentas (apesar que as rotinas BLAS (Basic Linear Algebra Subprograms, que geralmente são escritas em Fortran, apresentaram melhor desempenho do que Rust).


 O Zabbix Agent2 passou a ser escrito na linguagem Go. O motivo explicado pela comunidade é que fica melhor para integrar seus plugins e de forma mais modular mas vale a ressalva que partes do código do Zabbix Agent2 ainda é escrito em C. E assim vemos vários projetos fazendo adoção da linguagem Rust.

 O que eu me pergunto é, será que estamos no caminho certo? Será que isso não acabará solucionando um problema e causando vários outros ainda mais graves? Essas são as perguntas que devemos (ou ao menos deveríamos) nos fazer antes de começar o trabalho.

 E no meio de toda essa euforia, de muita gente que não entende de nada sobre linguagem de programação e outros tantos que também não leem nada sobre o assunto, vamos tratar de um assunto que quase ninguém prestou a atenção e que na verdade é o tema principal deste artigo.


O QUE NÃO TE CONTAM SOBRE A LINGUAGEM RUST

 Ao meu ver Rust solucionará certos problemas, mas outros não (muito menos solucionará todos como andam fantasiando). O problema é que todo mundo focou somente no prós da linguagem e esqueceram dos contras. É questão de saber quando, aonde e a que custo adotá-la.

 Um ótimo exemplo disso, o projeto Warp (um terminal escrito em Rust disponível para MacOS mas com planos para ser portado para Linux e Windows) que apresentou o tamanho da dificuldade de implementar UI (User Interface = Interface de Usuário) ou GUI (Grafical User Interface) utilizando a linguagem Rust:


 O segundo exemplo apresentando pelo projeto Warp foi utilizando o Timer da 7GUI e a dificuldade que é enfrentada para conseguir algo tão simples com Rust.


 A equipe desenhou um mapa explicando como todo o projeto ficaria e que essa abordagem de árvore não mapeia claramente para Rust. Uma série de erros iriam acontecer e tornariam o trabalho mais difícil para projetar um único componente e adicionar uma simples função em sua estrutura.




 Um outro bom exemplo de dificuldade GUI em Rust é o emulador Obliteration que a equipe do projeto reescreveu o seu núcleo de emulação em Rust enquanto que a interface gráfica é desenvolvida em C++ (utilizando o framework QT).

 Fora do contesto de GUIs, temos o gerenciador de pacotes da distribuição Glaucus que era escrito em Rust, mas a equipe o reescreveu na linguagem Nim no lançamento s6-x86-64-v3-28042023. Os motivos apresentados pela equipe na nota de lançamento foram:
  • O código e razoavelmente mais legível (mais do que a versão em Rust)
  • Muito menos LOC mesmo com mais recursos adicionados (comparado com a versão Rust)
  • O código foi escrito um montante de tempo razoável (muito menos do que a versão Rust, novamente a reescrita em si levou em torno de um mês, mas a velocidade que recursos mais novos foram adicionados é algo entre 4 a 8 vezes mais rápido do que o tempo que leva para implementa-los em Rust, provavelmente por conta que eu me aborreço com Rust mesmo depois de um ano de uso, mas quem sabe...)
  • menos uso de recursos do sistema (1/3 do que a versão em Rus utiliza)
  • Executável muito menor (200 a 300 KB. Comparado a versão em Rust que é de 3 MB)*
  • Pode ser construído utilizando toolchain existente no Glaucus porque Nim transpila para C; assim, tornando o uso de toolchain otimizada pelo Glaucus (diferente de Rust que é muito difícil de fazer bootstrap**, e não funciona tudo tão bem assim com musl compartilhada...)
  • Um pouco mais rápida (em analise, é por volta de 6 - 20% mais rápido no geral. Provavelmente porque eu odeio Rust mesmo depois de um ano utilizando, mas novamente eu estou escrevendo em Nim em apenas um mês ou dois...)


*Eu como administrador de sistemas utilizando programas escritos na linguagem Rust, sim eu constatei que executáveis em Rust são maiores e conseguiram apresentar problemas e menor desempenho. No artigo uutils: Um coreutils escrito na linguagem Rust eu acabei fazendo a observação que o uutils, com apenas 87 comandos e sendo linkado dinamicamente, ocupa mais de 12MB enquanto que o toybox 0.8.9 consegue ser 17 vezes menor ocupando apenas 724KB mesmo contendo 233 comandos (é mais de duas vezes e meia a quantidade de comandos do uutils) e ainda sendo linkado estaticamente (o que, pela lógica, o tornaria maior e foi ao contrário). Veja o resultado na imagem abaixo

uutils vs toybox
comparando o uutils e toybox

**Exatamente o motivo que Linus Torvalds não queria aceitar Rust no Linux e quase puniu quem tentou implementa-la (na verdade eu acho que deveria ter feito isso).

 Ainda podemos ressalta o PX5 RTOS, um sistema operacional Real Time que é novo, moderno e que vai atender as necessidades atuais do mercado. O PX5 é quase totalmente (99%) escrito em C. O motivo é que C o torna altamente portável para qualquer arquitetura de processador e por conta disso, o PX5 possui suporte a maioria das arquiteturas de embarcados MCU e MPU populares incluindo as famílias de arquiteturas ARM's Cortex-M, Cortex-R, Cortex-A e RISC-V.


 E aqui vai a minha pergunta, porque ninguém pensou em adotar a linguagem Nim como segunda linguagem no kernel ao invés de Rust? Drivers, sistemas operacionais (existe até mesmo um kernel escrito na linguagem Nim, o NimKernel e que ainda pretendem trabalhar em um Nim OS no futuro), embarcados e até Internet of Things (IoT) podem ser escritos em Nim. Nim possui a característica de memory safety ativa por padrão, faz o gerenciamento de memória através do suporte a diferentes tipos de garbage collectors com diferentes aplicações em mente além de lhe permitir trabalhar com gerenciamento de memória manualmente. Vocês puderam ver o projeto Glaucus se tornar muito mais eficiente com Nim do que com Rust. Por que ninguém pensou ou sugeriu isso?



Gerenciamento de memória na linguagem C?


 O que todos hoje temem a respeito de gerenciamento de memória em linguagens de programação como C e C++ na verdade é uma característica das duas linguagem e não uma falha; elas permitem que os programas tenham acesso direto a memória. O problema é que essa característica pode levar a certos desastres permitindo que programas que não foram atribuídos para esse uso acessarem memória. Já linguagens que recorrem ao recurso memory safe fazem isso ao custo de não permitir que programas acessem detalhes de baixo nível da memória que em alguns casos são necessário e também degrada o desempenho dos programas.

 Recentemente que foi adotado C11 no Linux. O que me leva a questionar se estamos no caminho correto. O que seria mais vantajoso? Reescrever códigos de uma linguagem para outra ou escrever patches usufruindo dos reais recursos da linguagem?

 Pode ser que de repente alguém ou um grupo de pesquisadores desenvolvam algoritmos ou simplesmente façam uso de algoritmos já existentes e solucionem esse "problema". Veja como exemplo a biblioteca Newlib; um desenvolvedor da empresa ARM desenvolveu um patch que melhora o desempenho da biblioteca baseando-se no algorítimo Horspool da universidade de Helsinki (o berço do Linux ;). Parte do algoritmo pode ser conferido na imagem abaixo; são algoritmos assim que acabam surgindo até de forma inesperada.


 Mais exemplos de algoritmos que solucionaram problemas e que quase ninguém imaginava que um dia seriam capazes, não nos faltam como é o caso do Btrfs pois sistemas de arquivos CopyonWrite são incompatíveis com Btree (o ZFS é incompatível com Btree; o HAMMER em sua primeira versão era Btree e não possuía suporte a CopyonWrite mas em sua segunda versão se tornou CopyonWrite e automaticamente não possui mais suporte a Btree; o Ext4 é Btree e também não possui suporte a CopyonWrite; o NTFS é Btree e faz uso shadow por conta desta incompatibilidade). Mas o que tornou o Btrfs Btree e CopyonWrite? Os algorítimos escritos por Ohad Rodeh da IBM de Haifa que permitiu que essa fosse uma das características do Btrfs e hoje herdado pelo BcacheFS.

 Outro exemplo é o algoritmo malloc (abreviação de memory allocator). O artigo da Etalabs chamado O que é Overcommit? E por que ele é ruim? descreve que "existem mal entendimentos a respeito de gerenciamento de memória no Linux que acabam levando a muitos programas ruins falhar em lidar de forma robusta com condições de pouca memóriaGrande parte dessa falha de gerenciamento de memória na linguagem C está relacionada a forma como os programas são escritos (vale lembrar que bibliotecas como dietlibc e musl possuem recursos para auxiliar desenvolvedores a escrever códigos melhores. Na bibliotec musl surgiu o conceito de Quality Safe Code e a própria musl possui recursos de debug).

 Rich Felker começou a desenvolver sua própria implementação do algoritmo malloc para a musl chamada de mallocng que a proporciona ganhos de desempenho. A microsoft mantem um fork do jemalloc chamado mimalloc que é utilizado nas imagens Apline do Docker, Azure, no Bing, no jogo Death Stranging, no Unreal Engine, na assembly toolkit SPAdes e em muitos outros projetos oferecendo desempenho muito melhor do que os dois anteriormente mencionados.

glibc vs musl
Comparação de desempenho entre glibc e musl sem malloc

glibc vs musl vs malloc-ng
Comparação de desempenho entre glibc, musl e malloc-ng

glibc vs musl vs malloc-ng vs musl+mimalloc
Comparação de desempenho entre glibc, musl, malloc-ng e musl+mimalloc

 Todos os detalhes sobre o desempenho do algoritmo malloc podem ser conferido no linkedin do Emerson Gomes. Vale acrescentar que no elinux de 2022 descreve que Rust no kernel é um problema difícil de solucionar pois, programas escritos em Rust normalmente não lidam com falhas de alocação de memória (estranho a maior propaganda da linguagem Rust ser segurança de memória e não tratar do ponto de alocação de memória) e sofre também com muitos recursos que ainda são INSTÁVEIS.


 E o terceiro exemplo é o novo recurso _FORTIFY_SOURCE que foi adicionado no GCC e no LLVM/Clang. Esse recurso é uma macro de pré-processamento que garante um nível extra de segurança para as linguagens C e C++ detectando erros durante o processo de compilação e de execução já que, como descrito no link da Red Hat, programas escritos na linguagem C rotineiramente sofrem com problemas de gerenciamento de memória. O _FORTIFY_SOURCE detecta mais buffer overflows e bugs que mitigam problemas de segurança na aplicações em tempo de execução.


CONCLUSÃO


 Se levou tanto tempo para adotar C11 no Linux, acredito que adotar Rust está sendo uma ideia de certa forma prematura e um tanto precipitada. Um erro que pode custar muito caro no futuro. Lembrando que quando eu iniciei este artigo, estamos na C17 (ISO/IEC 9899:2018e agora já estamos na C23 (ISO/IEC 9899:202x). A própria biblioteca musl já está recebendo suporte a C23 dentro do padrão WG14 (musl patch for c2x %b printf/scanf). Esse mesmo recurso (macros %b/%B PRI* e SCN*) foi adicionado à Bionic do Android no dia 7 de Março de 2023 (leia Add the %b/%B PRI* and SCN* macros).


 Pode ser que a versão C25 ou C26 surja com as exatas características da linguagem Rust que todos enaltecendo. Eu acredito que Rust irá substituir C? Não! Eu acredito que cada linguagem será adotada em campos que cada uma possui melhor atuação.

 Diziam que o o kernel monolítico era obsoleto e que o microkernel iria substituí-lo; já se passaram quase 40 anos e ainda nada. Diziam que php estava morrendo, diziam até que php estava sendo substituído por Java (uma linguagem que não tem nada a ver com a outra), contudo php está bem forte no mercado e Java declinando.

 O que temos que entender é que em cada linguagem existem suas vantagens e desvantagens. Cabe a nós saber quando desfrutar de cada uma nos momentos exatos.


Comente com o Facebook:

Nenhum comentário:

Postar um comentário

Viu algum erro e quer compartilhar seu conhecimento? então comente aí.

Observação: somente um membro deste blog pode postar um comentário.

Marcadores

A pior história sobre Linux que já ouvi (5) A.I (2) ambiente gráfico (19) AMD (14) analise (10) Andriod (16) android (7) Apple (1) arm (5) artigo (5) aws (1) bc (23) benchmark (6) BetrFS (1) blackhat (1) BSDs (30) btrfs (32) bugs (2) Caixa de Ferramentas do UNIX (19) canto do Diego Lins (2) certificações Linux (7) Código Fonte (54) comandos (32) comp (1) compressores (6) container (7) CPU (19) cracker (1) criptografia (5) crowdfunding (9) cursos (24) daemons (13) Debian (31) desempenho (1) desenvolvimento (94) desktop (19) DevOps (3) DevSecOps (4) dic (1) Dica de leitura (91) dica DLins (2) dicas do Flávio (27) Dicas TechWarn (1) diet libc (3) diocast (1) dioliunx (3) distribuições Linux (14) Docker (12) DragonflyBSD (22) driver (1) dropbear (3) ead Diolinux (2) edição de vídeo (5) embarcados (1) EMMI Linux (4) emuladores (9) endless (5) English interview (3) Enless OS (2) entrevista (17) espaço aberto (82) evento (6) facebook (1) Fedora (11) filesystem (82) financiamento coletivo (2) fork (4) fox n forests (4) FreeBSD (20) Funtoo Linux (13) games (94) gerenciadores de pacotes (4) glaucus (4) GOG (3) google (9) gpu (3) hacker (2) hardware (104) hash (1) helenos (3) I.A (1) init system (12) Intel (15) inteligencia artificial (2) IoT (1) ispconfig (1) jogos (38) kde (1) kernel (138) lançamento (64) leis (1) LFCS (1) libs (2) licenças (8) Linus (16) linus torvalds (2) Linux (194) linux foundation (3) linux para leigos (1) live (5) LPI (8) LTS (1) Mac (1) machine learning (1) matemática (9) mesa redonda (27) microcontroladores (1) microsoft (6) microst (1) muito além do GNU (169) musl (3) não viva de boatos (9) navegadores (5) NetBSD (7) newlib (1) nim (2) nintendo (1) novatec (17) novidades (1) nuvem (1) o meu ambiente de trabalho (3) off-topic (12) open source (84) OpenBSD (7) OpenShift (1) oracle (1) os vários sabores de Linux (44) padrim (2) palestras e eventos (5) partições (6) pentest (8) performance (1) pipewire (1) plan9 (1) playstation (1) processadores (30) professor Augusto Manzano (11) Programação (65) promoção (1) propagandas com Linux (8) ps4 (1) real-time. (1) Red Hat (23) redes (4) resenha nerd (4) Resumo da Semana do Dlins (2) resumo do Tux (19) retrospectiva Linux (1) risc-V (14) RISCV (13) rtos (1) runlevel (2) rust (13) segurança digital (24) servidor web (2) servidores (3) shell (9) shell script (8) sistema operacional (25) skarnet (2) smartphones (3) Software livre e de código aberto (151) sorteio (3) Steam (10) Steam no Linux (8) supercomputadores (4) suse (6) systemd (8) terminal (89) terminal de comandos (18) toca do tux (1) toybox (27) tutorial (6) Tux (3) unboxing (7) UNIX (17) UNIX Toolbox (14) vartroy (1) vga (1) virtualização (2) vulnerabilidade (6) wayland (5) web (1) whatsapp (1) whitehat (1) Windows Subsystem for Linux (2) wine (14) WoT (1) yash (1) ZFS (15) zsh (3)