SlideShare a Scribd company logo
SLUB
data structures
Masami Ichikawa
@masami256
README
• このスライドは以下の点に絞ってます
• SLUBのデータ構造
• slab cacheの作成
• 下記資料にあるSLUB data structuresを理解する
• http://events.linuxfoundation.org/sites/events/files/
slides/slaballocators.pdf
• memory control groupも絡むのですが、そこは気にしない方
向でコードリーディングしてます
Common variable name
• slub.cでよく使われれる変数名
• このスライドでも単にcと書いている場合はstruct kmem_cache_cpuの変数
を指します
• s
• struct kmem_cacheの変数
• c
• struct kmem_cache_cpuの変数
• n
• struct kmem_cache_nodeの変数
Important variables
• s->cpu_slab
• 現在のcpuに紐づくstruct kmem_cache_cpuへのポインタ
• c->page
• slab objectが使用しているstruct pageへのポインタ
• c->freelist
• リストと名前が付いてるが次の空きslabオブジェクトを指す
Slab allocator
implementations in Linux
• LinuxにおけるSlab allocator実装の一つ
• SLAB
• SunOSのSlab allocatorアルゴリズムに基づく
• SLUB
• 2.6.23からデフォルトのSlab allocatorに
• メモリのフラグメンテーションが発生しにくい
• SLOB
• サイズの小さいallocator
SLUB basis
• SLABにあったfull、partial、emptyといったリストによ
る管理をしていない
• slab objectへはstruct kmem_cache_cpuのfreelist
より参照
• partial listはあるけどSLABとは違う使い方
• Slab cache作成時に似たサイズのスラブがあればマージ
• Cache Coloring無し
SLUB merge
• スラブキャッシュ作成時にすでに同サイズのスラブがあればそこ
にマージ
• slabinfo -aでマージされたSlabを確認可能
• kernel source treeにあるtools/vm/slabinfo.c
:at-0000104 <- sda1 buffer_head
:at-0000320 <- jbd2_transaction_s nfs_direct_cache
:t-0000024 <- scsi_data_buffer numa_policy
:t-0000032 <- sd_ext_cdb dnotify_struct kmalloc-32
:t-0000040 <- khugepaged_mm_slot Acpi-Namespace ext4_system_zone
Cache Coloring
• SLABでは使用している
• SLUBでは実装していない
• Christophさん曰く、これについてはcpuの
キャッシュ設計側で面倒見るべきだろう
• https://lkml.org/lkml/2008/8/4/521
Main structures
• struct kmem_cache
• include/linux/slub_def.h
• slab objectを管理する構造体
• 下記の2つの構造体はkmem_cache構造体のメンバ変数
• struct kmem_cache_cpu
• include/linux/slub_def.h
• slab objectへのアクセスはここから
• struct kmem_cache_node
• mm/slab.h
• NUMAノード毎のslabを指す
• struct page
• freelistへのポインタ、オブジェクト使用数などの変数が追加された
Slab object format
• Slab objetのフォーマットは下図のような形
• Objectとpadding以外はデバッグ機能向け
Slab object - offset
• struct kmem_cacheの変数offset
• 下記の条件に該当する場合、objectの先頭アドレス+offsetバイト目からをslab
objectにする
• slab objectのfree時にRCUを使う
• SLAB_POISONがセットされている
• コンストラクタが指定されている
• offsetは下記のサイズに設定される
• objectのサイズをsizeof(void *)の境界にあうようにalignしたサイズ
• SLAB_REDZONEがセットされている場合はRED ZONEのサイズも足す
struct kmem_cache
struct kmem_cache {
struct kmem_cache_cpu __percpu *cpu_slab;
/* Used for retriving partial slabs etc */
unsigned long flags;
unsigned long min_partial;
int size; /* The size of an object including meta data */
int object_size; /* The size of an object without meta data */
int offset; /* Free pointer offset. */
int cpu_partial; /* Number of per cpu partial objects to keep around
*/
struct kmem_cache_order_objects oo;
∼略∼
struct kmem_cache_node *node[MAX_NUMNODES];
};
Slab Objectの管理
に使う主な変数
struct kmem_cache_cpu
struct kmem_cache_cpu {
void **freelist; /* Pointer to next available object */
unsigned long tid; /* Globally unique transaction id */
struct page *page; /* The slab from which we are allocating */
struct page *partial; /* Partially allocated frozen slabs */
#ifdef CONFIG_SLUB_STATS
unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};
struct kmem_cache_node
struct kmem_cache_node {
spinlock_t list_lock;
∼略∼
#ifdef CONFIG_SLUB
unsigned long nr_partial;
struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
atomic_long_t nr_slabs;
atomic_long_t total_objects;
struct list_head full;
#endif
#endif
debug用途を除くとlistと個
数を保持する変数だけ
struct page
struct {
union {
pgoff_t index; /* Our offset within mapping. */
void *freelist; /* sl[aou]b first free object */
∼略∼
}
union {
∼略∼
/* Used for cmpxchg_double in slub */
unsigned long counters;
∼略∼
struct {
union {
∼略
struct { /* SLUB */
unsigned inuse:16;
unsigned objects:15;
unsigned frozen:1;
};
Slab data relation
• 現在のcpuで使用しているslabへのアクセス
• cよりアクセス
• c->freelist、c->pageなど
• s->cpu_slabから外されたslab
• s->node[node number]からアクセス
Slub data structure
Create a slab
• slabの作成はkmem_cache_create()
• KMEM_CACHE(__struct, __flags) マクロもある
• kmem_cache_create()の時点ではslab objectsの作成はしない
• freelistの作成、slab objectの初期化などはkmem_cache_alloc()実行時
• 処理は2段階
• 最初にstruct kmem_cacheのオブジェクトを取得
• 次に取得したsの変数を設定
struct kmem_cache *
kmem_cache_create(const char *name, size_t size,size_t align,
unsigned long flags, void (*ctor)(void *))
slab creating flow
kmem_cache_create()
̶> __kmem_cache_alias()
̶> do_kmem_cache_create()
̶> kmem_cache_zalloc()
̶> __kmem_cache_create()
̶> kmem_cache_open()
̶> calucalate_sizes()
̶> init_kmem_cache_nodes()
̶> alloc_kmem_cache_cpus()
主なところ
kmem_cache_create()
• kmem_cache構造体のオブジェクトを取得して返す
• 作成しようとしたslabがマージ可能かチェック
• マージ可能ならslabオブジェクトの作成せずに終了
• do_kmem_cache_create()でkmem_cache構造体の
オブジェクト(s)を取得
__kmem_cache_alias()
• 作成しようとしているslabがマージ可能か
チェック
• 実際にチェックするのはfind_mergeable()
• マージ可能ならマージ先のsを返す
do_kmem_cache_create()
• kmem_cache_zalloc()でstruct kmem_cache構造体のオブジェクトを取得
• kmem_cache構造体はslubで管理されている
• これを管理しているオブジェクトはkmem_cache
• kernelの初期化時にkmem_cache_init()にて設定
• sの変数を一部設定
• __kmem_cache_create()でsの設定
• slab_cachesリストにsをつなぐ
• 全kmem_cache構造体をつないでいるリスト
kmem_cache_zalloc()
• __GFP_ZEROをフラグに設定してkmem_cache_alloc()
を呼ぶだけ
• kmem_cache_alloc()はslab_alloc()のラッパー的なもの
• slab_alloc()はslab_alloc_node()へのラッパー
• 大雑把にいうとstruct kmem_cache構造体のインスタン
スを取得して返す
• しかし、この処理が肝なので後のスライドで説明します
__kmem_cache_create()
• kmem_cache_open()でsの初期化
• sysfsでオブジェクトが見えるように設定
[root@miko slab]# ls -al /sys/kernel/slab/
total 0
drwxr-xr-x 108 root root 0 Dec 14 01:54 .
drwxr-xr-x 9 root root 0 Dec 14 01:54 ..
lrwxrwxrwx 1 root root 0 Dec 13 18:29 Acpi-Namespace -> :t-0000040
lrwxrwxrwx 1 root root 0 Dec 13 18:29 Acpi-Operand -> :t-0000072
lrwxrwxrwx 1 root root 0 Dec 13 18:29 Acpi-Parse -> :t-0000048
lrwxrwxrwx 1 root root 0 Dec 13 18:29 Acpi-ParseExt -> :t-0000072
lrwxrwxrwx 1 root root 0 Dec 13 18:29 Acpi-State -> :t-0000080
drwxr-xr-x 3 root root 0 Dec 14 01:54 anon_vma
lrwxrwxrwx 1 root root 0 Dec 13 18:29 anon_vma_chain -> :t-0000064
drwxr-xr-x 3 root root 0 Dec 14 01:54 :at-0000016
symlinkがalias
(mergeされたもの)
kmem_cache_open()
• calucalate_sizes()でslab objectのサイズに関
する変数を設定
• kmem_cache_node構造体の初期化
• percpuな kmem_cache_cpu構造体の初期化
calucalate_sizes()
• slab objectのサイズ周りの変数を設定
• s->size、 s->offset、s->reserved
• debugオプション等によってオブジェクトの
大きさが変わる
• 他に、allocationのフラグ、メモリ確保に使用
するオーダーの設定もする
init_kmem_cache_nodes()
• kmem_cache_alloc_node()でstruct
kmem_cache_nodeオブジェクトの取得
• slubで管理されている
• 管理しているのはkmem_cache_node
• init_kmem_cache_node()でstruct
kmem_cache_nodeの初期化
• リストの初期化等
alloc_kmem_cache_cpus()
• s->cpu_slabオブジェクトの設定
• __alloc_percpu()を使う
• init_kmem_cache_cpu()でslubで使うトランザ
クションIDの設定
/*
* The transaction ids are globally unique per cpu and per operation on
* a per cpu queue. Thus they can be guarantee that the cmpxchg_double
* occurs on the right processor and that there was no operation on the
* linked list in between.
*/
setup freelist
• kmem_cache_alloc()実行時に行う
• freelist用のpage取得
• slab objectsの初期化
• __slab_alloc()にて以下に該当する場合にsetupする
• c->page == NULL or c->freelist == NULL
setup flow
__slab_alloc()
̶> new_slab_objects()
̶> new_slab()
̶> allocate_slab()
̶> alloc_slab_page()
̶> alloc_pages() or alloc_pages_exact_node()
̶> setup_object()
̶> set_freepointer()
主なもの
__slab_alloc()
• c->page、c->freelistがNULLかチェックし、
NULLの場合にnew_slab_objects()を呼ぶ
• pageを確保出来たらc->freelist、c->tidを設定
• freelistが最初の未使用slab objectを指す
• get_freepointer()で設定
new_slab_objects()
• get_partial()で他のノードにfreelistがあるかチェック
• 見つかればそれを返す(過去にsetup済みなので)
• new_slab()でpageの確保
• sよりcを取得し、cがNULLでない場合はcpu_slabを入れ替えるため下記を実行
• deactivate_slab()でslabをpartialリストにつなぐ
• cのデータを初期化する
• c->page = c->freelist = NULL等
• page->freelistを戻り値の変数freelistに代入し、page->freelistはNULLに
• c->pageを確保したpageに置き換え
new_slab()
• alloca_slab()でfreelist用のpageを確保
• slab objectを初期化
for_each_object_idx(p, idx, s, start, page->objects) {
setup_object(s, page, p);
if (likely(idx < page->objects))
set_freepointer(s, p, p + s->size);
else
set_freepointer(s, p, NULL);
}
for_each_object_idxマクロの終了条件はidx <= page->objects
allocate_slab()
• allocate_slab_page()でpageを確保するのが仕事
• s->ooで指定されているorderでpageを確保を試
みる
• もし失敗した場合はs->minに設定されている最
小サイズでpage確保をリトライ
• これでも失敗したらNULLを返す
alloc_slab_page()
• 実際にpage確保の関数を呼ぶのが個々
• NUMAノードの指定有無で呼ぶ関数が変わる
• node == NUMA_NO_NODE(ノード不問)
• alloc_pages()
• node != NUMA_NO_NODE
• alloc_pages_exact_node()
setup_object()
• setup_object_debug()でデバッグ用のオブジェ
クト設定
• POISON、RED ZONE、Tracking
• s->ctorが設定されていればコンストラクタ関数
の呼び出し
set_freepointer()
• object + s->offsetのところに次のobjectのアドレス
を設定
static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
*(void **)(object + s->offset) = fp;
}
for_each_object_idx(p, idx, s, start, page->objects) {
setup_object(s, page, p);
if (likely(idx < page->objects))
set_freepointer(s, p, p + s->size);
else
set_freepointer(s, p, NULL);
}
Slab object format
• setup_object()、set_freepointer()で1slab
objectが以下のような形に
参考資料
• Slab allocators in the Linux Kernel: SLAB, SLOB, SLUB
• http://events.linuxfoundation.org/sites/events/files/
slides/slaballocators.pdf
• Linux Kernel Watch番外編 Linuxメモリ管理の最先端を探
る
• http://www.atmarkit.co.jp/flinux/rensai/watch2008/
watchmema.html

More Related Content

PDF
Slub alloc and free
PDF
SystemV IPC
PDF
Minix smp
PDF
Kernel fcache-bug
PDF
デバドラを書いてみよう!
PDF
社内勉強会資料(Varnish Module)
PPT
HandlerSocket plugin for MySQL
PDF
Nodejuku01 ohtsu
Slub alloc and free
SystemV IPC
Minix smp
Kernel fcache-bug
デバドラを書いてみよう!
社内勉強会資料(Varnish Module)
HandlerSocket plugin for MySQL
Nodejuku01 ohtsu

What's hot (20)

PDF
C/C++プログラマのための開発ツール
PDF
VarnishではじめるESI
PDF
Memory sanitizer
PDF
片手間MySQLチューニング戦略
PDF
Node-v0.12の新機能について
PDF
Lisp Tutorial for Pythonista : Day 4
PPTX
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
PPTX
Stream2の基本
PDF
JVM-Reading-ConcurrentMarkSweep
PDF
仮想記憶入門 BSD-4.3を例題に
PDF
x86とコンテキストスイッチ
PDF
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
PDF
Openresty
PDF
WDD2012_SC-004
PDF
Nuxt.js + microCMS + netlify
PDF
毎秒2000Requestを捌くPerl製CMSの内部構造(Debianサーバ1台にて)
PPT
Glibc malloc internal
PDF
effective modern c++ chapeter36
PPTX
前期講座09
PDF
ゆるバグ
C/C++プログラマのための開発ツール
VarnishではじめるESI
Memory sanitizer
片手間MySQLチューニング戦略
Node-v0.12の新機能について
Lisp Tutorial for Pythonista : Day 4
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
Stream2の基本
JVM-Reading-ConcurrentMarkSweep
仮想記憶入門 BSD-4.3を例題に
x86とコンテキストスイッチ
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
Openresty
WDD2012_SC-004
Nuxt.js + microCMS + netlify
毎秒2000Requestを捌くPerl製CMSの内部構造(Debianサーバ1台にて)
Glibc malloc internal
effective modern c++ chapeter36
前期講座09
ゆるバグ
Ad

Slub data structure