最近、kosakiという人が「オレはLKMLでもっとも頻繁にOOMバグの解析を行っているデベロッパの一人である。オレが言うんだから間違いない。現在のOOMの表示と/proc/meminfoはフィールドが足りない」と真偽が定かではない主張をして、フィールドを大量に増やすパッチを、ねじ込んだ。

ちなみに、現在の /proc/meminfoはこんな感じ


$ cat /proc/meminfo
MemTotal: 6037184 kB
MemFree: 1229820 kB
Buffers: 252336 kB
Cached: 3673464 kB
SwapCached: 0 kB
Active: 1463432 kB
Inactive: 2772100 kB
Active(anon): 315332 kB
Inactive(anon): 16 kB
Active(file): 1148100 kB
Inactive(file): 2772084 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 10174448 kB
SwapFree: 10174448 kB
Dirty: 1092 kB
Writeback: 0 kB
AnonPages: 309728 kB
Mapped: 75640 kB
Shmem: 5620 kB
Slab: 379376 kB
SReclaimable: 339928 kB
SUnreclaim: 39448 kB
KernelStack: 2392 kB
PageTables: 33848 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 13193040 kB
Committed_AS: 788376 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 46116 kB
VmallocChunk: 34359682980 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 7104 kB
DirectMap2M: 3137536 kB
DirectMap1G: 3145728 kB



んで、せっかくなので、今回増えたShmem(共有メモリとtmpfs上のファイル) とKernelStask(それぞれのプロセスがカーネル内で使うスタック)をmuninの表示に反映させるプラグインを書いてみた。
ソースは以下にアップしてあるので、興味がある人は好きなように使ってもらってかまわない
(ただし、v2.6.32以降でないと利点があまり生かせないと思うが)

http://github.com/kosaki/munin-plugins

なお、標準のmemory usage プラグインとの差分は以下

  • app フィールドの廃止(内部処理として、/proc/meminfoで取得できなかった使途不明メモリをappとして表示していたので意味がなかった)

  • 代わりに anon フィールドを追加
  • slab_cache フィールドを slab(unreclaim) と slab(reclaimable) の2つに分けた
    reclaimableはinode cacheとdentry cacheでその名の通りメモリが逼迫すれば捨ててもかまわないキャッシュ unreclaimはカーネルの内部処理に使っているメモリで破棄不可能。
    この2つはシステム分析上まったく性格が違うメモリなので混在させるべきではない
  • cache フィールドを cache とshmemに分割
    tmpfs上のファイル、および共有メモリは破棄することが出来ず、スワップアウトさせないといけないという所がレギュラーファイルを大きく異なる。普通キャッシュがたくさんあるときは、まだまだスワップしないと思いたいところなので、この2つは混在させるべきではない
  • active と inactive を削除。VMの内部なんかみても何も分析できんよ。2.6.28のSplit LRU VMで意味が大きく変わっているし
  • committed も削除。JavaVMなど、使用メモリ量の数十倍も仮想メモリを予約するソフトがいるので意味のある値は取れない。だいたい普通Web Serverで使うソフトでpreforkアーキテクチャと相性悪い値取ってどうする
  • swapフィールドの表示を(他のメモリのような)色塗りから、(mappedのような)ラインに変更。スワップはメモリではない
  • mlocked フィールドを追加
  • dirty フィールドを追加
  • writeback フィールドを追加
  • 表示順を大きく変更。グラフが下から順に、アプリ系メモリ、カーネル・IO系メモリ、キャッシュ系に並ぶようになった



以下、サンプル画像
12e62339.jpg



ところで、色が気に入らないんだけど、これって変えられないの?

追記: githubの同じディレクトリにmemory_lruというプラグインも入れておいた。これはVM LRUの内訳
・Active(anon)
・Inactive(anon)
・Active(file)
・Inactive(file)
・Unevictable
を表示するもので、mlock()やshmctl(SHM_LOCK)を多用するシステムで威力を発揮する。なぜならMlockedフィールドはanonをmlockしたのかfileをmlockしたのか分からないため、あとどのくらいmlockされていないページがあるのか分からなくなるから。こっちでActive(file) + Inactive(file)を見れば自明。

追記2: memory_ext と memory_lruを統合して、v2 を作った。現在のフィールドは以下

  • anon
    anonymousメモリ。v1と違ってmlockされたページは抜かれていてswap可能なもののみを集計
  • page_tables
  • kernel_stack
  • swap_cache
  • shmem
  • vmalloc_used
  • unevictable
    mlocked の代わりに導入。mlock以外にもshmctl(SHM_LOCK)のようなあらゆるページ固定されたメモリを集計
    また表示がライン表示から積み重ね表示に変更。これを実現するためanonとcacheはページ固定されたメモリは抜くように仕様変更
  • slab_unreclaim
  • slab_reclaimable
  • file_cache_dirty
    キャッシュのうちダーティーなページ
  • file_cache_clean
    キャッシュのうちクリーンなページ。これとfreeを足した量で空きメモリが十分か判断する
  • free
  • swap_used
  • mapped
  • writeback


ポイントは以下

  • bufferフィールドは削除し、file_cacheに統合した。あれはfreeコマンド等古いコマンドがBuffersカラムがなくなると発狂するので表示されているだけで、この2つを分けることによっていかなる分析も出来はしない
  • file_cache_cleanフィールドを実現。"file_cache_clean + free" でシステムの余力を簡単に把握できるようになった
  • Mlock フィールドを Unevictableフィールドに変換。ロックされた量が他と同じように積み重ね表示出来るようになった


画面イメージはこんな感じ
86bc9996.jpg


途中で赤(unevictable)が増えているのは、anonymousメモリを1GBほどmlock()したから。mlockするとanonではなくなってしまうのが奇妙に思う人もいると思うけど

anon: スワップ可能メモリ
cache_clean: 破棄可能メモリ
cache_dirty: writebackが終われば破棄可能メモリ
unevictable: 破棄不可能メモリ

という分類にする事によって、システム高負荷時の挙動を予測しやすくするのが狙い

追記3: 追記2で書いたv2を revert した。すまん、あれバグってる。Unevictableでもdirtyになりうるので、{A|ina}ctive(file) - Dirty は正しくない計算式。これは、さらにもう1つフィールド追加がいるね。絶対反対されそうなので、作戦がいるけど。