カーネルのクイックリスト

カーネルは、ページフレームを割り当てて解放するときに多くのことを行う必要があり、これにより多くのクロックサイクルが消費されます。このため、解放するページをリンクリストからキャッシュできます。つまり、実際には解放しませんが、リンクリストでは、次にページが割り当てられるときに、リンクリストから直接取得されるため、ページフレームの解放と割り当ての作業負荷が大幅に軽減され、パフォーマンスが向上します。カーネルには、このようなリンクリスト(CPUごとの変数であるクイックリスト)があります。各CPUは、構造体クイックリストタイプの構造変数に対応します。キャッシュページフレームの管理は、この構造によって実現されます。構造体クイックリストの定義は次のとおりです。

struct quicklist {
    void *page;
    int nr_pages;
};

最初は、この構造体の操作を見ると少し混乱するかもしれませんが、なぜこのリンクリスト構造体に次のポインタがないのですか?次のポインタがページフレームの先頭に書き込まれていることがわかります。これは、スペースを節約するために行うことができます。
1)最初にページフレームのリリース操作を確認します

static inline void __quicklist_free(int nr, void (*dtor)(void *), void *p,
    struct page *page)
{
    struct quicklist *q;

    q = &get_cpu_var(quicklist)[nr];
    *(void **)p = q->page;
    q->page = p;
    q->nr_pages++;
    put_cpu_var(quicklist);
}

最初の呼び出しでは、q-> pageの値はNULLです。この関数が複数回呼び出されると、次のリンクリストが形成されます。

2)ページフレームの割り当てコードを上図と組み合わせると、ページフレームが割り当てられると、前回リンクリストに追加されたノードがスタック:

static inline void *quicklist_alloc(int nr, gfp_t flags, void (*ctor)(void *))
{     
    struct quicklist *q;
    void **p = NULL;
      
    q =&get_cpu_var(quicklist)[nr];
    p = q->page;
    if (likely(p)) {
        q->page = p[0];
        p[0] = NULL;
        q->nr_pages--;
    } 
    put_cpu_var(quicklist);
    if (likely(p))
        return p;
      
    p = (void *)__get_free_page(flags | __GFP_ZERO);
    if (ctor && p)
        ctor(p);
    return p;
}

 

おすすめ

転載: blog.csdn.net/choumin/article/details/114544690