Conhecendo o Kernel Linux pelo /proc (Parte 1)

Conhecendo o Kernel Linux pelo /proc (Parte 1)

O que é o “/proc” ?

O “/proc” ou “procfs” é um pseudo filesystem que nos permite interagir e observar as estruturas internas do kernel Linux em formato de arquivos. Nele podemos configurar comportamentos do kernel, como o ip forwarding, limites de memória compartilhada, limites de semáforos, habilitar/desabilitar ipv6,  comportamento de cache do filesystem e também obter informações sobre uso de memória, estados dos processos, dentre vários outros itens. É através dele que muita das ferramentas que conhecemos como “top”, “free”, “vmstat”, “ps” e várias outras conseguem obter seu dados.

Se não está entendendo nada do que comentei até agora, recomendo nosso treinamento System Administrator onde abordamos este tema.

Analisando os processos existentes:

Vamos começar esta série de posts analisando como podemos identificar os processos  do sistema operacional através do /proc. Para facilitar o entendimento iremos fornecer um repositório (https://github.com/wfelipew/memory-tests) com alguns trechos de códigos escritos em C para realizar demonstração dos comportamentos apresentados .

Inicialmente vamos executar nosso primeiro processo de demonstração, o mem.c.

#include stdio.h;

int main(int argc, char* argv[]){
printf("Up And Running");
getchar();
return 0;
}

$ gcc mem.c -o mem.o
$ ./mem.o
Up And Running

Com nosso código em execução, vamos verificar o seu PID através do comando abaixo:

$ pgrep mem.o
16753

De posse do PID, podemos iniciar a análise deste processo através do “/proc”, pois cada processo possui um diretório com seu PID no “/proc”.

Neste caso vamos começar analisando como o processo foi executado:

# cat /proc/16753/cmdline
./mem.o

Pode até parecer uma informação irrelevante, porém pode ser muito útil em cenário onde precisamos analisar o problema de um processo que foi inicializado anteriormente por outro usuário e não possui uma documentação de como ele foi iniciado.

Na mesma ideia do arquivo anterior, podemos consultar as variáveis de ambiente para saber quais existiam quando o comando foi executado, essa também é uma informação útil para entender como a aplicação foi inicializada e também pode ser útil para investigar processos suspeitos:

cat /proc/16753/environ
XDG_VTNR=7LC_PAPER=pt_BR.UTF-8LC_ADDRESS=pt_BR.UTF-8XDG_SESSION_ID=c2XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/iron_trooperLC_MONETARY=pt_BR.UTF-8CLUTTER_IM_MODULE=ximTERM=xterm-256colorVTE_VERSION=4002SHELL=/bin/bashWINDOWID=77600167LC_NUMERIC=pt_BR.UTF-8UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/3432GNOME_KEYRING_CONTROL=GTK_MODULES=unity-gtk-moduleUSER=iron_trooperLS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:LC_TELEPHONE=pt_BR.UTF-8QT_ACCESSIBILITY=1XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0SSH_AUTH_SOCK=/run/user/1000/keyring/sshDEFAULTS_PATH=/usr/share/gconf/ubuntu.default.pathLIBVIRT_DEFAULT_URI=qemu:///systemXDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdgDESKTOP_SESSION=ubuntuPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/gamesQT_IM_MODULE=ibusQT_QPA_PLATFORMTHEME=appmenu-qt5LC_IDENTIFICATION=pt_BR.UTF-8XDG_SESSION_TYPE=x11PWD=/home/iron_trooper/Documents/memory-testsJOB=gnome-sessionXMODIFIERS=@im=ibusGNOME_KEYRING_PID=LANG=en_US.UTF-8GDM_LANG=en_USMANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.pathLC_MEASUREMENT=pt_BR.UTF-8COMPIZ_CONFIG_PROFILE=ubuntuIM_CONFIG_PHASE=1GDMSESSION=ubuntuSESSIONTYPE=gnome-sessionGTK2_MODULES=overlay-scrollbarSHLVL=1HOME=/home/iron_trooperXDG_SEAT=seat0LANGUAGE=en_USGNOME_DESKTOP_SESSION_ID=this-is-deprecatedUPSTART_INSTANCE=UPSTART_EVENTS=started startingXDG_SESSION_DESKTOP=ubuntuLOGNAME=iron_trooperDBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-cbfSSb5lvfXDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/QT4_IM_MODULE=ximLC_CTYPE=pt_BR.UTF-8LESSOPEN=| /usr/bin/lesspipe %sINSTANCE=UnityUPSTART_JOB=unity-settings-daemonXDG_RUNTIME_DIR=/run/user/1000DISPLAY=:0XDG_CURRENT_DESKTOP=Un

Também é possível saber qual o workdir corrente do processo através do link “cwd”:

# ls -lh /proc/16753/cwd
lrwxrwxrwx 1 iron_trooper iron_trooper 0 Out 31 01:11 /proc/16753/cwd -> /home/iron_trooper/Documents/memory-tests

Qual o estado do meu processo ?

Outro arquivo que pode nos trazer uma grande quantidade de informações sobre o processo é o “status”:

# cat /proc/16753/status
Name: mem.o
State: S (sleeping)
Tgid: 16753
Ngid: 0
Pid: 16753
PPid: 14274
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 256
Groups: 4 24 27 29 30 46 113 128 139 141 1000
NStgid: 16753
NSpid: 16753
NSpgid: 16753
NSsid: 14274
VmPeak: 4412 kB
VmSize: 4228 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 804 kB
VmRSS: 804 kB
VmData: 64 kB
VmStk: 136 kB
VmExe: 4 kB
VmLib: 1936 kB
VmPTE: 24 kB
VmPMD: 12 kB
VmSwap: 0 kB
Threads: 1
SigQ: 0/31062
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
Seccomp: 0
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 1
nonvoluntary_ctxt_switches: 4

O primeiro ponto a ser notado aqui é o estado do processo, que neste caso é “S” de sleeping. Mas o que seria o um processo em estado sleeping ?

Nos próximos posts entraremos mais a fundo neste assunto, porém, dando um pequeno #spoiler o sleeping é um estado utilizado quando um processo precisa aguardar para um determinado recurso, assim, para que o processo não fique desperdiçando uso de CPU enquanto aguarda o processo entra em estado sleeping, desta forma a CPU não será alocada para execução até que o recurso desejado esteja disponível ou que processo receba uma interrupção.

O que meu processo esta aguardando ?

A grande questão agora é saber por qual recurso o processo esta aguardando??

Inicialmente podemos checar qual chamada de sistema esta aguardando, consultando o “wait channel” do processo.

# cat /proc/16753/wchan
wait_woken

O que meu processo esta executando ?

Neste caso a chamada de espera em questão é bem genérica (wait_woken) e não traz muita informação do que esta sendo aguardado.

Desta forma podemos consultar a stack completa para entender quem chamou a wait_woken:

# cat /proc/16753/stack
[<ffffffff810bcf82>] wait_woken+0x42/0x80
[<ffffffff814c17f3>] n_tty_read+0x273/0xb80
[<ffffffff814bb8ad>] tty_read+0x8d/0xf0
[<ffffffff811fcc58>] __vfs_read+0x18/0x40
[<ffffffff811fd227>] vfs_read+0x87/0x130
[<ffffffff811fdfa5>] SyS_read+0x55/0xc0
[<ffffffff817f01f2>] entry_SYSCALL_64_fastpath+0x16/0x75
[<ffffffffffffffff>] 0xffffffffffffffff

Através da stack é possível concluir que estamos aguardando por uma leitura de terminal (tty_read), ou seja, possivelmente o processo está aguardando pela digitação de uma tecla em um terminal.

Qual processo gerou esse processo ?

O próximo ponto útil neste arquivo (/proc/[]/status) é o PPid (Parent Pid), ele permite saber qual foi o processo que originou o processo.

# cat /proc/14274/cmdline
bash

Que neste caso foi o bash. Esse tipo de informação é extremamente útil na investigação de causa raiz de diversos tipos de problema, como por exemplo, em cenários onde temos uma grande quantidade de processos sendo criados e precisamos saber quem está criando estes processos.

Quem é o dono do processo ?

Na item UID e GID temos as informações de quem está rodando e a qual grupo pertence o processo em questão e no Groups temos os grupos adicionas as quais o usuário dono do processo faz parte.

Quais são os vínculos do meu processo ?

Outro ponto interessante aqui é NSpgid e o NSsid os quais definem o Process Group ID e o Session ID do processo, veremos isso com mais detalhes quando focarmos na parte processos, por enquanto, basta saber que eles são utilizados para enviar interrupções para um conjunto de processos, e a manipulação destes itens permite que um processo filho possa ser desvinculado por completo do processo pai. Em nosso exemplo podemos ver que o Session ID está vinculado ao nosso processo pai (14274).

# cat /proc/16753/status
Name: mem.o
State: S (sleeping)
Tgid: 16753
Ngid: 0
Pid: 16753
PPid: 14274

Quanto de memória este processo consome ?

Em seguida temos o bloco de uso de memória, com os seguintes itens:

  • VmPeak: Pico de memória virtual já atingida
  • VmSize: Tamanho atual da memória virtual
  • VmHWM: Pico de memória residente já utilizada
  • VmRSS: Uso de memória residente
  • VmData: Uso de memória para heap
  • VmStk: Uso de memória para área de stack
  • VmExe Uso de memória para o executável
  • VmLib Uso de memória compartilhada
  • VmSwap: Uso de swap

Com estas informações conseguimos analisar em nosso exemplo acima que este processo não está utilizando swap e que ele está utilizando apenas 804Kb efetivos da memória RAM (memória residente).

Não se preucupe com o restante dos itens por enquanto, no próximo post iremos nos aprofundar na questão de gerenciamento de memória.

O que mais podemos saber ?

Ainda no arquivo “status”  através do campo “threads” podemos saber quantas threads existem neste processo, neste caso apenas 1.

Por fim, através dos campos Cpus_allowed e Cpus_allowed_list é possivel saber se este processo possui alguma restrição a uso de um conjunto de núcleos de CPU, assim como Mems_allowed e Mems_allowed_list permite saber se existe alguma restrição ao uso de um conjunto de nós de memória. Esta informações pode ser de extrema relevância em cenários onde estamos analisando problemas de desempenho em ambiente desconhecido.

 

O que vem por ai ?

No próximo post iremos nos aprofundar sobre o funcionamento da memória virtual no Linux.

CURSOSCONSULTORIACONTATO

Anterior Coletando métricas do Wildfly com Prometheus
Próxima Group Panel com Grafana

About author

william.welter
william.welter 2 posts

Formado em ciência da computação, com as certificações LPIC-3, LPI DevOps Tools Engineer, LFCS, LFCE, ZCE-PHP5.3, ZFCA, PP9A, desenvolvedor PHP e C, com foco em Linux e software livre. Atualmente é gerente e líder técnico do time de consultoria e suporte na 4Linux, a qual atua principalmente com ferramentas DevOps, containers, cloud, monitoramento e sistemas de missão critica.

View all posts by this author →

Você pode gostar também

DevOps

Curso MongoDB Presencial em São Paulo | 4Linux

Bancos de dados são a base dos projetos de desenvolvimento Web. Muitos desenvolvedores estão voltando sua atenção para o MongoDB, um banco de dados sem esquema que é popular para uma

Cloud

Terraform #parte3 – Criando dependências entre recursos

Esta é o terceiro capítulo da nossa série de postagens sobre Terraform, neste post iremos falar sobre as dependências entre recursos. Caso tenha perdido o início da nossa série, recomendo

Infraestrutura

Screencast tutorial criando mapas de rede para monitoramento com zabbix.

Assista ao vídeo e confira o Screencast Tutorial: Criando mapas de rede para monitoramento com Zabbix. Conheça nosso novo curso Monitoramento de Redes com Zabbix agora com Oracle e Jboss. Baixe também