radix-tree(基数ツリー)


Rev.1を表示中。最新版はこちら

radix-treeは基数ツリーというそうで、アドレス空間内のページを効率よく検索するためのツリーである。構造はext2/ext3のような間接ブロックの考え方で、その階層を動的に変化させるということだが、ノードの追加とかノードのtagメンバーの取り扱いなどよく考えられている。

#ifdef __KERNEL__
#define RADIX_TREE_MAP_SHIFT    (CONFIG_BASE_SMALL ? 4 : 6)
#else
#define RADIX_TREE_MAP_SHIFT    3       /* For more stressful testing */
#endif
#define RADIX_TREE_MAP_SIZE     (1UL << RADIX_TREE_MAP_SHIFT)

struct radix_tree_root {
       unsigned int            height;
       gfp_t                   gfp_mask;
       struct radix_tree_node  *rnode;
};

struct radix_tree_node {
       unsigned int    height;         /* Height from the bottom */
       unsigned int    count;
       struct rcu_head rcu_head;
       void            *slots[RADIX_TREE_MAP_SIZE];
       unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
};
radix-treeはrootをトップとするradix_tree_node構造体をノードとして階層構造を作成する。heightはそのノードの階層レベルを表し、最下位位階層を1として、上位階層に従って1づつ大きくなっていく。rootは0となる。*slotsは実データないし下位ノードが設定される。1ノードあたりのスロット数はRADIX_TREE_MAP_SIZEで通常は64となる。

ノードツリーはキーとなる32ビットインデックの下位から6ビットずつを割り当てる。(最上位は2ビット)従って最大階層は6階層となり、スロット数との関係は以下のようになる。ただし6階層ではインデックスは2ビットとなるため、すべてを使うわけでない。

階層 スロット数
0 1 1
1 64 64
2 64*64 4096
3 64*64*64 262144
4 64*64*64*64 16252928
5 64*64*64*64*64 1073741823
6 64*64*64*64*64*64 66571993088

下記は上記の内容を検証するためのものである。rootを静的変数radix_treeとして定義し、radix_tree_insert関数でmy_objectを登録し、このときの階層値を確認するものである。インデックスが0のときrootの*rnodeに繋がれている。そしてインデックスが1から63までは階層1、64から4095は階層2となっていくことが確認できる。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/radix-tree.h>

MODULE_LICENSE("GPL");

struct radix_tree_root radix_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN);
struct my_object {
    char data[10];
};
struct my_object *myobj;

static int mod_init(void)
{
   int error, i;
   struct my_object    *p;

   error = radix_tree_preload(__GFP_NOWARN);
   if (!error) {
       for (i = 0; i < 4097; i++) {
           myobj = kmalloc(sizeof(struct my_object), GFP_KERNEL);
           sprintf(myobj->data, "%d", i);
           error = radix_tree_insert(&radix_tree, i, myobj);
           printk("insert:%d:%s\n", radix_tree.height, myobj->data);
       }
       radix_tree_preload_end();
       if (!error) {
           for (i = 0; i < 4097; i++) {
               p = radix_tree_lookup(&radix_tree, i);
               printk("look:%s\n", p->data);
           }
       }
   }
   return error;
}

static void mod_exit(void)
{
   int i;
   struct my_object    *p;

   for (i = 0; i < 4097; i++) {
       p = radix_tree_lookup(&radix_tree, i);
       kfree(p);
   }
}

module_init(mod_init);
module_exit(mod_exit);

[root@localhost test]# dmesg
insert:0:0
insert:1:1
insert:1:2
 :
 :
insert:1:62
insert:1:63
insert:2:64
insert:2:65
 :
 :
insert:2:4094
insert:2:4095
insert:3:4096
look:0
look:1
 :
 :
look:4095
look:4096

radix_tree_insert関数は引数のインデックスでrootから対応するノードを辿ってスロットは見つけるわけだが、見つからなければradix_tree_extend関数で新規ノードを割り当てる。このノードはroot配下に割り付ける。そして以下のノードのheightを1インクリメントする。そしてradix_tree_insert関数へ戻ると、目的とするデータのインデックスに応じた必要とする階層ノードを作成しながら、そのツリー下に該当するノードを作成する。

radix_tree_node構造体にtagsメンバーは、汚れているページ検索の効率化を図っている。汚れているページを有しているツリーノードのtagsメンバーにその旨の情報を設定することで、そうでないノードは検索する必要がなくなる。

補足
radix_tree_preload関数はカーネルプリエンプションを禁止し、64GBまでの登録処理を保障するものらしい。

最終更新 2010/05/26 19:16:37 - north
(2010/05/26 19:16:37 作成)


検索

アクセス数
3023137
最近のコメント
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
Adsense
広告情報が設定されていません。