Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1029027
  • 博文数量: 123
  • 博客积分: 5051
  • 博客等级: 大校
  • 技术积分: 1356
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-14 10:56
文章分类
文章存档

2012年(1)

2011年(21)

2010年(13)

2009年(55)

2008年(33)

分类: LINUX

2009-07-17 10:04:40

/*
    下面的测试数据是在linux 2.6.16.36中进行的,这个版本没有支持slub
    cache_cache是对所有cache描述符的管理
*/
/*
 * Initialisation.  Called after the page allocator have been initialised and
 * before smp_init().
   初始化操作,在页分配初始化后,smp_init()之前被调用
 */
void __init kmem_cache_init(void)
{
    size_t left_over;
    struct cache_sizes *sizes;
    struct cache_names *names;
    int i;
    int order;
    int node;

    if (num_possible_nodes() == 1) {    //num_possible_nodes() = 1
        use_alien_caches = 0;
        numa_platform = 0;
    }

    for (i = 0; i < NUM_INIT_LISTS; i++) {    //NUM_INIT_LISTS = 3
        kmem_list3_init(&initkmem_list3[i]);
        if (i < MAX_NUMNODES)
            cache_cache.nodelists[i] = NULL;    //初始化当前CPU对应的kmem_list3为空
    }

    /*
     * Fragmentation resistance on low memory - only use bigger
     * page orders on machines with more than 32MB of memory.
     * the value of num_physpages is 32752
     */
    
    if (num_physpages > (32 << 20) >> PAGE_SHIFT)
        slab_break_gfp_order = BREAK_GFP_ORDER_HI;
        /*
            slab_break_gfp_order = 1;
        */

    /* Bootstrap is tricky, because several objects are allocated
     * from caches that do not exist yet:
     * 1) initialize the cache_cache cache: it contains the struct
     *    kmem_cache structures of all caches, except cache_cache itself:
     *    cache_cache is statically allocated.
     *    Initially an __init data area is used for the head array and the
     *    kmem_list3 structures, it's replaced with a kmalloc allocated
     *    array at the end of the bootstrap.
     * 2) Create the first kmalloc cache.
     *    The struct kmem_cache for the new cache is allocated normally.
     *    An __init data area is used for the head array.
     * 3) Create the remaining kmalloc caches, with minimally sized
     *    head arrays.
     * 4) Replace the __init data head arrays for cache_cache and the first
     *    kmalloc cache with kmalloc allocated arrays.
     * 5) Replace the __init data for kmem_list3 for cache_cache and
     *    the other cache's with kmalloc allocated memory.
     * 6) Resize the head arrays of the kmalloc caches to their final sizes.
     */

    node = numa_node_id();

    /* 1) create the cache_cache */
    /*
        创建cache_cache
        初始化cache_chain,即cache链
        
        INIT_LIST_HEAD(&cache_chain);
    */
    /*
        将cache_cache作为cache_chain的头节点
    */
    list_add(&cache_cache.next, &cache_chain);
    
    /*
        设置cache_cache 中slab的基本对齐偏移
    */
    /*
        在调试过程中,cache_line_size()的值为32
    */
    cache_cache.colour_off = cache_line_size();
    
    /*
        初始化cache_cache空闲对象的本地高速缓存所对应的描述符
    */
    cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
    //
    cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];

    /*
     * struct kmem_cache size depends on nr_node_ids(1), which
     * can be less than MAX_NUMNODES.
     */
     /*
         计算kmem_cache结构体的缓存大小,cache_cache.buffer_size = 80;
     */
    cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
                 nr_node_ids * sizeof(struct kmem_list3 *);
#if DEBUG
    cache_cache.obj_size = cache_cache.buffer_size;
#endif
    /*
        设置对齐数值,减少刷新次数,cache_cache.buffer_size = 96.
    */
    cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
                    cache_line_size());
    /*
        #define    ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a) - 1);
    */
    cache_cache.reciprocal_buffer_size =
        reciprocal_value(cache_cache.buffer_size);

    /*
        设置缓存大小以及slab内未使用的字节,实际上,这里是创建第一个slab描述符,并
        设计了分配第一个页框
    */
    for (order = 0; order < MAX_ORDER; order++) {
    /*
        这里详细解释cache_estimate(unsigned long gfporder,size_t buffer_size,
        size_t align,int flags,size_t *left_over,unsigned int *num)    
        这个函数是用来计算slab所包含的对象的数量以及left-over(即空闲区域),作为初始化
        函数,这里的sizeof(struct kmem_cache),所以值order = 0.
    */
        cache_estimate(order, cache_cache.buffer_size,
            cache_line_size(), 0, &left_over, &cache_cache.num);
        /*
            cache_cache.num = 40,left_over = 64;
        */
        if (cache_cache.num)
            break;
    }
    BUG_ON(!cache_cache.num);
    
    /*
        设置cache_cache中第一个单独slab中包含的连续页框数目的对数,这里的值为0
    */
    cache_cache.gfporder = order;
    
    /*
        确定cache_cache中可用颜色的个数,根据以上的计算,得到的值为2
        这里注意的一点是:“着色”其实是用来再细分slab,本质上是将slab中的一些空闲区
        域从末尾移动到开始处.这样可能会使内核从微处理器的硬件高速缓存中获得最好性能.
        为什么?
    */
    cache_cache.colour = left_over / cache_cache.colour_off;
    
    /*
        设置slab描述符以及对象描述符的大小,这里的值为192,
        cache_cache.num(对象的数量),kmem_bufctl_t(对象描述符),slab(slab描述符)
        cache_cache.num = 40,sizeof(struct kmem_bufctl_t) = 4
        sizeof(strict slab) = 28,三者之和为188,以32对齐,得到192
        
    */
    cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
                      sizeof(struct slab), cache_line_size());

    /* 2+3) create the kmalloc caches */
    /*
        下面调用kmem_cache_create来创建cache
    */
    sizes = malloc_sizes;
    
    /*
    $36 = {{name = 0xc031c9e0 "size-32", name_dma = 0xc031c9e8 "size-32(DMA)"}, {
    name = 0xc031c9f5 "size-64", name_dma = 0xc031c9fd "size-64(DMA)"}, {
    name = 0xc031ca0a "size-128", name_dma = 0xc031ca13 "size-128(DMA)"}, {
    name = 0xc031ca21 "size-192", name_dma = 0xc031ca2a "size-192(DMA)"}, {
    name = 0xc031ca38 "size-256", name_dma = 0xc031ca41 "size-256(DMA)"}, {
    name = 0xc031ca4f "size-512", name_dma = 0xc031ca58 "size-512(DMA)"}, {
    name = 0xc031ca66 "size-1024", name_dma = 0xc031ca70 "size-1024(DMA)"}, {
    name = 0xc031ca7f "size-2048", name_dma = 0xc031ca89 "size-2048(DMA)"}, {
    name = 0xc031ca98 "size-4096", name_dma = 0xc031caa2 "size-4096(DMA)"}, {
    name = 0xc031cab1 "size-8192", name_dma = 0xc031cabb "size-8192(DMA)"}, {
    name = 0xc031caca "size-16384", name_dma = 0xc031cad5 "size-16384(DMA)"}, {
    name = 0xc031cae5 "size-32768", name_dma = 0xc031caf0 "size-32768(DMA)"}, {
    name = 0xc031cb00 "size-65536", name_dma = 0xc031cb0b "size-65536(DMA)"}, {
    name = 0xc031cb1b "size-131072",
    name_dma = 0xc031cb27 "size-131072(DMA)"}, {name = 0x0, name_dma = 0x0}}

    */
    names = cache_names;

    /*
        首先为cache数组以及kmem_list3结构体提供内存,这是通过初始化caches,如果没
        有这个初始数据,那么后面的分配工作将会出现bug
     */

    /*    
        kmem_cache_create创建一个高速缓存cache;
        
        struct kmem_cache *kmem_cache_create(const char *name,size_t size,
        size_t align,    unsigned long flags,void (*ctor)(void *,struct kmem_cache
         *,unsigned long))
        name:用于/proc/slabinfo文件中来识别这个cache
        size:在对应的cache中所创建的对象的长度
        align:对象对齐尺寸
        flags:SLAB标志
        ctor:构造函数
        kmem_cache_create()创建成功返回一个指针ptr,失败返回NULL,当新的页框被
        cache分配时执行ctor构造函数
        name在cache销毁之前必须是合法的,
        flags:这个变量取值有SLAB_POISON,SLAB_RED_ZONE,SLAB_HWCACHE_ALIGN
    */
    /*
        kmem_cache_create()的核心代码:
        kmem_cache_create() {
        size_t left_over,slab_size,ralign;
        struct kmem_cache *cachep =NULL,*pc;
        
        ...
        cachep = kmem_cache_zalloc(&cache_cache,GFP_KERNEL);
        ...
        left_over = calculate_slab_order(cachep,size,align,flags);
        ...
        cachep->colour_off = cache_line_size();    
        cachep->colour = left_over/cachep->colour_off;
        cachep->slab_size = flags;
        cachep->gfpflags = 0;
        cachep->buffer_size = size;
        cachep->reciprocal_buffer_size = reciprocal_value(size);
        ...
        cachep->ctor = ctor;
        cachep->name = name;
        ...
        return cachep;
    }
    */
    
    /*
        根据arraycache_int的大小使用kmem_cache_create来创建cache,即
        kmem_cache_create创建的第一个高速缓存是用来处理arraycache_init的
        INDEX_AC = sizeof(struct arraycache_t)
        此处的names[INDEX_AC].name = "size-32".
       
    */
    sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,
                    sizes[INDEX_AC].cs_size,
                    ARCH_KMALLOC_MINALIGN,
                    ARCH_KMALLOC_FLAGS|SLAB_PANIC,
                    NULL);
                    
    /*
        kmem_cache_create()最终函数的实现是cache_alloc_refill();
        cache_alloc_refill()的最终实现看后面.+
    *
    /
    /*    
        如果arraycache_init和kmem_list3所使用的高速缓存大小不同就给kmem_list3
        创建一个新的高速缓存描述符
    */
    if (INDEX_AC != INDEX_L3) {
        sizes[INDEX_L3].cs_cachep =
            kmem_cache_create(names[INDEX_L3].name,
                sizes[INDEX_L3].cs_size,
                ARCH_KMALLOC_MINALIGN,
                ARCH_KMALLOC_FLAGS|SLAB_PANIC,
                NULL);
    }

    slab_early_init = 0;
    
    /*
        此循环初始创建所有类型的高速缓存,相当于为所有类型的高速缓存开辟了一个起点
    */
    while (sizes->cs_size != ULONG_MAX) {
        /*
         * For performance, all the general caches are L1 aligned.
         * This should be particularly beneficial on SMP boxes, as it

     * eliminates "false sharing".
         * Note for systems short on memory removing the alignment will
         * allow tighter packing of the smaller caches.
         */
        if (!sizes->cs_cachep) {
            sizes->cs_cachep = kmem_cache_create(names->name,
                    sizes->cs_size,
                    ARCH_KMALLOC_MINALIGN,
                    ARCH_KMALLOC_FLAGS|SLAB_PANIC,
                    NULL);
        }
#ifdef CONFIG_ZONE_DMA
        /*
            给DMA创建一个高速缓存
        */
        sizes->cs_dmacachep = kmem_cache_create(
                    names->name_dma,
                    sizes->cs_size,
                    ARCH_KMALLOC_MINALIGN,
                    ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|
                        SLAB_PANIC,
                    NULL);
#endif
        sizes++;
        names++;
    }
    /* 4) Replace the bootstrap head arrays */
    {
        struct array_cache *ptr;
        
        /*
            创建array_cache类型对象,代替前面已初始化的cache_cache.array[0],
            如此一来,这就受到cache_cache的管理了.
        */
        ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);

        local_irq_disable();
        BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);
        //复制cache_cache中array_cache的值到ptr.
        memcpy(ptr, cpu_cache_get(&cache_cache),
               sizeof(struct arraycache_init));
        /*
         * Do not assume that spinlocks can be initialized via memcpy:
         */
        spin_lock_init(&ptr->lock);
        
        /*
            改变cache_cache原有的array_cache
        */
        cache_cache.array[smp_processor_id()] = ptr;
        
        local_irq_enable();

        ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);

        local_irq_disable();
        BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep)
               != &initarray_generic.cache);
        memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep),
               sizeof(struct arraycache_init));
        /*
         * Do not assume that spinlocks can be initialized via memcpy:
         */
        spin_lock_init(&ptr->lock);

        malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =
            ptr;
        local_irq_enable();
    }
    /* 5) Replace the bootstrap kmem_list3's */
    //取代引导程序所使用的kmem_list3
    {
        int nid;

        /*
            调用kmalloc_node()函数创建kmem_list3对象,取代初始的静态数据kmem_list3
        */
        init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);
        /*
        下面是init_list的具体实现
        struct kmem_list3 *ptr;
        ptr = kmalloc_node(sizeof(struct kmem_list3),GFP_KERNEL,nodeid);
        local_irq_disable();
        memcpy(ptr,list,sizeof(struct kmem_list3));
        spin_lock_init(&ptr->list_lock);
        MAKE_ALL_LISTS(cachep,ptr,nodeid);
        cachep->nodelists[nodeid] = ptr;
        local_irq_enable();
        */

        for_each_online_node(nid) {
            init_list(malloc_sizes[INDEX_AC].cs_cachep,
                  &initkmem_list3[SIZE_AC + nid], nid);

            if (INDEX_AC != INDEX_L3) {
                init_list(malloc_sizes[INDEX_L3].cs_cachep,
                      &initkmem_list3[SIZE_L3 + nid], nid);
            }
        }
    }

    /* 6) resize the head arrays to their final sizes */
    {
        struct kmem_cache *cachep;
        mutex_lock(&cache_chain_mutex);
        list_for_each_entry(cachep, &cache_chain, next)
            if (enable_cpucache(cachep))
                BUG();
        mutex_unlock(&cache_chain_mutex);
    }

    /* Annotate slab for lockdep -- annotate the malloc caches */
    init_lock_keys();


    /* Done! */
    g_cpucache_up = FULL;

    /*
     * Register a cpu startup notifier callback that initializes
     * cpu_cache_get for all new cpus
     */
    register_cpu_notifier(&cpucache_notifier);

    /*
     * The reap timers are started later, with a module init call: That part
     * of the kernel is not yet operational.
     */
}
阅读(2170) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~