/proc/slabinfo
Rev.1を表示中。最新版はこちら。
/proc/slabinfoはスラブの状態を表示してくれます。その処理はmm/slab.cのs_show関数で行われます。for_each_online_node(node)でループしているのは、NUMシステムを考慮してのことです。X86では0です。l3 = cachep->nodelists[node]でスラブを登録しているリストを取得します。このリストに全て未使用/一部使用/全て使用のスラブがリスト登録されています。
list_for_each_entryで、まず全て使用のスラブリストl3->slabs_fullを調べます。cachep->numは1スラブ内のオブジェクトの数で、slabp->inuseは使用中(実際kmallocで割り当てられているというのでなく、貸し出し用にプールしている配列に登録されていると言う事。)で、全て使用のスラブリスト故に、if (slabp->inuse != cachep->num && !error)ならprintkでその旨エラーメッセージを出すようにします。
active_objs += cachep->numで使用中オブジェクトを加算し、active_slabs++で使用中スラブをインクリメントします。
次のlist_for_each_entryは、部分使用としてのl3->slabs_partialの処理です。 部分使用しているはずだけにif (slabp->inuse == cachep->num && !error)ならエラー表示です。また!slabp->inuseまったく使用してないことになるため、これもエラー表示です。
active_objs += slabp->inuseで実際に使用中の分をactive_objsに加算します。active_slabs++をインクリメントしています。このことからactive_slabsはスラブ内の一部でもそのオブジェクトが使われているなら、active_slabsとなるようです。
最後のlist_for_each_entryは全く未使用のl3->slabs_freeの処理です。slabp->inuseは0であるはずです。使用/未使用のスラブ総数となるnum_slabsをインクリメントしています。
3つのスラブリストの処理が終わると、num_slabs += active_slabsで使用中スラブを足しこんで総スラブ数をセットし、num_objs = num_slabs * cachep->numでnum_objs にオブジェクトの総数をセットします。
あとは、seq_printfで各情報を表示するだけです。
static int s_show(struct seq_file *m, void *p) { struct kmem_cache *cachep = list_entry(p, struct kmem_cache, next); struct slab *slabp; unsigned long active_objs; unsigned long num_objs; unsigned long active_slabs = 0; unsigned long num_slabs, free_objects = 0, shared_avail = 0; const char *name; char *error = NULL; int node; struct kmem_list3 *l3; active_objs = 0; num_slabs = 0; for_each_online_node(node) { l3 = cachep->nodelists[node]; if (!l3) continue; check_irq_on(); spin_lock_irq(&l3->list_lock); list_for_each_entry(slabp, &l3->slabs_full, list) { if (slabp->inuse != cachep->num && !error) error = "slabs_full accounting error"; active_objs += cachep->num; active_slabs++; } list_for_each_entry(slabp, &l3->slabs_partial, list) { if (slabp->inuse == cachep->num && !error) error = "slabs_partial inuse accounting error"; if (!slabp->inuse && !error) error = "slabs_partial/inuse accounting error"; active_objs += slabp->inuse; active_slabs++; } list_for_each_entry(slabp, &l3->slabs_free, list) { if (slabp->inuse && !error) error = "slabs_free/inuse accounting error"; num_slabs++; } free_objects += l3->free_objects; if (l3->shared) shared_avail += l3->shared->avail; spin_unlock_irq(&l3->list_lock); } num_slabs += active_slabs; num_objs = num_slabs * cachep->num; if (num_objs - active_objs != free_objects && !error) error = "free_objects accounting error"; name = cachep->name; if (error) printk(KERN_ERR "slab: cache %s error: %s\n", name, error); seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", name, active_objs, num_objs, cachep->buffer_size, cachep->num, (1 << cachep->gfporder)); seq_printf(m, " : tunables %4u %4u %4u", cachep->limit, cachep->batchcount, cachep->shared); seq_printf(m, " : slabdata %6lu %6lu %6lu", active_slabs, num_slabs, shared_avail); seq_putc(m, '\n'); return 0; }
name | スラブ名 |
active_objs | 貸し出しオブジェクト総数 |
num_objs | 全オブジェクトの総数 |
cachep->buffer_size | 1オブジェクトのサイズ |
cachep->num | 1スラブ内のオブジェクト数 |
(1 << cachep->gfporder) | 1スラブのページ数(2を基底としている) |
cachep->limit | 貸し出しプール配列サイズ |
cachep->batchcount | 貸し代プール配列に設定する単位 |
cachep->shared | 補助貸し出しプール配列サイズ(cachep->shared×cachep->batchcountがサイズ(たぶん) |
active_slabs | 一部でも使用しているスラブ総数 |
num_slabs | 全スラブ総数 |
shared_avail | 補助貸し出しプール配列の空き数 |
なお、#if STATSでコンパイルした場合、スラブ獲得処理における統計情報も表示されるようになっています。