• pg_data_t、struct zonelist、struct zoneref和struct zone浅析


    在NUMA架构中存在多个内存节点,每个内存节点在Linux内核用pg_data_t类型(实际是struct pglist_data)来表示表示;

    各个内存节点又各自有各自的内存区(即struct zone),这些内存区由pg_data_t的成员struct zone node_zones[MAX_NR_ZONES]来存放;

    而在分配内存时不仅可以从自己的内存节点分配内存,还可从其他内存节点分配内存,选择哪个节点分配内存也是提前有策略设计好了的,这个是通过Linux内核一些数据结构的巧妙设计来决策,这个就是由pg_data_t的成员struct zonelist node_zonelists[MAX_ZONELISTS]来实现的。

    typedef struct pglist_data {
        /*
        * node_zones contains just the zones for THIS node. Not all of the
        * zones may be populated, but it is the full list. It is referenced by
        * this node's node_zonelists as well as other node's node_zonelists.
        */
        struct zone node_zones[MAX_NR_ZONES];             //存放该内存节点的内存区zones
    
        /*
        * node_zonelists contains references to all zones in all nodes.
        * Generally the first zones will be references to this node's
        * node_zones.
        */
        struct zonelist node_zonelists[MAX_ZONELISTS]; //zonelist装着系统中所有内存节点的zones
        ......
    } pg_data_t;
    
    struct zonelist {
        struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];    //一个zonelist最多可以有(MAX_ZONES_PER_ZONELIST + 1)个struct zoneref
    };
    
    
    //一个zoneref对应一个zone
    /*
     * This struct contains information about a zone in a zonelist. It is stored
     * here to avoid dereferences into large structures and lookups of tables
     */
    struct zoneref {
        struct zone *zone;      /* Pointer to actual zone */
        int zone_idx;           /* zone_idx(zoneref->zone) */
    };

    上面就是一个节点与其他节点zones发生关系的一些相关数据结构。还是来一张图清楚一点:

           

     图1  struct pglist_data与struct zone、struct zonelist关系示意图

    pg_data_t->node_zones[MAX_NR_ZONES]:该内存节点的MAX_NR_ZONE个内存区(struct zone)。

                                                                              具体多少视系统支持哪些类型的struct zone,例如ZONE_DMA, ZONE_DMA32, ZONE_NORMAL, ZONE_HIGH.....。有的架构可能没有ZONE_DMA,有的可能没有ZONE_DMA32,有的可能没有ZONE_HIGH。

    pg_data_t->node_zonelists[MAX_ZONELISTS]:定义了该内存节点分配内存时选择从struct zone分配内存的先后顺序。

                          在支持NUMA的内核中最多两个选择:ZONELIST_FALLBACK和ZONELIST_NOFALLBACK,如下所示

    enum {
        ZONELIST_FALLBACK,      /* zonelist with fallback */
    #ifdef CONFIG_NUMA
        /*
         * The NUMA zonelists are doubled because we need zonelists that
         * restrict the allocations to a single node for __GFP_THISNODE.
         */
        ZONELIST_NOFALLBACK,    /* zonelist without fallback (__GFP_THISNODE) */
    #endif
        MAX_ZONELISTS
    };

    从注释可以了解到:ZONELIST_NOFALLBACK是在NUMA架构中,如果分配内存时使用__GFP_THISNODE了标志时则尝试从pg_data_t->node_zonelists[ZONELIST_NOFALLBACK]中去分配内存;否则尝试从pg_data_t->node_zonelists[ZONELIST_FALLBACK]中去分配内存。

    在系统初始化阶段,Linux内核会遍历系统中的各个内存节点,并根据其他邻居节点到该节点"距离"的"远""近"关系安插邻居节点的struct zone到pg_data_t->node_zonelists[ZONELIST_FALLBACK]的数组中,即zonelist->_zonerefs[MAX_ZONES_PER_ZONELIST+1]这个数组中:

    struct zonelist {
        struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];    //一个zonelist最多可以有(MAX_ZONES_PER_ZONELIST + 1)个struct zoneref
    };

    "距离"越近的邻居节点所属的struct zone,在_zonerefs[]数组中的位置越靠前;同一个邻居节点中zones按照从高到低的顺序排列(即ZONE_HIGH、ZONE_NORMAL...ZONE_DMA)。

    这样在分配内存时,优先从最近的邻居内存节点的最高index的内存zone分配内存,这样就达到了前文所说的分配顺序策略的遴选情况。

  • 相关阅读:
    Javaweb中的监听器
    Maven
    Ajax
    jQuery
    Spring入门
    spring boot实战——微信点餐系统02:接口信息,分页工具,gson, 注解信息,表单验证,字段返回(时间处理,null处理)
    Nginx
    Spring Data JPA
    spring boot实战——微信点餐系统01:开始代码
    spring boot实战——微信点餐系统00:项目设计,环境搭建
  • 原文地址:https://www.cnblogs.com/liuhailong0112/p/14599816.html
Copyright © 2020-2023  润新知