バディシステム


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

バディシステムとは、バディ(仲間)という命名から、メモリー管理をある種の仲間で管理しようと言うものです。メモリーの仲間とは、物理的に連続するページです。1,2,4,8,16・・・という具合に、2を基底とする数の塊(実装する上で、この事が重要になってきます。)で管理すると言うものです。ただこれだけですが、バディシステムと言う名が有名になったのは、その考え方というより、その実装故でないかと、ソースを見て、プログラミングした人(結果的に設計も含めて)「すごいな〜。」という思いです。

バディシステム空のページ取得は__rmqueue関数で行います。__rmqueue_smallest関数で取得し、できなければ__rmqueue_fallback関数から取得するようになっています。なんか同一オーダのブロックリストにカテゴリを設けており、その中からカテゴリーIDとしてmigratetypeで、指定してブロックを取得しているようです。__rmqueue_fallback関数では__rmqueue_smallest関数で取得できなかった場合、別のカテゴリーから取得するみたいです。取得に関しては__rmqueue_smallest関数と同じようです。
(このmigratetypeのカテゴリーが、システム的にどのような意味をもつのかよく分かりません。たぶんzoneでカテゴリを持たしているような意味合いではと・・・)

取得ページ数を指定するのにオーダという形で指定します。オーダは、1ページ取得なら2^0=1,2ページなら2^1,4ページなら2^2と言う具合に、取得ページ数の基底2の指数部となります。
static struct page *__rmqueue(struct zone *zone, unsigned int order,
                                               int migratetype)
{
       struct page *page;

       page = __rmqueue_smallest(zone, order, migratetype);

       if (unlikely(!page))
               page = __rmqueue_fallback(zone, order, migratetype);

       return page;
}
取得ブロックオーダ(order)から、MAX_ORDERまでforループで取得します。zone->free_area[current_order]は、指定したオーダのブロックフリーリストです。そのリストが空でないかlist_emptyマクロでチェックします。空だと上位のオーダからの取得になります。migratetypeは、同じオーダのブロックをある種のカテゴリーに分けているようで、取得順序をカテゴリーで行っているようですが、その意味するところはよく分かりません。

ブロックリストは、list_headとするはarea->free_list[migratetype]に、page->lruを項目としてリストしています。目的とするブロックリストが空でないなら、list_entryマクロで先頭ページのページディスクリプタを取得できるわけです。

そしてlist_delマクロで、そのページをブロックリストから削除し、rmv_page_order関数でpage->private=0としています。(バディーシステムで管理されているページは、page->privateに管理リストのオーダがセットするようです。)

そのブロックオーダのリストは、1ブロックなくなり(area->nr_free--)、そして消費したページ数 1UL << orderです。従って__mod_zone_page_state関数で、フリーページ数をzone->vm_stat[NR_FREE_PAGES] -= (1UL << order)で更新しています。

そしてexpand関数をコールします。この関数がバディシステムの味噌となります。上位のオーダから取得した場合、残りのブロックを下位のオーダに繋ぎかえる処理を行います。指定したオーダから取得できた場合何もしません。

static struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
                                               int migratetype)
{
       unsigned int current_order;
       struct free_area * area;
       struct page *page;

       for (current_order = order; current_order < MAX_ORDER; ++current_order) {
               area = &(zone->free_area[current_order]);
               if (list_empty(&area->free_list[migratetype]))
                       continue;

               page = list_entry(area->free_list[migratetype].next,
                                                       struct page, lru);
               list_del(&page->lru);
               rmv_page_order(page);
               area->nr_free--;
               __mod_zone_page_state(zone, NR_FREE_PAGES, - (1UL << order));
               expand(zone, page, order, current_order, area, migratetype);
               return page;
       }

       return NULL;
}
引数のlowは取得したいオーダで、highは結果的に取得したオーダです。size = 1 << highは取得したページ数です。high > lowの時、下位オーダに繋ぎかえる必要があります。whileループで回しているのは、取得オーダが直上でなく、その上のオーダから取得した場合もありうるからです。(オーダ2でオーダ4から取得した場合)

引数はareaは、取得したブロックリストです。area--でその下位のオーダのリストとなります。size >>= 1でつなぎかえるページ数となります。上位から取得したブロック数はかならず1つで、しかもその半分です。ここが2を基底とする個数でリストしている所以です。

page[size].lruは取得された片割れの先頭ページです。それをlist_addマクロでリスト登録し、set_page_order関数でpage=>privateに管理オーダをセットしています。上位上位のオーダから取得しても、2を基底とするリスト構造のためsize >>= 1するだけで、問題なく処理できるという実装にただただ関心させられました。
static inline void expand(struct zone *zone, struct page *page,
       int low, int high, struct free_area *area,
       int migratetype)
{
       unsigned long size = 1 << high;

       while (high > low) {
               area--;
               high--;
               size >>= 1;
               VM_BUG_ON(bad_range(zone, &page[size]));
               list_add(&page[size].lru, &area->free_list[migratetype]);
               area->nr_free++;
               set_page_order(&page[size], high);
       }
}
ブロックの解放についても同じことが言えます(と思います)。できるだけ連続するブロックを構築して、そのリストに繋ぐ処理が行う必要があり、解放したブロックが下位のブロックと連続となるかの判断も入ってきて、取得の処理よりは複雑になりそうだとは認識していますが・・・。



最終更新 2010/12/03 18:08:07 - north
(2010/12/03 18:08:07 作成)


検索

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