Entenda o funcionamento do pseudo filesystem /proc no Linux
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.
Líder em Treinamento e serviços de Consultoria, Suporte e Implantação para o mundo open source. Conheça nossas soluções:
About author
Você pode gostar também
Descubra o mundo da Cloud Computing com o curso gratuito da 4Linux
Cloud Computing, ou computação em nuvem, é a entrega sob demanda de recursos de TI via internet com preços pré-pagos. Ao invés de comprar, possuir e manter centros de dados
Guia Prático: Aprenda a Manipular Dados no MongoDB
Dando continuidade na série de MongoDB, após construir um Cluster de MongoDB usando o passo a passo do desse artigo, vamos agora manipular os dados dentro desse banco, ou como
Guia prático: Como criar grupos e aplicar regras de política com SUDO no FreeIPA
Este é o terceiro post de uma série de publicações sobre o FreeIPA. Até aqui vimos em outros posts como subir um servidor IPA e também seus clientes, como criar