zoukankan      html  css  js  c++  java
  • 内存管理 初始化(七)kmem_cache_init_late 初始化slab分配器(下)

    我们知道kmem_cache中对于每CPU都有一个array_cache,已作为每CPU申请内存的缓存.  此函数的目的在于:每个kmem_cache都有一个kmem_list3实例,该实例的shared作为一个kmem_cache上所有CPU的内存申请缓存.  但是在此之前,seup_cpu_cache中对于kmem_cache中array_cache的值初始化体现不出缓存思想,而且对于kmem_cache中的kmem_list3.shared也没有利用.

    kmem_cache_init_late的目的就在于完善slab分配器的缓存机制.                                                                              

    start_kernel()
    |-->page_address_init() | |-->setup_arch(&command_line); | |-->setup_per_cpu_areas(); | |-->build_all_zonelist() | |-->page_alloc_init() | |-->pidhash_init() | |-->vfs_caches_init_early() | |-->mm_init() | |-->....... | |-->gfp_allowed_mask = __GFP_BITS_MASK; | 在此之前,gfp_allowed_mask = GFP_BOOT_MASK; | |-->kmem_cache_init_late(); |
    void __init kmem_cache_init_late(void)
      |-->struct kmem_cache *cachep;
      |
      |-->list_for_each_entry(cachep, &cache_chain, next)
      |-->if (enable_cpucache(cachep, GFP_NOWAIT))  BUG();
      |
      |--g_cpucache_up = FULL;
      |
      |-->init_lock_keys();
      |
      |-->register_cpu_notifiler(&cpu_notifier);
    int enabel_cpucache(struct kmem_cache *cachep, gfp_t gfp)
      |-->int limit;
      |
      |-->if (cachep->buffer_size > 131072) limit = 1;
      |   else if (cachep->buffer_size > PAGE_SIZE) limit = 8;
      |   else if (cachep->buffer_size > 1024) limit = 24;
      |   else if (cachep->buffer_size > 256) limit = 54;
      |   else limit = 120;
      |   为什么选择这些数值啊,不明白???
      |
      |-->int shared = 0;
      |   if(cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1)
      |      shared = 8;
      |
      |--int err = 0;
      |  err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared, gfp);
      |
      |--return err;
    int do_tune_cpucache(struct kmem_cache *cachep, int limit,
            int batchcount, int shared, gfp_t gfp)
      |-->struct ccupdate_struct *new = NULL;
      |   new = kazlloc(sizeof(*new), gfp);
      |
      |--int i;
      |--for_each_online_cpu(i)
      |--{
      |    new->new[i] = alloc_arraycache(cpu_to_node(i), limit,
    | batchcount, gfp);
    | 根据limit, batchcount数值,构建新的array_cache实例. | | 因为kmem_cache中的array_cache是每个CPU的,所以此处是循环,为每个CPU都 | 都构建一个array_cache实例. |--} | |-->new->cachep = cachep; | |-->on_each_cpu(do_ccupdate_local, (void*)new, 1); | 将kmem_cache下的每个CPU的array_cache[i]更换成new->new[i]; | |-->cachep->batchcount = batchcount; | cachep->limit = limit; | cachep->shared = shared; | | | 上面以替换了kmem_cache下的每个CPU的array_cache[i],
    | 因此需要把原来的array_cache释放掉.
    |--for_each_online_cpu(i) |--{ | struct array_cache *ccolde = new->new[i]; | if(!ccold) continue; | | free_block(cachep, ccold->entry, ccold->avail, cpu_to_node(i)); | 我们知道在此之前,ccold->avail一直为0,所以该函数暂时可以不看. | 此函数,就是把ccold->avail个ccole->entry中的数组元素指向的内存空间 | 释放给slab管理器. | | | kfree(ccold); | 基本同于free_block,我们知道slab所管理的内存都是位于低端内存,低端内存的物 | 理地址及其对应的虚拟地址存在固定偏移,因此根据该部分的虚拟地址可以很容易的找到 | struct page实例,而struct page中的lru链表,在slab中被复用了,根据链表 | 指针可以找到kmem_cache实例,所以kfree基本等同于free_block; | 但是kfree与free_block的重要的不同点在于,free_block直接将内存释放给了 | slab管理器,而kfree首选将内存释放给每CPU的array_cache数组. | |--} |-->kfree(new); | |--return alloc_kmemlist(cachep, gfp); | 每个kmem_cache中的kmem_list3.shared上array_cache可以被所有CPU共享.
    我们知道kmem_cache中对于每CPU都有一个array_cache,已作为每CPU申请内存的缓存. 
    此函数的目的在于:每个kmem_cache都有一个kmem_list3实例,该实例的shared作为
    一个kmem_cache上所有CPU的内存申请缓存(对于UMA,kmem_cache.alien没有用处).
    此时,我们不妨猜测,当一个CPU通过kmalloc申请内内存时,将从kmem_cache实例上
    自己的array_cache进行申请,如果没有则从kmem_list3->shared上补充到array_cache上,
    如果kmem_list3上也每有,将从slab管理器上获取,充分体现了缓存的利用.
    int alloc_kmemlist(struct kmem_cache *cachep, gfp_t gfp)
      |-->int node = 0;
      |   struct kmem_list3 *l3 = NULL;
      |   struct array_cache *new_shared = NULL;
      |   struct array_cache **new_alien = NULL;
      |
      |-->for_each_online_node(node)
      |--{
      |    new_shared = NULL;
      |    if(cachep->shared)
      |        new_shared = alloc_arraycache(node, 
      |                     cachep->shared * cachep->batchcount,
      |                     0xbaadf00d, gfp);
      |
      |
      |    l3 = cachep->nodelists[node];
      |    if(l3)
      |    |-{
      |    |    struct array_cache *shared = l3->shared;
      |    |    if(shared) 
    | | free_block(cachep, shared->entry, shared->avail, node); | | l3->shared = new_shared; | | if(!l3->alien) l3->alien = new_alien, new_alien = NULL; | | l3->free_limit = (1 + NR_CPUS) * cachep->batchcount
    | | + cachep->num;| | kfree(shared); | | free_alien_cache(new_alien); | | continue; //对于单节点,再次continue时,将退出循环 | |-} | | | | | ...... 对于UMA体系 nothing | |
    |--}
    | |--return 0;
    void do_ccupdate_local(void *info)
      |-->struct ccupdate_struct *new = info;
      |   struct array_cache *old = cpu_cache_get(new->cachep);
      |
      |-->new->cachep->array[smp_processor_id()] = 
    | new->new[smp_processor_id];
    | new->new[smp_processor_id()] = old;
    struct array_cache *alloc_arraycache(int node, int entries,
            int batchcount, gfp_t gfp)
      |-->int memsize = sizeof(void *) * entries
    | + sizeof(struct array_cache);
    | 根据entries的数值,计算该分配的array_cache空间大小. | |-->struct array_cache *nc = NULL; | nc = kmalloc_node(memsize, gfp, node); | nc->avail = 0; | nc->limit = entries; | nc->batchcount = batchcount; | nc->touched = 0; | spin_lock_init(&nc->lock); | |-->return nc;
  • 相关阅读:
    uva 10369 Arctic Network
    uvalive 5834 Genghis Khan The Conqueror
    uvalive 4848 Tour Belt
    uvalive 4960 Sensor Network
    codeforces 798c Mike And Gcd Problem
    codeforces 796c Bank Hacking
    codeforces 768c Jon Snow And His Favourite Number
    hdu 1114 Piggy-Bank
    poj 1276 Cash Machine
    bzoj 2423 最长公共子序列
  • 原文地址:https://www.cnblogs.com/openix/p/3352652.html
Copyright © 2011-2022 走看看