Escrito por Helio Loureiro
Categoria:

Esses dias estava analisando um código que era parecido com shell script.  Sua função era monitorar as interfaces de rede para, no caso de alteração (nova interface surgindo ou desaparecendo), registrar a mudança de objetos no sistema de dados do opensaf (objetos no IMM pra quem conhece).

Mas o código fazia algo parecido com um shell que a todo healthcheck do AMF (framework do opensaf que é muito semelhante ao systemd e roda determinado programa ou script de tempos em tempos) fazia uma busca com o comando "ip link addr list" e comparava com o que estava  armazenado no IMM.  Algo como:

def healthcheckCallback(self, invocation, compName, healthcheckKey):
		        saAmfResponse(self.check_macs,
				      invocation, eSaAisErrorT.SA_AIS_OK)

def check_macs(self):
macs = []
for line in self.get_link_list().split("\n"):
if not re.search("link/ether", line): continue
# [ 'link/ether', '52:54:00:c3:5d:88', 'brd', 'ff:ff:ff:ff:ff:ff']
mac.append(line.split()[1])
imm_obj = self.get_from_imm()
if imm_obj != macs:
self.update_imm(mac)

def get_link_list(self):
linux_command = "ip link list"
return self.run_shell(linux_command)

Essa é uma forma bastante simplificada pra tentar visualizar como tudo funciona.  Eu propositalmente tirei comentários extras e deixei mais limpo apenas para poder comentar aqui. 

  • Agora explicando o que cada método faz ali:
  • healthcheckCallback(): esse é  o método que eu registrei junto ao AMF pra que seja chamado de tempos e tempos e rode a função check_macs().  Não vou entrar em detalhes dos outros parâmetros pois são inerentes em como o AMF funciona junto ao OpenSAF.  Deixei o link pra o exemplo de uma implementação completa ao final do artigo.
  • check_macs(): é uma função que pega uma listagem em formato array do comando "ip link list" e armazena os MAC, endereço de camada 2 da placa de rede.
  • get_link_list(): apenas pra deixar mais legível a parte que busca e monta o array de informações de rede de um sistema Linux.  O método run_shell() é apenas um subprocess.check_output() de forma mais legível (e por isso omiti essa parte do código).

Como a chamada pra buscar os dados junto ao IMM no OpenSAF tem muitas linhas, eu só deixei um get_from_imm() que retornará um array de mac registrados anteriormente.  Se esse valor for diferente do coletado, então é chamado o método update_imm() com os macs que devem estar lá.

Funciona?  Sim, funciona.  Mas... se não houve nenhuma mudança nas interfaces de rede (como a subida de uma interface de VIP ou mesmo um container em docker), por quê eu preciso rodar o get_link_list()? 

Entendeu qual foi meu ponto?

O código em si consiste em rodar o monitoramente separado numa thread.  Toda vez que o código detecta uma mudança (na verdade o kernel sinaliza isso), ele altera uma variável que o programa lê durante o healthcheck.  Algo como:

def check_macs(self):
if self.network_changed is False: return

Assim bem simples.  Teve mudança? network_changed vira um True.

Linux tem mecanismos pra detectar uma mudanças na interfaces de rede.  Por quê não usar?  E foi o que fiz.

Criei um método chamado monitor_link() que é iniciado junto com programa no método initialize(), que é parte de como o AMF faz as chamadas de callback:

self.thread = threading.Thread(target=self.monitor_link, args=())
self.thread.start()

E como funciona o monitor_link()?  Aqui tenho de pedir desculpas antecipadamente que enquanto o código utiliza menos CPU e memória que chamar um shell script, o tamanho e complexidade é bastante grande.  No fim troquei 2 linhas de código por umas 35 linhas.  Na verdade eu praticamente escrevi o código por trás do "ip link".  Mas o resultado ficou independente desse comando e mesmo de utilizar um shell externo pra buscar o resultado.

A primeira coisa é criar um socket do tipo AF_NETLINK.  Em seguida fazer um bind() num ID aleatório e monitorar com RTMGRP_LINK.

def monitor_link(self):
    # Create the netlink socket and bind to RTMGRP_LINK,
    s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE)
    s.bind((os.getpid(), RTMGRP_LINK))

pra gerar o código aleatório que é um inteiro, usei os.getpid() pra usar o PID do próprio programa.

Em seguida é iniciado um loop com select() em cima do descritor do socket pra leitura.  Quando aparecer algum dado, daí sim a informação é lida.

rlist, wlist, xlist = select.select([s.fileno()], [], [], 1)

O que vem a seguir são quebras da sequência de bits até chegar no ponto é possível ver o tipo de mensagem que chegou do select().  Se o tipo de mensagem for NOOP de algo nulo, apenas continue monitorando no select().  Se vier algum ERROR, pare o programa.  Se vier mensagem e não for do tipo NEWLINK pra um link novo ou mudança de MAC, também continue aguardando no select().

if msg_type == NLMSG_NOOP: continue
elif msg_type == NLMSG_ERROR: break
elif msg_type != RTM_NEWLINK: continue

Por fim uma iteração nos dados pra buscar o tipo.  Se o dado for do tipo IFLA_IFNAME, que é uma nova interface ou mudança de nome, ou IFLA_ADDRESS, que é MAC e endereço IP, muda a flag de network_changed pra True. 

rta_type == IFLA_IFNAME or rta_type == IFLA_ADDRESS:

E é isso.  O código completo segue abaixo.

def monitor_link(self):
    # Create the netlink socket and bind to RTMGRP_LINK,
    s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE)
    s.bind((os.getpid(), RTMGRP_LINK))

    while self.terminating is False:
        rlist, wlist, xlist = select.select([s.fileno()], [], [], 1)
if self.network_changed is True: continue if self.terminating is True: return
try: data = os.read(rlist[0], 65535) except: continue msg_len, msg_type, flags, seq, pid = struct.unpack("=LHHLL", data[:16]) if msg_type == NLMSG_NOOP: continue elif msg_type == NLMSG_ERROR: break elif msg_type != RTM_NEWLINK: continue data = data[16:] family, _, if_type, index, flags, change = struct.unpack("=BBHiII", data[:16]) remaining = msg_len - 32 data = data[16:] while remaining: rta_len, rta_type = struct.unpack("=HH", data[:4]) if rta_len < 4: break rta_data = data[4:rta_len] increment = (rta_len + 4 - 1) & ~(4 - 1) data = data[increment:] remaining -= increment if rta_type == IFLA_IFNAME or rta_type == IFLA_ADDRESS: self.network_changed = True

Encontrei essa implementação no Stack Overflow buscando informação do código em C.  Foi uma grande ajuda e deixou meu programa muito mais coerente com o que eu realmente queria.

Ficou muito maior?  Ficou.  Mas também ficou muito mais 1337 :)

Mais:

[1] Exemplo de uso de python com AMF no OpenSAF: https://sourceforge.net/p/opensaf/staging/ci/default/tree/python/samples/amf_demo

[2] Projeto OpenSAF: https://sourceforge.net/projects/opensaf/

[3] Implementação original desse código: https://stackoverflow.com/questions/44299342/netlink-interface-listener-in-python

Escrito por Helio Loureiro
Categoria:

Tenho escrito pouco aqui, e já passei do prazo de fazer uma retrospectiva de 2017.  Mas antes tarde do que nunca.

Ao invés de escrever, resolvi aderir ao momento multimídia do mundo e fazer em vídeo.  O primeiro é um vídeo de fotos e vídeos meus que peguei direto no Google, no storage onde estão conectados meu smartphone e meu tablet.

O segundo é da coleção de snapshots que o raspberrypi tira a cada 15 minutos da janela de casa. Dá pra ver que no começo e no fim fica bem escuro, enquanto que no meio é mais claro (dias mais curtos no inverno e mais longos no verão).

 

Escrito por Helio Loureiro
Categoria:

Eu gosto de usar os kernels mais recentes e compilar minhas próprias versões.  Às vezes adiciono patches pra melhorar resposta de temporeal, às vezes um suporte pra AUFS no docker.

Atualmente estou com o 4.14-rc2, um pouco antigo nesse momento mas que me deu um uptime de 25 dias sem problemas até agora.

Linux elxaf7qtt32 4.14.0-rc2-helio #12 SMP PREEMPT Fri Sep 29 13:50:19 CEST 2017 x86_64 x86_64 x86_64 OSI/Linux

(é... troquei GNU/Linux por OSI/Linux... por diversão e usando sed na saída do uname)

E descobri que o VirtualBox versão 5.2 simplesmente não consegue rodar o comando /sbin/vboxconfig.  Olhando o erro um pouco mais de perto pelo log:

 

  gcc -Wp,-MD,/tmp/vbox.0/linux/.SUPR0IdcClient-linux.o.d  -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/5/include -I./arch/x86/include -I./arch/x86/include/generated  -I./include -
I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -Wall -Wundef -Wstrict-prototyp
es -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -
mno-avx -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -
DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG
_AS_AVX2=1 -DCONFIG_AS_AVX512=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -fno-delete-null-pointer-checks -O2 --param=allow-
store-data-races=0 -DCC_HAVE_ASM_GOTO -Wframe-larger-than=1024 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracki
ng-assignments -g -gdwarf-4 -pg -mfentry -DCC_USING_FENTRY -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-pro
totypes -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -include /tmp/vbox.0/include/VBox/SUPDrvMangling.h -fno-pie -I/lib/modules/4.14.0-rc2-helio/build/i
nclude -I/tmp/vbox.0/ -I/tmp/vbox.0/include -I/tmp/vbox.0/r0drv/linux -D__KERNEL__ -DMODULE -DRT_OS_LINUX -DIN_RING0 -DIN_RT_R0 -DIN_SUP_R0 -DVBOX -DRT_WITH_VBOX -DVBOX_WITH_HARDENING 
-Wno-declaration-after-statement -DRT_ARCH_AMD64 -DVBOX_WITH_64_BITS_GUESTS  -DMODULE  -DKBUILD_BASENAME='"SUPR0IdcClient_linux"'  -DKBUILD_MODNAME='"vboxnetflt"' -c -o /tmp/vbox.0/lin
ux/.tmp_SUPR0IdcClient-linux.o /tmp/vbox.0/linux/SUPR0IdcClient-linux.c
  if [ "-pg" = "-pg" ]; then if [ /tmp/vbox.0/SUPR0IdcClient.o != "scripts/mod/empty.o" ]; then ./scripts/recordmcount  "/tmp/vbox.0/SUPR0IdcClient.o"; fi; fi;
(cat /dev/null;   echo kernel//tmp/vbox.0/vboxnetflt.ko;) > /tmp/vbox.0/modules.order
  if [ "-pg" = "-pg" ]; then if [ /tmp/vbox.0/linux/SUPR0IdcClient-linux.o != "scripts/mod/empty.o" ]; then ./scripts/recordmcount  "/tmp/vbox.0/linux/SUPR0IdcClient-linux.o"; fi; fi;
  if [ "-pg" = "-pg" ]; then if [ /tmp/vbox.0/VBoxNetFlt.o != "scripts/mod/empty.o" ]; then ./scripts/recordmcount  "/tmp/vbox.0/VBoxNetFlt.o"; fi; fi;
/tmp/vbox.0/linux/VBoxNetFlt-linux.c: In function ‘vboxNetFltLinuxSkBufFromSG’:
/tmp/vbox.0/linux/VBoxNetFlt-linux.c:741:24: error: ‘SKB_GSO_UDP’ undeclared (first use in this function)
             fGsoType = SKB_GSO_UDP;
                        ^
/tmp/vbox.0/linux/VBoxNetFlt-linux.c:741:24: note: each undeclared identifier is reported only once for each function it appears in
In file included from /tmp/vbox.0/include/iprt/types.h:29:0,
                 from /tmp/vbox.0/r0drv/linux/the-linux-kernel.h:34,
                 from /tmp/vbox.0/linux/VBoxNetFlt-linux.c:24:
/tmp/vbox.0/linux/VBoxNetFlt-linux.c: In function ‘vboxNetFltLinuxCanForwardAsGso’:
/tmp/vbox.0/linux/VBoxNetFlt-linux.c:1276:53: error: ‘SKB_GSO_UDP’ undeclared (first use in this function)
     if (RT_UNLIKELY( skb_shinfo(pSkb)->gso_type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | SKB_GSO_TCPV6 | SKB_GSO_TCPV4) ))
                                                     ^
/tmp/vbox.0/include/iprt/cdefs.h:1616:53: note: in definition of macro ‘RT_UNLIKELY’
 #  define RT_UNLIKELY(expr)     __builtin_expect(!!(expr), 0)
                                                     ^
/tmp/vbox.0/linux/VBoxNetFlt-linux.c: In function ‘vboxNetFltLinuxForwardToIntNetInner’:
/tmp/vbox.0/linux/VBoxNetFlt-linux.c:1526:47: error: ‘SKB_GSO_UDP’ undeclared (first use in this function)
         if (   (skb_shinfo(pBuf)->gso_type & (SKB_GSO_UDP | SKB_GSO_TCPV6 | SKB_GSO_TCPV4))
                                               ^
scripts/Makefile.build:311: recipe for target '/tmp/vbox.0/linux/VBoxNetFlt-linux.o' failed
make[2]: *** [/tmp/vbox.0/linux/VBoxNetFlt-linux.o] Error 1
Makefile:1498: recipe for target '_module_/tmp/vbox.0' failed
make[1]: *** [_module_/tmp/vbox.0] Error 2
/tmp/vbox.0/Makefile.include.footer:97: recipe for target 'vboxnetflt' failed

Foi algo relacionado com a variável SKB_GSO_UDP, que parece não existir no kernel mais recente ou no VirtualBox.

Buscando pelo termo pude encontrar que realmente existe uma diferença entre ambos um patch precisa ser aplicado, descrito aqui:

Fonte: https://gist.github.com/herbmillerjr/039c129e9c25b047b906e19ad1f23a59

diff --git a/work/vboxnetflt/linux/VBoxNetFlt-linux.c b/work/vboxnetflt/linux/VBoxNetFlt-linux.c
index f824654..b61d82c 100644
--- work/vboxnetflt/linux/VBoxNetFlt-linux.c
+++ work/vboxnetflt/linux/VBoxNetFlt-linux.c
@@ -126,6 +126,10 @@ typedef struct VBOXNETFLTNOTIFIER *PVBOXNETFLTNOTIFIER;
 # endif
 #endif

+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+#define SKB_GSO_UDP 0
+#endif
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 20, 0)
 # define VBOX_HAVE_SKB_VLAN
 #else
diff --git a/work/vboxpci/linux/VBoxPci-linux.c b/work/vboxpci/linux/VBoxPci-linux.c
index 2dbf47f..e361ef3 100644
--- work/vboxpci/linux/VBoxPci-linux.c
+++ work/vboxpci/linux/VBoxPci-linux.c
@@ -353,12 +353,16 @@ static void  vboxPciFileClose(struct file* file)
 static int vboxPciFileWrite(struct file* file, unsigned long long offset, unsigned char* data, unsigned int size)
 {
     int          ret;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+    ret = kernel_write(file, data, size, &offset);
+#else
     mm_segment_t fs_save;

     fs_save = get_fs();
     set_fs(get_ds());
     ret = vfs_write(file, data, size, &offset);
     set_fs(fs_save);
+#endif
     if (ret < 0)
         printk(KERN_DEBUG "vboxPciFileWrite: error %d\n", ret);

Mas como minha versão de VirtualBox não era exatamente a mesma que essa descrita, acabei fazendo o patch manualmente, que adiciona a variável SKB_GSO_UDP ao VirtualBox caso seja um kernel 4.14.0 ou superior.  Os arquivos para serem modificados no Ubuntu (e possivelmente Debian) são:

  • /usr/share/virtualbox/src/vboxhost/vboxnetflt/linux/VBoxNetFlt-linux.c
  • /usr/share/virtualbox/src/vboxhost/vboxpci/linux/VBoxPci-linux.c

depois basta rodar novamente como root o comando /sbin/vboxconfig para criar os módulos de kernel necessários pro funcionamento do VirtualBox.

SKB_GSO_UDP

SKB: SocKet Buffer

GSO: Generic Segmentation Offloading

UDP: User Datagram Protocol

Não tenho idéia do que isso faz exatamente mas parece ser uma chamada de um pacote UDP encapsulado.

 

Escrito por Helio Loureiro
Categoria:

Sobre o tema de carreira, que parece ter despertado um certo interesse, eu participe a convite do Ivan da gravação de dois episódios do OpenCast no canal Tecnologia Aberta sobre o assunto.  Estávamos eu, Og Maciel, Bruno Rocha, Elyézer Rezende e Tiago Salem, além do próprio Ivan.

Foi um bom bate papo sobre a área de desenvolvimento e inclusive perspectivas de trabalho no exterior.

Opencast #72 - Carreira de Desenvolvedor de Software Livre - parte 1

Opencast #75 - Carreira de Desenvolvedor de Software Livre - parte 2

Unix Load On - RELEASE-170101

E falando ainda de carreira no exterior, eu, Rodolpho Eckhardt, Christiano Linuxmen and Lucas Judocka gravamos no Unix Load On um programa contando como foi nossa experiência pra trabalhar fora, as dificuldades encontradas, socialização, língua e como é a vida atualmente, além de oportunidades no próprio Brasil.  Tudo sob uma perspectiva em relação ao software livre.

Escrito por Helio Loureiro
Categoria:

Não Facebook, nem Google+, nem Twitter e muito menos o Diaspora.  A grande rede social do momento parece mesmo ser o Telegram*.

O Telegram é o novo IRC, ou IRC 2.0.  Um mundo sem fronteiras e controle exercido por moderadores.  Não sei se a sensação é apenas para mim, mas boa parte das conversas de grupos parece que migraram pro Telegram.  De forma fluida e em geral bem descontraída.  É possível criar stickers (adesivos), o que torna a coisa muito engraçada, fazer gifs animados (eu já tenho os meus), e até mesmo bots.  O Telegram trouxe aquela alegria hacker de fazer um monte de coisas que não servem pra nada mas que fazem uma rede crescer.  Lembra o começo do Twitter, quando não tinha a limitação de uso da API e tudo era possível.

Mas o Telegram não é um sistema com indexação.  Então é difícil saber qual grupo participar.  Existem iniciativas pra listar os grupos no github ou um grupo que lista outros grupos de TI, mas em geral a coisa funciona no boca-à-boca.

Existem grupos privados, que são acessíveis somente por convite, e grupos abertos (super grupos) que agora permite até 10.000 pessoas, vários moderadores e níveis diferentes de poder a cada moderador.  E, claro, ainda é possível usar o Telegram da mesma forma que se usa o Whatsapp para mensagens individuais e mesmo chamadas de voz.

Os grupos que participo e recomendo são:

  • Canais e grupos de TI: https://t.me/grupos_ti - Grupo que lista ou tentar listar os demais grupos relacionados com TI.
  • Linux Brasil: https://t.me/linux_brasil - Grupo de discussão de Linux, software livre e coisas completamente aleatórias.  Tem várias discussões políticas também mas é possível sobreviver.
  • Debian Brasil:https://t.me/debian_br - Grupo de discussão sobre Debian**.
  • PyCoding pt-br: https://t.me/PyCoding - Grupo de discussão sobre programação em Python.
  • PyBR #rlz: https://t.me/pythonbr - Grupo mais generalista sobre Python e atividades dentro da comunidade Python Brasil como eventos.
  • SecurityCast: https://t.me/seccast - Grupo de conversas sobre o podcast (ou seria webcast) securitycast com assuntos sobre segurança e criptografia.
  • DockerBR: https://t.me/dockerbr - Grupo sobre Docker.
  • Valhacke, a capital do Telegram: https://t.me/hackncast - Grupo de conversas completamente sem sentido com várias pessoas de vários podcasts como o hack n' cast (original do grupo), Castálio, opencast, etc.  Assunto vai rapidamente sobre ransomwares pra pokemons sem muita cerimônia.  Adoro.
  • UltraOSI: https://t.me/ultraOSI - Da descrição do grupo, "Não seja um iGNUrante,seja um revoluzuero. "Blob!" é a nossa musica oficial: https://ftp.openbsd.org/pub/OpenBSD/songs/song39.mp3 Teste o seu nível de fofosismo e osismo: /fofometro@Stallnoman_Bot".  Muito bom pra dar boas risadas e descontrair.
  • LaTeX BR: https://t.me/latexbr - Grupo pra quem mexe com \latex.
  • UbuntuBR: https://t.me/ulboficial - Grupo de usuários Ubuntu.
  • GNUGRAF: https://t.me/grupoGNUGRAF - Grupo de discussão sobre ferramentas de arte gráfica em software livre.  Vai desde editoração gráfica à fotografia.
  • Shell Script (#! /bin/bash): https://t.me/shellbr - Grupo de dúvidas e discussões sobre shell script.  E tem uns posts simplesmente lindos sobre REGEX.
  • LibreOfficeBR: https://t.me/libreofficebr - Grupo de usuários de LibreOffice.  São discutidas questões sobre fórmulas em planilhas, apresentações, etc.  Bem interessante pra quem usa bastante a suíte de escritório e precisa fugir do "trivial com molho".
  • OsProgramadores: https://t.me/osprogramadores - Grupo para interessados em aprender ou afiar seus conhecimentos em programação.  Muito bom para quem gosta de software craftmanship.
  • Papo de sysadmin: https://t.me/papodesysadmin - Grupo de discussão e dicas pra quem trabalha ou trabalhou como sysadmin ou devops.
  • FreeBSD: https://telegram.me/joinchat/CYyDAUFhgLG8UJfPJrjTUg - Esse é o único grupo que ainda não é um super grupo (por isso não tem url própria), mas é um grupo legal pra falar não só de FreeBSD mas de todas as variantes da família BSD.

 Eu participo de muitos outros grupos, mas esses são os principais.  Sinta-se à vontade para entrar e participar.  Seja pelo app no smartphone ou tablet, ou seja pela web.

[*] Nota: claro que essa percepção pode ser parte da bolha social que cada um participa (ou viés cognitivo).

[**] Update: como o grupo de Debian tava muita xaropada, ainda com o Kretcheu como administrador, eu acabei fazendo um fork e criando outro grupo.  Vou sobreviver a essa grande perda.

Escrito por Helio Loureiro
Categoria:

Vira e mexe aparece esse assunto em algum grupo de discussão, seja no Facebook ou seja no Telegram.  São vários os relatos de instalação de sistemas de 32 bits em máquinas mais modestas, em geral com até 2 GB de RAM, e que ficaram mais rápidas.

Então resolvi passar um tempo fazendo a prova, inclusive da quantidade de memória.

Sistema de testes e validação

Pra validar, instalei em VMs (VirtualBox) dois sistemas Ubuntu baseados no 16.04, Xenial.  Ambos configurados como CPUs de 64 bits, 2 GB de RAM, 128 MB de vídeo com aceleração 3D e 20 GB de disco.

Pra consumir memória, deixei ambos com o navegador firefox rodando no tweetdeck, aplicativo que mostra o fluxo de mensagens do twitter.  Como o mesmo é feito em javascript, vai consumindo a memória conforme o tempo passa.  Ambos começaram com frugais 300 MB de RAM e ao terminar de escrever, depois de mais de 24 horas rodandos, ambos consumiam mais de 1.5 GB da RAM.

Não fiz testes de desempenho pelo motivo óbvio: fiz com meu laptop e ele não é exatamente um tipo de ambiente dos mais robustos pra esse tipo de coisa.  Mas pra finalidade de verificação de tamanho de binários em máquinas virtuais, serve bem.

Controle da missão.

Cada VM recebeu o nome de "UbuntuXX" onde XX é a arquitetura do software, 32 ou 64 bits.

Memória consumida

Logo de início o sistema com 32 bits mostra mais memória que realmente disponível.  Ambas as VMs com 2 GB de RAM, mas com 32 bits ele mostra um pouco mais de 2048 MB.  Bug?  Não sei.

root@ubuntu64:~# head -5 /proc/meminfo
MemTotal:        2048524 kB
MemFree:          102900 kB
MemAvailable:     859980 kB
Buffers:          132452 kB
Cached:           541576 kB
root@ubuntu32:~# head -5 /proc/meminfo 
MemTotal:        2060988 kB
MemFree:          380360 kB
MemAvailable:     507600 kB
Buffers:           58812 kB
Cached:           272512 kB

E na configuração das VMS...

helio@XPS13:VirtualBox VMs$ grep RAMSize Ubuntu\ {32,64}/Ubuntu\ {32,64}.vbox
Ubuntu 32/Ubuntu 32.vbox:      <Memory RAMSize="2048"/>
Ubuntu 32/Ubuntu 32.vbox:      <Display VRAMSize="128" accelerate3D="true"/>
Ubuntu 64/Ubuntu 64.vbox:      <Memory RAMSize="2048"/>
Ubuntu 64/Ubuntu 64.vbox:      <Display VRAMSize="128" accelerate3D="true"/>   

Uma olhada no sistema usando top.

root@ubuntu64:~# top -b -n 1 | head -5
top - 18:42:55 up  2:38,  2 users,  load average: 0,01, 0,02, 0,05
Tasks: 178 total,   1 running, 177 sleeping,   0 stopped,   0 zombie
%Cpu(s):  5,0 us,  0,8 sy,  0,1 ni, 93,8 id,  0,1 wa,  0,0 hi,  0,1 si,  0,0 st
KiB Mem :  2048524 total,    47004 free,  1157408 used,   844112 buff/cache
KiB Swap:  2095100 total,  2082632 free,    12468 used.   842436 avail Mem 
root@ubuntu32:~# top -b -n 1 | head -5
top - 18:42:45 up  2:38,  2 users,  load average: 0,00, 0,00, 0,00
Tasks: 171 total,   1 running, 170 sleeping,   0 stopped,   0 zombie
%Cpu(s):  9,3 us,  3,2 sy,  0,1 ni, 87,1 id,  0,1 wa,  0,0 hi,  0,2 si,  0,0 st
KiB Mem :  2060988 total,   256196 free,  1112400 used,   692392 buff/cache
KiB Swap:  2095100 total,  2089776 free,     5324 used.   681120 avail Mem

Como pode ser visto, o sistema de 32 bits mostra mais memória livre, 256 MB contra 47 MB, menos uso de swap, 5 MB contra 12 MB, mas tem menor memória disponível, 681 MB contra 842 MB.

Outro ponto interessante é que são 177 processos rodando em 64 bits contra 170 em 32.  E antes de perguntarem, não investiguei o motivo e não acho que realmente importe muito.  Mas percebi que por algum motivo acabei com versões de kernel diferentes.

root@ubuntu64:~# uname -a
Linux ubuntu64 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
root@ubuntu32:~# uname -a
Linux ubuntu32 4.8.0-45-generic #48~16.04.1-Ubuntu SMP Fri Mar 24 12:47:29 UTC 2017 i686 i686 i686 GNU/Linux

Isso tem importância na forma em que o kernel reserva a memória mas não usa.  Fora isso, o resto é o mesmo.

Consumo de memória com o comando top ou htop

É bastante comum a verificação de memória utilizada pelo comando top, htop ou mesmo ps.  É possívei ver uma saída mais ou menos como essa com o top.

top - 12:58:22 up 20:54,  2 users,  load average: 1,08, 0,43, 0,19
Tasks: 184 total,   1 running, 183 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3,5 us,  0,5 sy,  0,1 ni, 95,6 id,  0,1 wa,  0,0 hi,  0,1 si,  0,0 st
KiB Mem :  2048524 total,   106008 free,  1134092 used,   808424 buff/cache
KiB Swap:  2095100 total,  2017780 free,    77320 used.   860776 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 1241 helio     20   0 1254076 160784  10380 S 50,0  7,8  30:33.19 compiz
  767 root      20   0  480156  88992   8388 S 25,0  4,3  15:18.11 Xorg
 2272 helio     20   0 1539028 451060  50504 S  6,2 22,0  42:32.37 firefox
    1 root      20   0  185720   5708   3340 S  0,0  0,3   0:03.14 systemd
    2 root      20   0       0      0      0 S  0,0  0,0   0:00.00 kthreadd
    3 root      20   0       0      0      0 S  0,0  0,0   0:01.38 ksoftirqd/0
    5 root       0 -20       0      0      0 S  0,0  0,0   0:00.00 kworker/0:0H
    7 root      20   0       0      0      0 S  0,0  0,0   0:01.65 rcu_sched
    8 root      20   0       0      0      0 S  0,0  0,0   0:00.00 rcu_bh
    9 root      rt   0       0      0      0 S  0,0  0,0   0:00.00 migration/0
   10 root      rt   0       0      0      0 S  0,0  0,0   0:00.38 watchdog/0
   11 root      20   0       0      0      0 S  0,0  0,0   0:00.00 kdevtmpfs

O comando top mostra o consumo de memória em VIRT, RES e SHR.  É possível ver o firefox consumindo 1.54 GB de memória VIRT, 451 MB de memória RES e 50 MB de memória SHR.  Mas o que são?

Atualmente é muito difícil um programa tão grande quanto firefox ter todas as bibliotecas incluídas em seu binário.  Esse formato é chamado estático se usado.  Isso faria com que o executável ficasse gigantesco.  Fora isso, cada executável traria dentro de si a mesma biblioteca com os mesmos conteúdos.  E a cada atualização dessas bibliotecas, seria necessário alterar o executável também.

Pra melhorar a eficiência, binários criados no formato ELF, Executable and Linkable Format, tem uma parte do cabeçalho que informa onde buscar essas bibliotecas de funções, que são os arquivos .so.  São chamadas as bibliotecas dinâmicas, que podem ser atualizadas com o executável rodando.   Quando um binário ELF é executado, o kernel carrega seu código na memória e de suas bibliotecas de funções.  Se outro binário que aponta pra mesma biblioteca é executado, o kernel não carrega novamente a biblioteca, mas aponta pro endereçamento de memória onde essa já existe.

Então a memória VIRT, de virtual, mostra o total que um binário carregou na memória, inclusive com as bibliotecas dinâmicas que são compartilhadas.  Esse tamanho então não é exatamente o que aquele programa sozinho carrega.

A memória RES mostra o quanto de memória está na RAM e não no SWAP.  Mas ela mostra o total, incluindo das bibliotecas dinâmicas que são compartilhadas com outros programas.

A memória SHR é da compartilhada, de quanto de memória é compartilhado com bibliotecas dinâmicas.

O resultado é que pra saber o quanto um programa está consumindo por si só, seria algo como VIRT menos a SHR.  Dai seria possível ver quanto o executável ocupa de memória, mais os stack de dados.  Só que fica a pergunta: e a parte compartilhada?  Não conta?

Conta!  É memória consumida.  É RAM que não pode usar.  Mas como fazer isso?  Se o firefox e o unity, como exemplo, compartilharem uma biblioteca de renderização 3D, então a gente diz que cada um consumiu metade dessa memória alocada?  E se tiver mais um terceiro, ou quarto ou muito mais programas compartilhando essa mesma biblioteca?  A resposta é tão complicada que é esse o motivo que o programa top não tenta resolver isso e mostra o total alocado, mesmo sabendo que boa parte daquilo é compartilhado.

Algumas formas de ver o quanto cada programa ocupa em stack de memória sem as bibliotecas compartilhadas são os comandos pmap e readelf, que serão usados mais adiante.

Uso de memória do firefox

Vamos começar pelo tamanho dos binários.  O binário de 32 bits é muito menor que o de 64 bits?

root@ubuntu64:~# ls -l /usr/lib/firefox/firefox
-rwxr-xr-x 1 root root 125152 mar 29 18:25 /usr/lib/firefox/firefox
root@ubuntu32:~# ls -l /usr/lib/firefox/firefox
-rwxr-xr-x 1 root root 136664 mar 29 18:50 /usr/lib/firefox/firefox

E já de cara as coisas começam a ficar mais interessantes.  O binário do firefox em 32 bits é maior que o de 64 bits.  Usando o comando readelf -S é possível olhar o conteúdo de ambos e quanto de memória ocupa cada parte.  Mas vou evitar colocar aqui o resultado inteiro pois é muito longo e não será fácil visualizar as diferenças.  Então mostro apenas as partes diferentes de ambos.  Os valores estão em hexadecimal.

  32 bits 64 bits
.gnu.hash 04d4 04c4
.dynsym 0ea0 1578
.dynstr 184f 17c8
.gnu.version 01d4 01ca
.gnu.version_r 01a0 0160
.rel.dyn 0468 0cd8
init 0023 001a
.plt.got 02b0 02a0
.text 013b34 0123ff

Não completei a tablet toda, mas já dá pra perceber que os valores em 64 bits são menores em geral.  Antes de uma pergunta sobre o motivo, isso eu não sei.  Talvez algo em relação com compilador.

E quanto estão ocupando de memória rodando?  Isso fica fácil verificar com o comando pmap.

root@ubuntu64:~# pmap  2272  | grep total
  total          1548796K
root@ubuntu32:~# pmap 2334 | grep total
 total   959916K

E o firefox ocupa 1.55 GB de RAM em 64 bits contra 956 MB em 32.  Alguns já começam a se exaltar e gritar "viu! eu falei!" mas... e sempre tem um mas... em 32 bits, não sei a razão disso, o firefox usa um plugin-container junto.  Ao matar esse plugin-container...

então ele tem de contar com o consumo de memória do firefox como um todo.  Sendo assim.

root@ubuntu32:~# ps auxwww | grep -i firefox
helio     2334  1.3 11.5 959920 238924 ?       Sl   apr01  17:44 /usr/lib/firefox/firefox
helio     2490  3.6 19.6 1102860 404644 ?      Sl   apr01  47:30 /usr/lib/firefox/plugin-container -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 2334 true tab
root      9461  0.0  0.0   6644   840 pts/4    S+   13:42   0:00 grep --color=auto -i firefox
root@ubuntu32:~# pmap 2334 | grep total
 total   959916K
root@ubuntu32:~# pmap 2490 | grep total
 total   996360K

O total de uso de memória em 32 bits é na verdade 1956276K, 1.96 GB de RAM.

O consumo de memória é mais otimizado em 64 bits.  O esperado resultado de 32 bits ocupar menos memória não passa de uma lenda urbana.

Fazendo nossos próprios binários

Mas podemos fazer algo mais interessante e olhar à fundo as difrenças de 32 bits e 64 bits em arquiteturas de 64 bits.  Pra isso eu criei um pequeno programa em C que basicamente cria uma string com meu nome e copia pra outra variável.  E fica fazendo isso.  O motivo é apenas fazer análise de uso de memória com readelf e pmap.

testing.c

#include
#include
#include

char nome[] = "Helio Loureiro";

int main() {
    char tmp[sizeof(nome)];
    while(1) {
        sleep(30);
        strcpy(tmp, nome);
   }
}

Compilando e verificando os tamanhos dos binários.

root@ubuntu64:~# vi testing.c
root@ubuntu64:~# gcc -o testing testing.c
root@ubuntu64:~# ls -l testing
-rwxr-xr-x 1 root root 8696 apr  1 18:22 testing
root@ubuntu32:~# vi testing.c
root@ubuntu32:~# gcc -o testing testing.c
root@ubuntu32:~# ls -l testing
-rwxr-xr-x 1 root root 7424 apr  1 18:22 testing

Nesse caso bem simples, com nenhuma biblioteca dinâmica em uso além da própria GNU libc, o executável em 32 bits ficou menor.  Não metade do tamanho, mas 14% menor.  E rodando?

root@ubuntu64:~# ./testing &
[1] 19892
root@ubuntu64:~# pmap -x 19892
19892:   ./testing
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- testing
0000000000400000       0       0       0 r-x-- testing
0000000000600000       4       4       4 r---- testing
0000000000600000       0       0       0 r---- testing
0000000000601000       4       4       4 rw--- testing
0000000000601000       0       0       0 rw--- testing
00007f21a0044000    1788     816       0 r-x-- libc-2.23.so
00007f21a0044000       0       0       0 r-x-- libc-2.23.so
00007f21a0203000    2048       0       0 ----- libc-2.23.so
00007f21a0203000       0       0       0 ----- libc-2.23.so
00007f21a0403000      16      16      16 r---- libc-2.23.so
00007f21a0403000       0       0       0 r---- libc-2.23.so
00007f21a0407000       8       8       8 rw--- libc-2.23.so
00007f21a0407000       0       0       0 rw--- libc-2.23.so
00007f21a0409000      16       8       8 rw---   [ anon ]
00007f21a0409000       0       0       0 rw---   [ anon ]
00007f21a040d000     152     140       0 r-x-- ld-2.23.so
00007f21a040d000       0       0       0 r-x-- ld-2.23.so
00007f21a0615000      12      12      12 rw---   [ anon ]
00007f21a0615000       0       0       0 rw---   [ anon ]
00007f21a0630000       8       8       8 rw---   [ anon ]
00007f21a0630000       0       0       0 rw---   [ anon ]
00007f21a0632000       4       4       4 r---- ld-2.23.so
00007f21a0632000       0       0       0 r---- ld-2.23.so
00007f21a0633000       4       4       4 rw--- ld-2.23.so
00007f21a0633000       0       0       0 rw--- ld-2.23.so
00007f21a0634000       4       4       4 rw---   [ anon ]
00007f21a0634000       0       0       0 rw---   [ anon ]
00007ffd44054000     132      12      12 rw---   [ stack ]
00007ffd44054000       0       0       0 rw---   [ stack ]
00007ffd440e3000       8       0       0 r----   [ anon ]
00007ffd440e3000       0       0       0 r----   [ anon ]
00007ffd440e5000       8       4       0 r-x--   [ anon ]
00007ffd440e5000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB            4224    1048      84
root@ubuntu32:~# ./testing &
[1] 9589
root@ubuntu32:~# pmap -x 9589
9589:   ./testing
Address   Kbytes     RSS   Dirty Mode  Mapping
08048000       4       4       0 r-x-- testing
08048000       0       0       0 r-x-- testing
08049000       4       4       4 r---- testing
08049000       0       0       0 r---- testing
0804a000       4       4       4 rw--- testing
0804a000       0       0       0 rw--- testing
b75d7000    1724     732       0 r-x-- libc-2.23.so
b75d7000       0       0       0 r-x-- libc-2.23.so
b7786000       4       0       0 ----- libc-2.23.so
b7786000       0       0       0 ----- libc-2.23.so
b7787000       8       8       8 r---- libc-2.23.so
b7787000       0       0       0 r---- libc-2.23.so
b7789000       4       4       4 rw--- libc-2.23.so
b7789000       0       0       0 rw--- libc-2.23.so
b778a000      12       8       8 rw---   [ anon ]
b778a000       0       0       0 rw---   [ anon ]
b77a5000       8       8       8 rw---   [ anon ]
b77a5000       0       0       0 rw---   [ anon ]
b77a7000       8       0       0 r----   [ anon ]
b77a7000       0       0       0 r----   [ anon ]
b77a9000       8       4       0 r-x--   [ anon ]
b77a9000       0       0       0 r-x--   [ anon ]
b77ab000     136     136       0 r-x-- ld-2.23.so
b77ab000       0       0       0 r-x-- ld-2.23.so
b77cd000       4       4       4 rw---   [ anon ]
b77cd000       0       0       0 rw---   [ anon ]
b77ce000       4       4       4 r---- ld-2.23.so
b77ce000       0       0       0 r---- ld-2.23.so
b77cf000       4       4       4 rw--- ld-2.23.so
b77cf000       0       0       0 rw--- ld-2.23.so
bfe72000     132       8       8 rw---   [ stack ]
bfe72000       0       0       0 rw---   [ stack ]
-------- ------- ------- ------- 
total kB    2068     932      56

É possível ver que em 64 bits o programa ocupa o dobro de memória em RAM que 32 bits.  São 4224 KB contra 2068 KB.  E é possível ver que é causado pela libc em 64 bits.  Essa memória é totalmente usada pelo programa?  Não uma vez que a libc é compartilhada.  Mas em 64 bits ela faz duas chamadas para si.  O restante, como stack, os valores são exatamente os mesmos.

Olhando com readelf pra investigar o tamanho de cada parte do binário.

root@ubuntu64:~# readelf -S -W testing
There are 31 section headers, starting at offset 0x1a40:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        0000000000400238 000238 00001c 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            0000000000400254 000254 000020 00   A  0   0  4
  [ 3] .note.gnu.build-id NOTE            0000000000400274 000274 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        0000000000400298 000298 00001c 00   A  5   0  8
  [ 5] .dynsym           DYNSYM          00000000004002b8 0002b8 000078 18   A  6   1  8
  [ 6] .dynstr           STRTAB          0000000000400330 000330 000045 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0000000000400376 000376 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0000000000400380 000380 000020 00   A  6   1  8
  [ 9] .rela.dyn         RELA            00000000004003a0 0003a0 000018 18   A  5   0  8
  [10] .rela.plt         RELA            00000000004003b8 0003b8 000048 18  AI  5  24  8
  [11] .init             PROGBITS        0000000000400400 000400 00001a 00  AX  0   0  4
  [12] .plt              PROGBITS        0000000000400420 000420 000040 10  AX  0   0 16
  [13] .plt.got          PROGBITS        0000000000400460 000460 000008 00  AX  0   0  8
  [14] .text             PROGBITS        0000000000400470 000470 0001a2 00  AX  0   0 16
  [15] .fini             PROGBITS        0000000000400614 000614 000009 00  AX  0   0  4
  [16] .rodata           PROGBITS        0000000000400620 000620 000004 04  AM  0   0  4
  [17] .eh_frame_hdr     PROGBITS        0000000000400624 000624 000034 00   A  0   0  4
  [18] .eh_frame         PROGBITS        0000000000400658 000658 0000f4 00   A  0   0  8
  [19] .init_array       INIT_ARRAY      0000000000600e10 000e10 000008 00  WA  0   0  8
  [20] .fini_array       FINI_ARRAY      0000000000600e18 000e18 000008 00  WA  0   0  8
  [21] .jcr              PROGBITS        0000000000600e20 000e20 000008 00  WA  0   0  8
  [22] .dynamic          DYNAMIC         0000000000600e28 000e28 0001d0 10  WA  6   0  8
  [23] .got              PROGBITS        0000000000600ff8 000ff8 000008 08  WA  0   0  8
  [24] .got.plt          PROGBITS        0000000000601000 001000 000030 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000601030 001030 00001f 00  WA  0   0  8
  [26] .bss              NOBITS          000000000060104f 00104f 000001 00  WA  0   0  1
  [27] .comment          PROGBITS        0000000000000000 00104f 000034 01  MS  0   0  1
  [28] .shstrtab         STRTAB          0000000000000000 001930 00010c 00      0   0  1
  [29] .symtab           SYMTAB          0000000000000000 001088 000678 18     30  47  8
  [30] .strtab           STRTAB          0000000000000000 001700 000230 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
root@ubuntu32:~# readelf -S testing
There are 31 section headers, starting at offset 0x1828:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000060 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0804822c 00022c 000052 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0804827e 00027e 00000c 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0804828c 00028c 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             080482ac 0002ac 000008 08   A  5   0  4
  [10] .rel.plt          REL             080482b4 0002b4 000018 08  AI  5  24  4
  [11] .init             PROGBITS        080482cc 0002cc 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482f0 0002f0 000040 04  AX  0   0 16
  [13] .plt.got          PROGBITS        08048330 000330 000008 00  AX  0   0  8
  [14] .text             PROGBITS        08048340 000340 0001a2 00  AX  0   0 16
  [15] .fini             PROGBITS        080484e4 0004e4 000014 00  AX  0   0  4
  [16] .rodata           PROGBITS        080484f8 0004f8 000008 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        08048500 000500 00002c 00   A  0   0  4
  [18] .eh_frame         PROGBITS        0804852c 00052c 0000c4 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      08049f08 000f08 000004 00  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      08049f0c 000f0c 000004 00  WA  0   0  4
  [21] .jcr              PROGBITS        08049f10 000f10 000004 00  WA  0   0  4
  [22] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
  [23] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
  [24] .got.plt          PROGBITS        0804a000 001000 000018 04  WA  0   0  4
  [25] .data             PROGBITS        0804a018 001018 000017 00  WA  0   0  4
  [26] .bss              NOBITS          0804a02f 00102f 000001 00  WA  0   0  1
  [27] .comment          PROGBITS        00000000 00102f 000034 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 00171b 00010a 00      0   0  1
  [29] .symtab           SYMTAB          00000000 001064 000470 10     30  47  4
  [30] .strtab           STRTAB          00000000 0014d4 000247 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Pra facilitar a análise, crie uma tabela com os valores em hexadecimal, em decimal e os valores de 64 bits menos os valores de 32 bits.  Se 64 bits tiver valores maiores, o resultado é positivo.  Do contrário, negativo.  Isso mostra que a quantidade bytes alocados é maior ou menor em cada caso.

 

Name Type Size 64 bits (hexa) Size 32 bits (hexa) 64 bits (dec) 32 bits (dec) Bigger?
NULL 0 0 0 0 0 0
.interp PROGBITS 00001c 154 28 340 -312
.note.ABI-tag NOTE 20 168 32 360 -328
.note.gnu.build-id NOTE 24 188 36 392 -356
.gnu.hash GNU_HASH 00001c 0001ac 28 428 -400
.dynsym DYNSYM 78 0001cc 120 460 -340
.dynstr STRTAB 45 00022c 69 556 -487
.gnu.version VERSYM 00000a 00027e 10 638 -628
.gnu.version_r VERNEED 20 00028c 32 652 -620
.rela.dyn RELA 18 0002ac 24 684 -660
.rela.plt RELA 48 0002b4 72 692 -620
.init PROGBITS 00001a 0002cc 26 716 -690
.plt PROGBITS 40 0002f0 64 752 -688
.plt.got PROGBITS 8 330 8 816 -808
.text PROGBITS 0001a2 340 418 832 -414
.fini PROGBITS 9 4,00E+04 9 262144 -262135
.rodata PROGBITS 4 0004f8 4 1272 -1268
.eh_frame_hdr PROGBITS 34 500 52 1280 -1228
.eh_frame PROGBITS 0000f4 00052c 244 1324 -1080
.init_array INIT_ARRAY 8 000f08 8 3848 -3840
.fini_array FINI_ARRAY 8 000f0c 8 3852 -3844
.jcr PROGBITS 8 000f10 8 3856 -3848
.dynamic DYNAMIC 0001d0 000f14 464 3860 -3396
.got PROGBITS 8 000ffc 8 4092 -4084
.got.plt PROGBITS 30 1000 48 4096 -4048
.data PROGBITS 00001f 1018 31 4120 -4089
.bss NOBITS 1 00102f 1 4143 -4142
.comment PROGBITS 34 00102f 52 4143 -4091
.shstrtab STRTAB 00010c 00171b 268 5915 -5647
.symtab SYMTAB 678 1064 1656 4196 -2540
.strtab STRTAB 230 0014d4 560 5332 -4772

Como pode ser visto na tabela, em todas as partes de cabeçalho ELF do executável, 64 bits é menor.  O resultado é um binário com mais espaço na memória por alguma diferença na GNU libc, que não necessariamente significa que seu programa está ocupando mais memória em 64 bits.  Pelo contrário.  O stack pra dados alocados em geral é o mesmo que em 32 bits, mas o binário criado é mais eficiente com menor uso.

Espero com isso ter mostrado que 32 bits em arquitetura de 64 não traz um benefício real em dados.  O motivo de pessoas dizerem que ficou mais rápido?  Pode ser o resultado de algum outro problema de HD ou coisa do tipo, mas não pela arquitetura da CPU rodar melhor 32 bits em 64 bits, como alguns acham que é.  No fim essa discussão de melhor ou pior fica num campo de sensações.  Então é complicado argumentar contra alguém que acha que ficou mais rápido.

Minha sugestão final: se tem uma CPU que suporta 64 bits, use 64 bits.

Escrito por Helio Loureiro
Categoria:

E começou 2017.  Pra celebrar o ano novo, resolvi entrar com tudo no Ubuntu 16.04, Xenial.

Ubuntu 16.04

Apesar de ser 2017 e o Ubuntu 16.04 ter sido lançado em abril de 2016, a versão que uso é corporativa, o que significa homologada pela empresa.  Então leva um tempo até estar certificado pra uso (o que significam várias adaptações na Intranet também).  O anúncio de sua disponibilidade foi quase no fim de dezembro de 2016 e fiquei feliz de começar 2017 já com um sistema novo.

Eu tinha já atualizado meu desktop pro 16.04, mas eu praticamente nunca o uso.  Está lá o steam instalado, mas eu dificilmente ligo.  Quem me adicionou pra jogar saber disso (spoiler: eu também jogo mal pra caramba).

Mas a instalação no meu laptop seria um passo muito maior, com uso diário e desenfreado do sistema, puxando ao limite.

Uptime 241 days

Nem preciso dizer que até rolou uma lágrima quando rebootei meu Ubuntu 14.04 com 241 dias de uptime pra fazer upgrade.  Foram quase 8 meses de longevidade.  Mas eu precisava desse upgrade.  Um sistema de 2014 estava pra lá de desatualizado.

A instalação foi tranquila e terminou depois de aproximadamente meia hora.  Mesmo sendo um laptop com SSD, o que demorou mesmo foi a recuperação dos dados do meu /home.  E sim, foi preciso reinstalar.  Recomendação da Canonical.

Mas como alguém forjado no fogo do Unix através de décadas, certeza que fiz backup.  Inclusive perdi um certo tempo salvando meus containers preciosos de docker. E... esqueci de fazer backup do diretório onde salvei os containers.  Mas meu /home foi recuperado. .oO(nota mental: salvar os containers num diretório que eu realmente faça backup)

O Ubuntu 16.04 já sai pedido atualizações pra virar 16.04.1.  Sinal do tempo que levou pra ser homologado.  O kernel padrão é o 4.4.x, então não perdi tempo e, enquanto sincronizava o /home, já fui dando git clone no repositório do kernel.  Tentei o kernel 4.9 mas encontrei problemas no suspend e na parte gráfica.  Tentei o 4.10-rcx e também encontrei instabilidade.  Voltei pro 4.7.x.  Fiquei com ele até ontem, quando problemas na placa gráfica da Intel começaram a aparecer (os videos, como efeito colateral, ficavam sempre atrasados em relação ao som).  Então compilei o 4.9.5 que teve release faz 2 dias.  E aparentemente está tudo funcionando melhor.

Linux elxaf7qtt32 4.9.5-helio #7 SMP PREEMPT Sat Jan 21 23:35:49 CET 2017 x86_64 x86_64 x86_64 GNU/Linux

Mesmo rodando systemd, minha decepção ficou por conta do KDE5.  Vários coredumps, travadas em geral, mudança na proteção de tela, que agora é uma insossa tela estática com imagem ao invés de xscreensaver, mundança na UI de configuração e, o que foi o pior, mudança na API de systray do Xprotocol.  Isso significou que programas como pidgin e keepassx simplesmente não voltam mais se são minimizados.  A coisa desandou tanto que tive de sair do KDE5.  Experimentei alguns outros WMs e no fim terminei com o mate.  Não sou fã do Gnome, mas o mate deve servir até eu recompilar o KDE4 inteiro pro Xenial.  Essa é a solução que vi no momento.  Eu estava tão excitado com plasma... decepção... decepção...

Mas fora o KDE5, o sistema roda redondo.  Já gravei 2 webcasts esse ano no Unix Load On e o gerenciamento de dispositivos funcionou lindamente (pavucontrol na veia).  Também já fiz um vídeo com o Kdenlive que se mostrou melhor e até mais rápido que a versão que usava no 14.04.

No geral estou feliz com a versão mais nova do Ubuntu, mas triste em ver que o KDE permitiu um release tão podre da sua versão 5.  E antes que mencionem ser uma versão mais velha e com muitos bugs, eu sincronizei com o ppa do kubuntu pra pegar os releases e updates mais recentes.  Alguns bugs resolvidos mas... coredump em quase tudo.

E vamos ver se chego novamente nos 241 dias de uptime.  Só faltam 240 dias e 6 horas pra chegar lá.

Escrito por Helio Loureiro
Categoria:

A convite do pessoal do SecurityCast, participei de um webcast pra desmistificar sobre ataques em redes de telefonia, mais especificamente no core da rede, nos enlaces de sinalização SS7.

Não sei se consegui deixar muito claro os pontos, pois o tempo é curto pra entrar em detalhes, mas espero ter respondido a maioria das dúvidas sobre essa rede e sua segurança.

As redes de sinalização de telefonia não tem criptografia ou algo do tipo, mas estão cercadas por um ambiente seguro.  A segurança do perímetro é responsável por garantir o sigilo, confidencialidade e integridade da informação, não a rede em si.

Escrito por Helio Loureiro
Categoria:

Faz anos que escrevi sobre um uptime de 100 dias, em guerra dos 100 dias, e agora finalmente bati esse uptime.

No momento o uptime é um pouco maior:

17:42:23 up 212 days,  3:29, 31 users,  load average: 1.54, 1.25, 1.27

mas já vale pra ilustrar o quanto o Linux evoluiu em estabilidade.  Não só ele, mas toda a distro, que no meu caso é Ubuntu.

Anteriormente a maioria de problemas que exigiam o desligamento eram sempre relacionados com driver de vídeo Intel (na época do uptime de 100 dias).  Recentemente eu experimentei alguns congelamentos por falta de memória e até mesmo alguns crashes ao mudar de monitor (altero com bastante frequência entre só a tela do laptop, laptop e um monitor, e laptop e projetor).  Também tive problemas com entrada e saída de áudio com pulseaudio.

Por esse motivo eu sempre tentei compilar uma kernel mais recente e experimentar.  No caso estou 4.5.4.  Nem era dos mais estáveis e ainda está com bug de segurança pra acesso local, como o Dirty COW.  Uma vez que a invasão exige acesso local, estou relativamente seguro (se acessarem meu laptop, provavelmente será mais pelo valor do equipamento que pelos dados).

Mas uso diariamente meu laptop e de forma bastante extensiva.  Uso com docker, compilação de programas em C e C++, VMs com virtualbox e libvirt, edição de vídeo e de fotografia, etc.  É o famoso "pau pra toda obra".  E sem demais problemas.

Encontrei alguns?  Com certeza.  Tive alguns crashes do Xorg.  Mas como tenho habilitado o <ctr>+<alt>+<backspace> pra fechar o X inteiro e forçar um restart, não perdi nada além alguns segundos.

Fico feliz em usar Linux de uma maneira tão útil e que permite ser produtivo, tendo meu desktop pronto somente abrindo a tampa.

E por falar de desktop, fiz recentemente um vídeo pra mostrar o porquê de eu usar KDE, que adoro.

E agora tentar chegar em 365 dias.  Ou mais.

 

Escrito por Helio Loureiro
Categoria:

Software livre pode ser uma vantagem estratégica pra empresas, seja como forma de manter os custos baixos com uso da gratuidade dos programas ou seja como forma de inovação tecnológica pela forma simples e aberta de integrar os software. Mas e no lado pessoal?  Como seguir uma carreira com software livre?

Contarei como foi no meu caso, mas... não recomendo seguir os mesmos passos.  Eu tive sorte de uma questão de momento, que abriu uma enorme oportunidade pra mim.  Atualmente essa mesma condição não existe mais.  Então tente ver a questão de oportunidade aproveitada e só isso.  Como o texto ficou muito longo, resolvi quebrar em partes pra abordar o início, e como se desenvolveu em seguida.

 

[AVISO: O RESTANTE DO TEXTO É LONGO E CONTÉM MUITA, MUITA, MAS MUITA NOSTALGIA]

 

Eu comecei com software livre na faculdade, UFSC, em 97.  Eu tinha um computador que havia sido sucateado pela família, um 486, mas que era perfeito pros meus trabalhos na faculdade.  Por um acaso muito grande, um raio caiu na rede elétrica e fritou a placa mãe.  O que foi um grande azar na época acabou por se tornar um catalisador do restante da minha vida profissional nos 19 anos seguintes (e contando).

Sem muita opção eu acabei arrumando uma placa mãe de um 386 com 8MB de RAM com um amigo (valeu kibão!).  Sem coprocessador numérico.  A máquina era uma carroça e o tal do Windows 95 travava o tempo todo.  Naquela época a vida era um inferno.

E nesse inferno por coincidência eu iniciei uma matéria optativa: Unix.  Achei muito legal o sistema e descobri que tinha uma variação dele que rodava no meu cambaleante 386:  era um RedHat.  Acho que 4.  Dois CDs de instalação da Cheap&Bytes.

 

De início não funcionava.  Eu não conseguia instalar, mas o tal de Slackware, em disquetes funcionava.  Levei 1 mês pra desvendar o problema que era o cdrom conectado na placa de som e que exigia um parâmetro extra no RedHat após o boot.  Mas esse mês de insistência me ajudou a aprender o caminho unix de se fazer as coisas: leia as manpages!

Eu passava horas e horas nos laboratórios da faculdade lendo howtos e manpages na Internet.  Documentação existia, mas não era fácil mandar um "como faz isso aqui" pra alguém responder.  Existia a lista de discussão linux-br, mas perguntar algo que estava facilmente disponível em documentação era pedir pra ser chicoteado em praça pública.  A caminhada da vergonha de Sersei em game of thrones é muito menos humilhante pra ter idéia de como era.  Mas nesse ambiente hostil, onde só os mais fortes sobreviviam, eu consegui permanecer.  E instalar o tal RedHat.

Era um prazer imensurável ter aquele ambiente OpenWin igual do Solaris da faculdade rodando em casa.  E tinha spice (um programa de simulação de circuitos elétricos - coisa de quem faz engenharia elétrica)!  Não exatamente aquele todo gráfico e bonitinho da faculdade, mas um todo em texto.  O importante era que funcionava.  E depois de ter aprendido a usar o editor vi, entre muitas lágrimas de revolta e me perguntando como alguém poderia ter criado aquilo, o spice era moleza.

 

Mas não tinha editor de textos WYSIWYG (What You See Is What You Get - o que você vê é o que você quer).  Não tão simples quanto o Microsoft word.  Essa limitação me levou rapidamente a aprender e usar latex.  Textos muito mais elegantes num "vi" de distância de você.  A bem da verdade eu usava emacs pra isso.

Não demorou muito e tudo aquilo virou minha paixão.  Escolhi uma distro pra viver a minha vida com o mesmo amor com que se escolhe um time de futebol. Era torcida pura e simples.  Flameware de formatos de pacotes, escrever textos e documentação sobre tudo o que fazia e participar de encontros.  Foi assim que acabei indo pro primeiro FISL e conhecendo essas figuras que depois fizeram e até hoje fazem parte da minha vida profissional e até mesmo pessoal.

 

Nessa época meu sonho era ser sysadmin.  Mas não sysadmin de Linux.  Eu queria ser daqueles sysadmins que eram mitos.  Um quase Denis Ritchie.  Só não podia ser trabalho com Windows.  No máximo uma configuração de servidor samba.

Então nesse pique quase que obssessivo por me torna um sysadmin, eu comecei a fazer consultorias em Unix.  Alguns eram implementação de firewall, que eu já dominava com certa facilidade, outras eram pra instalar uma solução completa de servidor web, mail e dns.  Fiz vários updates de servidores SCO pra Linux ou FreeBSD, que virou minha outra paixão nessa época  (um TRUE Unix se comparado com Linux, que vinha do Minix - meu pensamento na época). 

Toda essa introdução de como comecei com Linux é somente pra ilustrar de como eu não tinha a menor idéia do que estava fazendo.  Não sei se outros da mesma geração como Eduardo Maçan, Nelson Murilo e Klaus Stedding-Jenssen sabiam.  Sem modéstia nenhuma, esses caras eram monstros em Unix.  Eu achava divertido, mas não entendia nada de Unix, programação, redes de computadores ou mesmo segurança.  Só me achava o máximo por rodar um Unix em casa igual ao da faculdade.  Lutar pela liberdade?  A luta era sair do Windows.  Essa era a luta pra mim.  E ter um computador funcional num 386 de 8 MB de RAM sem coprocessador numérico.  Essa era liberdade que eu queria.

Com o caminho de sysadmin escolhido, mergulhei em livros e estudei muito.  Quase abandonei a faculdade de engenharia elétrica pra tentar seguir só como sysadmin.  Nesse ponto o fato de morar em Florianópolis ajudou bastante pois era difícil encontrar emprego na área.  Então acabei levando a faculdade até o fim.  Do contrário teria tomado a decisão errada de parar os estudos.

Ao terminar a faculdade, e tentando viver como sysadmin, consegui alguns trabalhos em provedores locais que usavam Linux.  Tive inclusive a oportunidade de trabalhar com máquinas FreeBSD.  Mas a quantidade de trabalho não era tão grande assim, nem pagava tão bem.  Então eu mantinha uma bolsa de trabalho na faculdade também.

Com os "freelas" aparecendo, consegui uma oportunidade pra cobrir um colega numa empresa de treinamentos.  Esse foi meu início como instrutor de cursos de Linux, segurança e logo depois de cabeamento estruturado.  Eu entendia de Linux, mas segurança e cabeamento... então tive de buscar apostilas e livros e estudar.  Pra cabeamento estruturado até mesmo uma certificação Furukawa eu tive de fazer.

Mas esse estudo e empenho trouxeram frutos.  Logo começaram a aparecer projetos maiores e mais interessantes, com empresas grandes.  Eu me associei à empresa de treinamentos e conseguimos uma parceria pra representar a Conectiva, empresa brasileira de sistema GNU/Linux, no estado de Santa Catarina.  Com a boa quantidade de trabalho, acabei abandonando a bolsa da faculdade pra me dedicar ao que eu gostava, que era ser um sysadmin profissional, instalando e configurando servidores, firewalls, IDSs, etc.

Mas logo eu comecei a sentir as limitações regionais.  Muitos dos trabalhos exigiam não somente meu mundinho sysadmin, mas uma integração total de sistemas em rede, ou seja, conhecer melhor roteadores e switches.  As opções de aprendizado eram complicadas pela falta de equipamento, que na época era muito cara.  Com isso eu tomei a decisão de buscar emprego numa empresa maior, onde eu pudesse ter contato com esse tipo de equipamento e tecnologia.

E assim eu consegui um trabalho em São Paulo, na empresa onde trabalho até hoje.  Essa parte em diante, deixo pra contar no próximo post :)

Escrito por Helio Loureiro
Categoria:

Abrimos uma pesquisa pra saber se as pessoas gostariam de um hangout falando sobre free software e open source, história, movimentos e polêmicas.  O "sim" ganhou uma larga margem, então fizemos o último programa do canal "Unix Load On" sobre isso.

Não sei se foi abordado tudo o que deveria ser falado, mas tenho certeza que a discussão longa, interminável e improdutiva sobre o asssunto também continuará.  Infelizmente.

Então aproveitem.

 

Escrito por Helio Loureiro
Categoria:

Estive trabalhando nos últimos tempos em publicar as palestras do FISL no Youtube.  Por que fazer isso?  Bom... primeiramente pra atender um interesse próprio que é assistir os vídeos na minha SmartTV, que é Smart, roda Linux, mas não suporta o formato OGV disponibilizado no site do FISL (software livre é sobre coçar sua coceira, lembram?).  Publicando o conteúdo no Youtube continua OGV por trás, mas daí a TV aceita o format HMTL5 pra envio do stream do vídeo.

Mas isso não é tudo.  Publicando no Youtube um público que não sabe da existência do FISL vai ter acesso aos vídeos.  Tenho notado vários acessos de gente no exterior ao conteúdo em inglês.

E tudo é feito de forma automatizada.  Como cada FISL usou uma forma distinta de publicação, tenho usando um mesmo script modificado a cada edição do evento.  Eles estão armazenados na minha conta de Github.

https://github.com/helioloureiro/homemadescripts

No momento estão carregados os vídeos da última e penúltima edição do FISL, mas pretendo carregar o máximo possível dos eventos anteriores.  

O outro motivo, além da disponibilização dos vídeos em outra plataforma (mesmo não sendo software livre), é ter um acesso permanente aos vídeos.  No momento estão hospedados nas máquinas da ASL assim como um dia tivemos nossas listas de mails nos servidores da CIPSGA (Comitê de Incentivo à Produção de Software Gratuito e Alternativo).  Não sei se a ASL está no mesmo nível da CIPSGA, que usava máquinas na SERPRO se não estou enganado, e por uma falha de disco perderam todos os dados, mas por precaução melhor fazer a maior quantidade de cópias possíveis dos vídeos.

Essa é a idéia no momento.

Nota: eu vi que alguns vídeos estão sem alguns caractéres.  É alguma conversão de utf-8 que deu errado :(

Escrito por Helio Loureiro
Categoria:

Depois da festança, sempre vem a ressaca.  Sempre.  O governo brasileiro sente com força esse pós-festa que se reflete em toda economia e deve durar ainda alguns bons anos pra se recuperar (haja engov).  Tudo causado por um certo "abuso" nos gastos que junto com um certo "otimismo demais" e uma não leitura da realidade resultou nisso.

E o governo brasileiro não está sozinho.  Eike Batista sofreu do mesmo mal com suas empresas X.  Vendidas como o modelo de empresas que se deveriam seguir no Brasil, com o típico empresário de sucesso, a bonança terminou antes que qualquer projeto fosse finalizado e empresas gerassem algo mais que prejuízo.  Como resultado a ressaca foi brava.  Quem acreditou, perdeu muito dinheiro.  Não, o Eike não perdeu dinheiro.

Em software livre existe algo parecido.  A festança foi a celebração da luta contra "as redes devassas", contra a "monitoração da NSA".  Como a canção de Gilberto Gil, todos gritavam "vamos fugir, desse lugar, babe" e apontavam a solução pra redes como Diaspora, Quitter, OpenMailBox, RiseUp, etc.  Quando escrevi o artigo as empresas nefastas e redes devassas, já apontava um problema de sustentabilidade: como uma alternativa dessa se mantem viável?  Quem paga essa conta?

Mas era época de festança.  Quem liga pra quem paga a conta enquanto tem cerveja?  E gratuita!  Todo brasileiro que se dizia ativista corria em euforia pra nova rede gratuita, gritando que errados eram os outros.  Éramos vendidos.  Não sabíamos o preço de nossa liberdade.

Mas chegou a ressaca.  Hoje ao entrar na rede do Diáspora, que faço pelo joindiaspora.com, que consegui participar por convite do Eduardo (BoiMate), encontrei um botão de doação.  Pra se manter vivo, o serviço precisa de máquina, acesso Internet, eletricidade, etc.  De forma voluntária é mantido o software e sistema, mas isso não basta: precisa de dinheiro.

Da mesma forma, com praticamente nenhum uso, tenho uma conta no OpenMailBox.  Das mensagens que recebo, o mesmo tipo de pedido: precisamos de dinheiro pra continuar existindo!

É algo terrível ou anti-ético?  Pelo contrário.  Se o modelo de financiamento não é por monetização com propaganda, nem vendendo nossos meta-dados, nada mais transparente que pedir dinheiro.  Querem usar o serviço?  Ajudem a manter!  A ASL pediu doações  pra realizar o FISL e teve, segundo relatos, um dos melhores FISLs dos últimos anos.  Vários serviços buscam financiamento pra se manter, inclusive a FSF.

De minha parte eu contribuo para:

  • JoinDiaspora (esporadicamente)
  • FreeBSD Foundation (esporadicamente)
  • WikiMedia Foundation (regularmente)
  • Free Software Foundation (regularmente)
  • Associação de Software Livre (regularmente)
  • Debian (esporadicamente)

Não é um valor alto, na verdade algo como 20 reais por mês em cada (exceção da FSF que cobra beeeeem mais caro), mas já deve ajudar.

E você que usa software livre, pra qual projeto faz doação em dinheiro?  Não acha que vale à pena ajudar algum projeto que goste?  Pense bem nisso antes da ressaca bater forte.