středa 10. února 2021

Smem - paměť procesů v detailu

Minule jsem psal o tom, jak to cca chodí s pamětí v linuxovém systému, dnes tedy aplikace. Původce proporcionálního PSS patche do smaps kernelu napsal také aplikaci smem, která tato (tehdy nová) data umí zpracovat. Na oficiální verzi 1.5 v repozitářích Ubuntu nikdo nesáhl už hodně dlouho, takže novinky kernelu tam zdaleka nejsou zakomponovány, ale tohle bude především o tom, jak jsem smem upgradoval já. Samozřejmě jsem, jako vždy, přidal i naprosto zbytečné detaily, které využije málokdo, ale přišlo mi škoda to neumět. Budu rád, když otestujete a zkritizujete, případně mi doplníte nějakou tu informaci.

 

 

Smem z repozitáře

Nicméně začnu tím, co je v repozitáři Ubuntu, ono to není zas tak málo.

$ sudo apt install smem

smem mapuje procesy a obsazení paměti v několika režimech volených přepínači:

  • základní zobrazení bez přepínače, výstupem je seznam procesů
  • -u/--users: seznam uživatelů se sečtenými procesy
  • -m/--mappings: seznam mapovaných souborů
  • -w/--system: zobrazuje souhrnné využití paměti systému. K tomuto režimu patří dále přepánače -R/--realmem pro zadání skutečné fyzické velikosti RAM, a -K/--kernel pro zadání cesty k rozbalenému kernelu pro započítání jeho velikosti.

Smem výstup umožňuje filtrovat regulárními výrazy a to ve všech třech základních režimech podle uživatele, příkazů, které procesy spustily, a podle mapovaných souborů. Můžete tak třeba zjistit, jaké procesy používají konkrétní knihovnu. Filtry se navíc dají kombinovat, takže si můžete vypsat pouze konkrétní knihovnu konkrétního procesu. Smem dále umí vypsat jen požadované sloupce v libovolném pořadí, podle libovolného seřadit výstup, a to i podle sloupce, který se výstupu nezúčastní. Umožňuje také analýzu dat z archivu (k tomu patří samostatná utilita smemcap napsaná v C pro dumpnutí potřebné části proc fs do archivu), nebo do systémového výpisu započítat velikost kernelu, když mu k němu (pozor - nekomprimovanému) zadáte cestu. Dokonce umí vykreslovat sloupce a koláče, doinstalujete-li python3-matplotlib. Na stránkách projektu jsou i nějaké příklady použití.

Pomocí smem zjistíte obsazení paměti Firefoxem jednoduše:

$ smem -ktP [f]irefox

Smem 1.5 bohužel neumí z filtru vyřadit sám sebe, tak je nutno použít hack s regulárním výrazem, třeba ten s hranatými závorkami. Také neumí využívat souboru smaps_rollup, tudíž je zbytečně pomalý, i tam kde už nemusí. Přepínač -k/--abbreviate je tam pro automatické přepočítání z výchozích kiB na MiB, GiB, TiB, … a přidání patřičné přípony. -t/--total pro celkové součty na posledním řádku, -P/--processfilter pro filtrování příkazů procesů.
Další možnosti si můžete vypsat pomocí smem --help, většinu dále proberu.

Já jsem tedy nakonec po pokusech s shell skripty a repozitářovým smem 1.5 stáhl čerstvější fork z Githubu od Kurta Kroegera. Tato verze přidává především širší možnosti formátování výstupu, ale byla zbavena části s grafy a koláči a také analýzy dat z externího archivu, což jsem si uvědomil až později a přijde mi to škoda, protože to bylo cíleno na vzdálenou správu, kdy vám server pošle dump užitečných souborů z /proc a vy to můžete analyzovat jinde. Tak jsem tedy kód testoval a snažil se to celé pochopit.

Nakonec jsem pochopil, opravil chyby, co jsem našel (některé jsou ještě v repozitářové verzi), dopsal funkčnost groupování procesů podle spustitelných souborů, přidal podporu smaps_rollup, čímž jsem základní sumarizace procesů zrychlil skoro řádově, a postupně dopisoval podporu dalších metrik nabízených novějšími kernely a další funkce, rozšiřující možnosti výstupu. Čím víc je paměť zaplněná, tím větší je při použití smaps_rollup časový rozdíl (analýza zaplněných cca 8,4 GB vzala originálnímu smemu 2,46 s, kdežto novému 0,28 s, a to je sakra znát. Samozřejmě, že když budete chtít vylistovat mapované soubory, nebo podle nich filtrovat, musí se použít plnotučný smaps, takže tam zrychlení nebude.

Kurtovu verzi jsem tedy na Githubu forknul a udělal vývojovou větvičku, kde řádím, takže můžete stahovat, testovat a nejlépe reportovat chyby, náměty. Nic speciálního to nepotřebuje, pouze nainstalovaný python3 pak stačí nastavit spustitelnost souboru smem a umístit ho nejlépe tam, kde na něj z shellu uvidí (skrz proměnnou \$PATH) jak uživatel, tak root, abyste nemuseli zadávat cestu k němu při spouštění (pro testování pod uživatelem stačí dát smem do ~/bin/).

Nové funkce

Postupně jsem do smem přidal / opravil následující:

  • Využití souboru smaps_rollup pro řádové zrychlení základního zpracování procesů
  • -g / --groupcmd: seskupuje procesy podle příkazů, kterými byly spuštěny
  • -b / --basename: zobrazje pouze jména spustitelných souborů místo celého příkazu. Má vliv i na seskupování procesů, protože pak /bin/bash a bash jedno jsou.
  • Nové sloupce pro nová data SwapPss, TPss, RssAnon, RssFile, RssShmem, PssAnon, PssFile, PssShmem, AvgVss.
  • Přibyl i sloupec Name zobrazující jméno procesu (Comm)
  • Filtrování procesů -P filtruje nejen řetězece z příkazu, ale i podle PIDu a jména procesu (Name/Comm)
  • Při filtrování procesů je vynechán vlastní proces.
  • -i/--ignorecase výraz pro vyhledávání nebude rozlišovat velká a malá písmena.
  • -W / --sysdetail pro detailnější náhled obsahu RAM.
  • Opravena detekce komprimace kernelu při využití přepínače -K/--kernel.
  • -T / --totalsonly zobrazí pouze celkové sumy sloupců, takže pokud vás zajímá pouze souhrn jediné veličiny, použije přepínač -T spolu s přepínači -H a -c “sloupec”
  • q / --quiet pro umlčení varování, která jsem přidal ohledně (ne)podporovaných funkcí
  • -c / --column nyní akceptuje místo jmen sloupců i all pro zobrazení všech dostupných a pomocí +sloupec1 sloupec2 ... můžete k výchozím další jen přidat.

Na starších kernelech, které můžete mít ještě třeba v Ubuntu 16.04, nebude možné využít nových metrik, které jsem přidal do nabídky sloupců, ale smem je ani nebude nabízet (zadáte-li neplatné jméno sloupce, smem vám s chybou vypíše všechny dostupné).

Příklady použití

Budu dávat příklady s mým upraveným programem, ale základní filtrace bez použití přidaných sloupců a přepínačů budou fungovat i s tím starým.

Celkové obsazení paměti např. prohlížečem Firefox

U mě to vypadá aktuálně takto (mívám toho otevřeno dost, když něco studuju):

$ smem -akbrtc "pid name command tpss pss uss rss vss swappss" -s tpss -P "firefox"
    PID Name            Command    TPSS     PSS     USS     RSS     VSS SwapPss 
1423856 Web Content     firefox  640.6M  489.6M  478.3M  531.6M    3.3G  151.0M 
1423561 firefox         firefox  594.4M  443.7M  376.4M  544.1M    4.9G  150.8M 
1423721 Web Content     firefox  579.9M  446.3M  424.2M  499.8M    3.5G  133.6M 
1423861 Web Content     firefox  457.9M  250.5M  246.9M  282.3M    3.2G  207.5M 
1423868 Web Content     firefox  432.6M  187.7M  183.9M  220.3M    3.0G  244.9M 
1423926 Web Content     firefox  403.8M  238.2M  214.3M  293.9M    3.2G  165.7M 
1423884 Web Content     firefox  303.8M  242.8M  236.3M  282.2M    3.1G   61.0M 
1423889 Web Content     firefox  276.1M   96.3M   92.6M  128.0M    2.9G  179.8M 
1423918 Web Content     firefox  251.2M   85.4M   82.2M  115.8M    3.0G  165.8M 
1424112 WebExtensions   firefox  163.8M  134.1M  131.2M  158.2M    8.7G   29.7M 
1424049 Privileged Cont firefox   77.3M   56.1M   53.3M   81.3M    2.4G   21.2M 
1426202 RDD Process     firefox   16.5M    5.1M    4.7M   10.2M  307.9M   11.4M 
--------------------------------------------------------------------------------
     12                            4.1G    2.6G    2.5G    3.1G   41.5G    1.5G 

Celková hodnota TPSS 4,1 GiB by tedy měla nejpřesněji odpovídat poměrném otisku Firefoxu v mém systému, přičemž 1,5 GiB z toho je momentálně odloženo do swapu. Zde můžete vidět, že RSS ukazuje pomalu o cca 500 mega více, než PSS. VSS naznačuje, že s virtuální pamětí se na 64 bitovém systému šetřit nemusí. Můžete si všimnout také různých jmen procesů, která Firefox používá.
Použil jsem přepínače -b/--basename pro potlačení zbytečných částí příkazů a přepínače -r/--reverse pro seřazení od nejvyšší hodnoty sloupce TPss vybraného přepínačem -s/--sort.
Jak jsem zmínil v minulém blogu, součet hodnot USS těchto procesů nedá skutečnou celkovou uvolněnou paměť při ukončení procesu, protože rozpočítává i soubory sdílené pouze těmito 12 procesy. Tzn. pokud např. všechny sdílí jedinou knihovnu o velikosti 120 MiB, každému je z něj do PSS počítáno 10 MiB a každému je těch 10 MiB také odebráno z USS, tudíž by v tomto případě měla být celková hodnota USS těchto procesů o 120 MiB vyšší.

V příkazech používám přepínač -c/--columns se seznamem požadovaných sloupců, protože chci konkrétní výstup, ale pokud přepínač nepoužijete, dostanete výchozí sloupce, které vám pro základní náhled mohou stačit.

Ještě doplním, že jako filtr můžete použít složitějších regulárních výrazů a tak není problém např. spočítat Firefox, i Chromium dohromady:

$ smem -P "firefox|chromium"

Výpis sdílených souborů použitých procesem / procesy

$ smem -maktrc "pids map tpss pss swappss avgpss avguss" -s tpss -P "firefox"

PIDs Map                                          TPSS     PSS SwapPss  AVGPSS  AVGUSS 
  12 <anonymous>                                  3.6G    3.2G  405.0M  276.4M  276.4M 
  12 /memfd:mozilla-ipc                         239.8M  239.8M       0   20.0M   16.8M 
  12 /usr/lib/firefox/libxul.so                 104.3M   83.0M   21.3M    6.9M    3.1M 
   6 /usr/lib/x86_64-linux-gnu/libLLVM-11.so.1   25.5M    1.2M   24.2M  208.0K  208.0K 
   1 /SYSV00000000                               17.3M   17.3M       0   17.3M       0 
   6 /usr/lib/x86_64-linux-gnu/dri/nouveau_dri    8.7M    4.0M    4.7M  674.0K  155.0K 
   9 /usr/lib/x86_64-linux-gnu/librsvg-2.so.2.    7.1M    2.3M    4.8M  265.0K  202.0K 
   9 /usr/lib/x86_64-linux-gnu/libavcodec.so.5    4.1M    1.8M    2.2M  210.0K  210.0K 
  12 [stack]                                      1.9M    1.6M  320.0K  138.0K  138.0K 
  12 /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.2    1.8M    1.4M  476.0K  117.0K   43.0K 
  12 /usr/lib/firefox/libmozsqlite3.so            1.1M  842.0K  236.0K   70.0K   50.0K 
   9 /usr/lib/x86_64-linux-gnu/libvorbisenc.so    1.0M  255.0K  804.0K   28.0K   26.0K 
  12 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.  905.0K  597.0K  308.0K   49.0K   30.0K 
   9 /usr/lib/x86_64-linux-gnu/libicuuc.so.66.  765.0K  233.0K  532.0K   25.0K   16.0K 
   9 /usr/lib/x86_64-linux-gnu/libzvbi.so.0.13  756.0K  220.0K  536.0K   24.0K   24.0K 
   6 /usr/lib/x86_64-linux-gnu/libGLdispatch.s  747.0K  155.0K  592.0K   25.0K   17.0K 
  12 /usr/lib/x86_64-linux-gnu/libepoxy.so.0.0  720.0K   32.0K  688.0K    2.0K    2.0K 
  12 /usr/lib/x86_64-linux-gnu/libgdk-3.so.0.2  704.0K  372.0K  332.0K   31.0K   16.0K 

     ...
   1 /usr/share/fonts/X11/Type1/c0583bt_.pfb         0       0       0       0       0 
   1 /usr/share/fonts/X11/Type1/c0582bt_.pfb         0       0       0       0       0 
   1 /run/user/1000/dconf/user                       0       0       0       0       0 
   1 /home/gdh/.cache/mozilla/firefox/uvpbrpq2       0       0       0       0       0 
---------------------------------------------------------------------------------------
3530 445                                          4.1G    3.6G  480.3M  324.7M  298.9M 

Ve výpisu mapovaných souborů můžete použít i sloupce, které data rozpočítají na všechny procesy, které je sdílí, ty začínají AVG. Aby se mi to vešlo rozumně na stránku, jsou cesty k souborům ořezané, přepínač -a/--autosize to zarovnal na šířku terminálu, ale není problém je nechat vypsat celé.

Zjištění velikosti zásobníku a haldy procesu

V ukázce výš si můžete všimnout, že součástí map je i [stack], tedy zásobník, takto najdete i [heap]. Oba si k procesu LibreOffice mohu vypsat následovně:

$ smem -ktmM "stack|heap"  -P soffice.bin
Map                                       PIDs   AVGPSS      PSS 
[stack]                                      1    44.0K    44.0K 
[heap]                                       1    25.7M    25.7M 
-----------------------------------------------------------------
2                                            2    25.8M    25.8M

Jaké procesy využívají konkrétní knihovnu / soubor

Přepínačem -M/--mapfilter můžete filtrovat místo procesů mapované objekty. Chcete-li zjistit, které procesy používají např. knihovnu gtk3, můžete na to jít takto (root/sudo není třeba, pokud vás zajímají pouze vaše procesy):

# smem -aktrc "pid command vss pss swappss tpss" -s tpss -M "libgtk-3.so"

PID Command                                   VSS     PSS SwapPss    TPSS 
3678458 file-roller /tmp/mozilla_gdh0/sme    7.7M    1.0M       0    1.0M 
   3739 /snap/snap-store/518/usr/bin/snap   11.3M  800.0K   44.0K  844.0K 
   5104 /usr/lib/firefox/firefox -content    7.7M  636.0K   32.0K  668.0K 
   5005 /usr/lib/firefox/firefox -new-win    7.7M  383.0K   24.0K  407.0K 
  67486 /usr/bin/nautilus --gapplication-    7.7M  406.0K       0  406.0K 
   3651 /usr/bin/python3 /usr/bin/guake      7.7M  356.0K    8.0K  364.0K 
   7651 /opt/sublime_text/sublime_text       7.7M  348.0K    8.0K  356.0K 
   3404 /usr/bin/gnome-shell                 7.7M  226.0K   32.0K  258.0K 
   5109 /usr/lib/firefox/firefox -content    7.7M  223.0K   20.0K  243.0K 
   4743 update-notifier                      7.7M  198.0K   28.0K  226.0K 
  67484 /usr/bin/gnome-software --gapplic    7.7M  225.0K       0  225.0K 
   3652 indicator-nameday cs                 7.7M  172.0K   28.0K  200.0K 
   5118 /usr/lib/firefox/firefox -content    7.7M  167.0K   24.0K  191.0K 
   5064 /usr/lib/firefox/firefox -content    7.7M  146.0K   40.0K  186.0K 
   5181 /usr/lib/firefox/firefox -content    7.7M  137.0K   36.0K  173.0K 
   5134 /usr/lib/firefox/firefox -content    7.7M  145.0K   28.0K  173.0K 
   5154 /usr/lib/firefox/firefox -content    7.7M  112.0K   32.0K  144.0K 
   5171 /usr/lib/firefox/firefox -content    7.7M  100.0K   32.0K  132.0K 
   3656 easystroke                           7.7M   56.0K   56.0K  112.0K 
   3551 /usr/libexec/gsd-media-keys          7.7M   47.0K   56.0K  103.0K 
        ...
   3290 /usr/libexec/gnome-session-binary    7.7M       0   76.0K   76.0K 
   3232 /usr/libexec/goa-daemon              7.7M       0   76.0K   76.0K 
--------------------------------------------------------------------------
     41                                    318.0M    6.0M    2.0M    8.0M 

Tady je krásně vidět, že ve virtuální paměti zabírá knihovna v každém procesu stejný prostor, ale její skutečné využití (načtení/namapování konkrétních stránek do RAM) se v jednotlivých procesech liší. Ta jediná výjimka je jiná verze knihovny, kterou má přibalenu aplikace běžící ze snapu.

Žebříček procesů seskupených podle stejného spustitelního souboru

To, kvůli čemu jsem s tímto vším začal, protože mě štvalo, že top 5 v Conky mám plné Firefoxů, které se ještě z většiny maskují jménem Web Content.

# smem -aktgbrc "pids command tpss pss uss rss vss swappss swap" -s tpss
PIDs Command              TPSS     PSS     USS     RSS     VSS SwapPss    Swap 
  12 firefox              5.2G    3.4G    3.3G    3.9G   42.5G    1.7G    1.9G 
   1 VirtualBoxVM         1.8G    1.7G    1.7G    1.7G    4.4G   80.2M   83.7M 
   1 sublime_text         1.3G  112.5M  103.7M  125.7M    3.1G    1.1G    1.1G 
   2 gnome-shell        581.7M  293.4M  288.8M  314.5M    8.6G  288.3M  289.4M 
   8 python3            190.2M   59.5M   54.4M   80.4M    1.8G  130.6M  139.7M 
   1 soffice.bin        136.3M   24.2M   23.6M   29.7M    1.6G  112.2M  116.6M 
   1 nautilus           120.1M   99.4M   97.2M  108.6M    1.7G   20.7M   23.7M 
   2 Xorg               117.9M   51.6M   21.1M   88.9M    1.2G   66.3M   96.3M 
  20 bash                75.0M   15.1M   14.3M   30.4M  305.0M   60.0M   60.0M 
   1 VirtualBox          70.7M   11.3M    9.9M   16.4M    1.5G   59.4M   59.4M 
   1 NetworkManager      51.5M   12.6M   12.5M   14.7M  902.9M   38.9M   38.9M 
   1 dockerd             39.3M   12.0M   12.0M   12.1M  997.0M   27.4M   27.4M 
   1 gthumb              35.6M   35.6M   32.9M   47.4M    1.2G       0  604.0K 
   3 gjs                 32.0M    6.1M    4.3M   19.2M    8.8G   25.9M   26.7M 
   1 containerd          22.2M    6.4M    6.4M    6.5M    1.1G   15.8M   15.8M 
   1 snapd               21.6M   11.2M   11.2M   12.0M    1.4G   10.4M   10.4M 
   2 tracker-miner-fs    20.1M    4.9M    4.7M   10.1M    1.8G   15.1M   15.1M 
   1 systemd-journald    17.9M   16.7M   15.9M   18.7M  523.0M    1.3M    1.3M 
   2 gsd-color           17.5M    5.5M    5.2M   13.0M    1.0G   12.0M   12.0M 
   6 dbus-daemon         15.5M    4.7M    4.4M   15.1M   55.0M   10.8M   10.8M 
   1 seahorse            14.6M    1.9M    1.8M    4.3M  456.5M   12.8M   12.8M 
   1 evolution-alarm-n   14.5M    2.0M    1.9M    4.3M  624.7M   12.6M   12.6M 
   1 plugin_host         14.0M    3.5M    3.4M    4.1M  147.4M   10.5M   10.6M 
   1 conky               13.4M    6.1M    6.1M    7.7M    2.3G    7.3M    7.3M 
   ...

Pozor na to, že i některé procesy spuštěné pod uživatelem mohou mít u smaps souborů jako vlastníka roota a ty se pak ve výpise procesů neobjeví, pokud smem neběží pod rootem. Narazil jsem na to u VirtualBoxu, kde procesy s virtuálním systémem vykazují toto chování, proces patří mně, ale k jeho datům se nedostanu a smem bez práv roota mi proces zamlčí. On ten VBox je vůbec plný nástrah, ještě se k němu vrátím později. Pozor ještě na jednu věc - sice odstraňuji vlastní proces smem při použití přepínače -P, ale pokud smem spustíte přes sudo, zachytí filtr procesů i proces sudo, který bude mít jako argument příkaz spouštějící smem a tudíž bude přesně odpovídat filtru, pokud nepoužijete finty s regulárním výrazem.

Pss/Rss Anon, File, Shmem

Jak jsem zmínil minule, nedávno do kernelu přibyl podrobnější rozpis PSS a RSS počítadel, takže nyní můžeme vidět i to, kolik místa v procesech zabírá anonymní paměť, kolik soubory a kolik sdílená paměť. Přidal jsem do smem i tyto metriky s názvy sloupců pssa, pssf, psss a stejně tak pro rss, mohl jsem si tak třeba ověřit, že obsah Shared v /proc/meminfo u mě odpovídá součtu Pss(Shmem) všech procesů, plus co je v RAM z tmpfs filesystémů.
Takto dostanu pouze tu jednu jedinou hodnotu, která mě zajímá (s přepínačem -H by to bylo i bez záhlaví):

# smem -kTc "psss"
PssShmem
   60.6M

Pss(A/F/S) a Rss(A/F/S) nejsou v jednom souboru, takže se při sekvenčním čtení od sebe posunou v čase, ale mimo to jsou prý RSS výpočty brány spíše jako orientační. Píšu to i z toho důvodu, že na následující ukázce je nejméně v jednom případě RssFile nižší, než PssFile, což by teoreticky nemělo nastat.

# smem -arktbc "pid command tpss pssa rssa pssf rssf psss rsss swappss" -s tpss

  PID Command          TPSS PssAnon RssAnon PssFile RssFile PssShmem RssShmem SwapPss
 3739 snap-store     918.1M  317.7M  317.3M    3.3M  844.0K    16.0K    20.0K  597.1M 
 5104 firefox        739.5M  589.6M  587.7M    5.0M   56.5M    44.7M    66.0M  100.2M 
 7651 sublime_text   713.1M  277.2M  276.6M    5.4M   21.3M    10.2M    20.2M  420.4M 
 5005 firefox        680.1M  530.5M  526.0M    9.7M   60.8M    54.0M   106.9M   85.9M 
67484 gnome-software 711.7M  534.6M  534.3M   17.1M   41.2M    25.4M    26.7M  134.6M
  ...

Všiml jsem si, že u snap-store procesu to není jediná zvláštnost, další je jeho velikost, je v tu chvíli největším procesem v systému, předčí i všechny procesy Firefoxu, a v zádech má gnome-software, který je v podstatě ta samá aplikace, jen s jiným (?) zdrojem dat. Raději se těmto aplikacím vyhnout, asi napíšu zápisek jen o tomto, protože obě aplikace se drží v paměti i po zavření jejich okna a většinou stále bobtnají, takže si toho uživatel ani nemusí všimnout, než mu třeba začne systém stávkovat při swapování. Po restartu procesu se gnome-software nějakou dobu vejde do 100 MiB, než začne opět nabírat:

   PID User Command         TPSS PssAnon RssAnon PssFile RssFile PssShmem RssShmem SwapPss 
920809 gdh  gnome-software 92.0M   44.2M   43.9M   22.1M   50.0M    25.7M    26.9M       0

Celkový náhled systému

# smem -wtkK /boot/vmlinuz -R 8G
    
Parameter '/boot/vmlinuz' should be an original uncompressed compiled kernel file.
Maybe uncompressed kernel can be extracted by the command:
  dd if=/boot/vmlinuz bs=1 skip=16808 | gzip -d >/boot/vmlinuz.unpacked
    
Area                           Used      Cache   Noncache 
firmware/hardware            266.9M          0     266.9M 
kernel image                  33.4M          0      33.4M 
kernel dynamic memory          1.1G     929.1M     239.3M 
userspace memory               5.7G       2.6G       3.2G 
free memory                  839.8M     839.8M          0 
----------------------------------------------------------
                               8.0G       4.3G       3.7G

Výpis obsazení RAM může obsahovat velikost kernelu, pokud k němu zadáte cestu (přepínač -K). Vzhledem k tomu, že distribuční kernely jsou většinou komprimované, což se pozná tak, že se jmenují vmlinuz, zatímco nekomprimované zpravidla vmlinux, není možné odečíst velikost bez jeho dekomprimace. Binární soubor kernelu, který se natahuje při bootu, bývá (překvapivě) v adresáři /boot, soubor nazvaný čistě vmlinuz je symlinkem na aktuální kernel, může tu být pár dalších verzí, v Ubuntu se běžně udržují dva poslední. Zadáte-li cestu ke komprimovanému kernelu, vygeneruje vám smem příkaz, kterým ho můžete rozbalit. Nejde o klasický archiv, musíte v souboru nejprve nalézt začátek samotného archivu (což za vás smem udělá), před kterým je zaváděcí kód, a poslat gzipu zbytek, k čemuž vám bude nabídnut celý hotový příkaz, můžete si jen změnit umístění cílového souboru. Já jsem v ukázce smíchal dva výstupy, tedy poslal jsem smem na komprimovaný kernel kvůli vygenerování příkazu a zbytek jsem dal už s rozbaleným kernelem.

Pomocí přepínače -R můžete zadat fyzickou velikost RAM zkoumaného systému, protože samotný kernel vám nareportuje v /proc/meminfo jako MemTotal pouze to, co mu zbylo po obsazení RAM hardwarem (např. i videoRAM pro integrovanou grafiku), firmwarem a vlastním kódem kernelu plus nějaká jeho rezervačka, u mě typicky zbývá 7,7 z 8 GiB. Smem reportuje i tento rozdíl, pokud zná skutečnou velikost RAM, tedy buď mu ji můžete zmíněným způsobem předat, nebo se můžete spolehnout na autodetekci pomocí dmidecode, kterou jsem pro systémové zobrazení do smem cvičně přidal (ta funguje pouze pod rootem). Nebude ale fungovat třeba ve virtualizovaných systémech, tam není co dekódovat.

Náhled obsazení systému se mi zdál příliš stručný, tak jsem přidal ještě rozšířenou variantu pod přepínač -W, která může pomoct odhalit případné viníky nedostatku RAM. Snažil jsem se podrobněji vyčíslit všechny klíčové oblasti paměti, ale zátím mi stále uniká kolem deseti procent obsahu značeného ve výstupu jako unknown, o kterém nemám tušení, kam patří. Rozhodně nepatří do cache (dropnutí keše s tím nehne) a ani procesům (ty smem umí spočítat po jednom a výsledek souhlasí s výstupem souboru meminfo). Nepatří ani do tmpfs, ramfs, … fakt nevím. Rozšířený výstup zatím vypadá následovně:

# smem -aktWc +details
Area                               Used   Cache Noncache Details 
firmware/hardware                300.3M       0   300.3M       0 
kernel image                          0       0        0       0 
kernel modules                    11.1M       0    11.1M       0 
page tables                       45.2M       0    45.2M       0 
kernel stack                      17.5M       0    17.5M       0 
slab (all/SReclaimable)          223.8M   71.4M   152.4M       0 
buffers                            3.3M    3.3M        0       0 
cached (w/o mapped,tmpfs,ramfs)   98.4M   98.4M        0       0 
shared (non process tmpfs)       121.0K       0   121.0K       0 
ramfs                                 0       0        0       0 
unknown                          474.9M       0   474.9M       0 
processes (all/mapped files)       6.1G  419.5M     5.7G       0 
free memory                      771.1M  771.1M        0       0 
-------------------------------       0       0        0       0 
/dev/zero mapped                      0       0        0    2.1G 
shared by processes                   0       0        0  305.0M 
unevictable                           0       0        0  164.0K 
dirty (unwritten files)               0       0        0    3.1M 
swapped                               0       0        0    2.1G 
available (estimated)                 0       0        0  809.4M 
-----------------------------------------------------------------
                                   8.0G    1.3G     6.7G    5.4G

Pokud si přepínačem -c vyžádáte sloupec details (nebo použijete místo sloupců all), vypíše se, spolu se sloupcem Details, i část pod přerušovanou čarou. Oddělil jsem to takto kvůli celkovému součtu paměti v sloupcích Used Cache Noncache při použití přepínače -t, aby dávaly použitelné hodnoty. Není to extra elegantní, ještě o tom budu přemýšlet, ale funguje to.
Vzal jsem informace z /proc/memInfo, trochu je přepočítal, protože mnoho z nich se navzájem překrývá a doplňuje. Doplnil jsem počítání obsahu ramfs, tedy ramdisků, které se projeví i v položce unevictable, která zahrnuje paměť, kterou z RAM momentálně nelze uvolnit. Sem spadají i procesy zamknuté stránky (v /proc/meminfo jako položka Mlocked:).
Další přidanou položkou je /dev/zero mapped, kterou jsem napsal kvůli VirtualBoxu, když jsem zjistil, že si připravuje paměť pro VM mapováním z /dev/zero a zařazením do Mapped, čímž zkresluje výstup, počítáte-li s tím, že Mapped je podmnožinou Cached. Skutečné využití takto mapované paměti odpovídá anonymnímu využití. Pokud chci vyčíslit paměť procesů zvlášť pro soubory a anonymní paměť, je nezbytné Mapped část o /dev/zero očistit a naopak. Ve výpise smem je Mapped promítnuta do Cache sloupce řádku userspace memory resp. processes (all/mapped files), protože soubory je možno v případě potřeby paměti pro další procesy odkládat na disk.
Z hodnoty dirty (unwritten files) zas například poznáte probíhající zápis větších objemů dat do souborů na disku, například při kopírování, jsou to stránky čekající v cache na zápis.
Následuje vyčíslení aktuálně do swapu odložené paměti swapped a poslední položkou je available (estimated), což je položka MemAvailable z /proc/meminfo, vyčíslující odhad paměti, která může být okamžitě uvolněna pro další proces, bez toho, aby se muselo swapovat.

Smem jako náhrada top mem v Conky

Conky top mem jednak pracuje se jmény procesů, což mi v případě používání Firefoxu fakt vadí, a samozřejmě neumí spočítat dohromady procesy jedné aplikace, takže jsem si zkusil žebříček vyrobit z výstupu nové funkce smem. Použil jsem conky proměnnou excepi pro spouštění příkazu v shellu v intervalech a parsováním jeho výstupu, jako by šlo o zápis kódu pro conky, tedy včetně interpretace vložených proměnných (funkcí). Pro mé conky jsem zkomponoval tento řádek, zvolil jsem žebříček podle TPss, tedy celkové velikosti v paměti, i swapu dohromady:

${execpi 10 smem -grkbHc "command tpss" -s tpss --cmd-width 16|head -5|awk '{print "${goto 165}"$1"${alignr}"$2}'}

Příklad výstupu vloženého příkazu, který následně conky zpracuje:

${goto 165}firefox${alignr}4.5G
${goto 165}VirtualBoxVM${alignr}1.8G
${goto 165}sublime_text${alignr}1.3G
${goto 165}gnome-shell${alignr}494.7M
${goto 165}python3${alignr}187.8M

V příkladu je vidět i VirtualBoxVM, ale v conky běžícím pod běžným uživatelem by vidět nebyl, pokud bych nezapsal výjimku pro smem do sudoers, aby nepotřeboval heslo na sudo a nespouštěl ho z conky se sudo. Z bezpečnostních důvodů je ale záhodno, aby i kód smem byl ve vlastnictví roota, aby nebylo možné mu z uživatelského prostoru měnit bez hesla kód. Takže já jsem si přidal výjimku přes příkaz visudo následující:

gdh     ALL=(root) NOPASSWD:/usr/local/bin/smem

Tady pozor, je třeba to dát na konec, za nastavení skupin %sudoers a %admin, které to jinak přerazí. Takto naopak uděláte skulinku v jejich všeobjímajícím nastavení. 

Aliasy pro jednoduché použití smem v různých režimech

Abych si ušetřil vypisování přepínačů a požadovaných sloupců jsem si do souborů

 /root/.bash_aliases
 ~/.bash_aliases

přidal pár jednoduchých aliasů:

alias mg="smem -arktgbc 'command pids tpss pss swappss uss' -s tpss"
alias mp="smem -arktc 'pid command tpss pss swappss uss' -s tpss"
alias mpp="smem -arktc 'pid command tpss pss swappss uss' -s tpss -P "
alias mm="smem -arktmc 'map pids tpss pss swappss avgpss avguss' -s tpss"
alias mw="smem -aWkt"

Mohu pak napsat např. příkaz:

$ mpp gnome-shell

abych dostall přehled procesů gnome-shell:

 PID Command                                   TPSS     PSS SwapPss     USS 
----------------------------------------------------------------------------
2863 /usr/bin/gnome-shell                    332.8M  332.8M       0  316.0M 
3592 /usr/bin/python3 /usr/bin/chrome-gnome   15.8M   15.8M       0   14.6M 
2975 /usr/bin/gjs /usr/share/gnome-shell/or    8.1M    8.1M       0    5.3M 
2914 /usr/libexec/gnome-shell-calendar-serv    5.0M    5.0M       0    3.4M 
----------------------------------------------------------------------------
   4                                         361.7M  361.7M       0  339.4M 


Závěrem

Nenašel jsem jinou aplikaci, která by uměla procesy prolustrovat podobným způsobem, jako Smem. Což neznamená, že určitě není, ale rozhodně to není běžný standard. Navíc je solidně napsaná a tak se velmi jednoduše doplňuje a vylepšuje. Má verze sice neumí koláče a externí zdroje dat, ale možná je tam opět vrátím, přijde mi to užitečné. Zatím si nejsem jist, co na mé vylepšováky řekne majitel zdroje, který jsem forknul, ale než dám pull request, ještě to trochu doladím. Každopádně budu rád, za konstruktivní kritiku a bug reporty.


Žádné komentáře:

Okomentovat

Zkuste prosím při komentováni používat místo volby Anonymní volbu Název/adresa URL, kde vyplníte nějakou přezdívku, adresu zadávat nemusíte. Vědět, které příspěvky jsou od jednoho člověka, je fajn. Díky.

Pokud by se vám náhodou odeslaný komentář na stránce nezobrazil, vytáhnu ho z koše hned jak si toho všimnu. I Google spam filter se občas sekne.