免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3178 | 回复: 0
打印 上一主题 下一主题

[FreeBSD] freebsd9.2-ULE线程调度-创建数据结构来描述CPU拓扑信息 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-06-27 20:11 |只看该作者 |倒序浏览
本帖最后由 71v5 于 2014-06-27 20:13 编辑

前提:
intel Xeon E3-1226V3,4个物理核心,不支持超线程,即4核心4线程,系统中有两个E3-1226V3,每个E3-1226V3
对应一个package。

在ULE调度程序初始化阶段,函数sched_setup_smp会调用smp_topo函数创建相应的数据结构来描述系统中cpu的
拓扑信息,并初始化变量cpu_top。

[struct cpu_group对象]-用来描述系统中cpu的拓扑信息,每个struct cpu_group对象用来描述系统中的每一个
package,cpu_top指向的struct cpu_group对象描述了系统中全部的package:
  1. /***************************************************************************************
  2. * Topology of a NUMA or HTT system.
  3. *
  4. * The top level topology is an array of pointers to groups.  Each group
  5. * contains a bitmask of cpus in its group or subgroups.  It may also
  6. * contain a pointer to an array of child groups.
  7. *
  8. * The bitmasks at non leaf groups may be used by consumers who support
  9. * a smaller depth than the hardware provides.
  10. *
  11. * The topology may be omitted by systems where all CPUs are equal.
  12.    
  13.    static struct cpu_group group[MAXCPU];
  14.    struct cpu_group *cpu_top;           CPU topology

  15.    在我们假定的前提下,描述一下各个成员,部分成员通过看图,其含义将一目了然:

  16.    cg_parent:指向parent group。

  17.    cg_child:指向children group。

  18.    cgmask:一个cpu位图,位图中的bit以logical cpu id为索引,在每一个group
  19.            中,cg_mask中以该group中包含的cpu的logicl cpu id为索引的bit位
  20.            被设置为1.cpu_top指向的group中cgmask成员设置了系统中全部
  21.            cpu对应的bit位。

  22.    cg_count:该group中logical cpu的数目,cpu_top指向的group中cg_count
  23.              成员为系统中全部logical cpu的数目。

  24.    cg_children:children group的数目。
  25.   
  26.    cg_level:描述每个group中cpu的高速缓存属性,可以取值如下:
  27.              #define        CG_SHARE_NONE        0
  28.              #define        CG_SHARE_L1        1
  29.              #define        CG_SHARE_L2        2
  30.              #define        CG_SHARE_L3        3
  31.    
  32.    cg_flags:可以取值如下,不清楚其具体用处:
  33.    #define        CG_FLAG_HTT        0x01        Schedule the alternate core last.
  34.    #define        CG_FLAG_SMT        0x02        New age htt, less crippled.
  35.    #define        CG_FLAG_THREAD        (CG_FLAG_HTT | CG_FLAG_SMT)  Any threading.

  36.    这里再谈一下每cpu的运行队列即tdq_cpu,假设cpu的logicl id为2,那么
  37.    tdq_cpu[2]对象的tdq_cg成员就指向group[1].
  38. **************************/         
  39.     34        struct cpu_group {
  40.     35                struct cpu_group *cg_parent;        /* Our parent group. */
  41.     36                struct cpu_group *cg_child;        /* Optional children groups. */
  42.     37                cpuset_t        cg_mask;        /* Mask of cpus in this group. */
  43.     38                int32_t                cg_count;        /* Count of cpus in this group. */
  44.     39                int16_t                cg_children;        /* Number of children groups. */
  45.     40                int8_t                cg_level;        /* Shared cache level. */
  46.     41                int8_t                cg_flags;        /* Traversal modifiers. */
  47.     42        };
  48.     43       
  49.     44        typedef struct cpu_group *cpu_group_t;
复制代码
先看看函数smp_topo执行完后所创建的使用struct cpu_group对象描述cpu拓扑信息的数据结构图,这样更清楚一点:



[函数smp_topo]:
  1. 487        struct cpu_group *
  2.    488        smp_topo(void)
  3.    489        {
  4.    490                char cpusetbuf[CPUSETBUFSIZ], cpusetbuf2[CPUSETBUFSIZ];
  5.    491                struct cpu_group *top;
  6.    492       
  7.    493               
  8.    494
  9.    495
  10. /*******************************************************************
  11. * Check for a fake topology request for debugging purposes.
  12.    int smp_topology = 0;  Which topology we're using.                    

  13.    496-530:这里将调用cpu_topo函数进行探测,这个探测过程挺有意思,
  14.             下面重点分析这个函数,这个函数完成了描述cpu拓扑信息
  15.             的大部分工作。
  16.    
  17.    531-540:进行额外的有效性检查。
  18. *********************************/
  19.    496                switch (smp_topology) {
  20.    497                case 1:
  21.    498                        /* Dual core with no sharing.  */
  22.    499                        top = smp_topo_1level(CG_SHARE_NONE, 2, 0);
  23.    500                        break;
  24.    501                case 2:
  25.    502                        /* No topology, all cpus are equal. */
  26.    503                        top = smp_topo_none();
  27.    504                        break;
  28.    505                case 3:
  29.    506                        /* Dual core with shared L2.  */
  30.    507                        top = smp_topo_1level(CG_SHARE_L2, 2, 0);
  31.    508                        break;
  32.    509                case 4:
  33.    510                        /* quad core, shared l3 among each package, private l2.  */
  34.    511                        top = smp_topo_1level(CG_SHARE_L3, 4, 0);
  35.    512                        break;
  36.    513                case 5:
  37.    514                        /* quad core,  2 dualcore parts on each package share l2.  */
  38.    515                        top = smp_topo_2level(CG_SHARE_NONE, 2, CG_SHARE_L2, 2, 0);
  39.    516                        break;
  40.    517                case 6:
  41.    518                        /* Single-core 2xHTT */
  42.    519                        top = smp_topo_1level(CG_SHARE_L1, 2, CG_FLAG_HTT);
  43.    520                        break;
  44.    521                case 7:
  45.    522                        /* quad core with a shared l3, 8 threads sharing L2.  */
  46.    523                        top = smp_topo_2level(CG_SHARE_L3, 4, CG_SHARE_L2, 8,
  47.    524                            CG_FLAG_SMT);
  48.    525                        break;
  49.    526                default:
  50.    527                        /* Default, ask the system what it wants. */
  51.    528                        top = cpu_topo();
  52.    529                        break;
  53.    530                }
  54.    531                /*
  55.    532                 * Verify the returned topology.
  56.    533                 */
  57.    534                if (top->cg_count != mp_ncpus)
  58.    535                        panic("Built bad topology at %p.  CPU count %d != %d",
  59.    536                            top, top->cg_count, mp_ncpus);
  60.    537                if (CPU_CMP(&top->cg_mask, &all_cpus))
  61.    538                        panic("Built bad topology at %p.  CPU mask (%s) != (%s)",
  62.    539                            top, cpusetobj_strprint(cpusetbuf, &top->cg_mask),
  63.    540                            cpusetobj_strprint(cpusetbuf2, &all_cpus));
  64.    541                return (top);
  65.    542        }
复制代码
[函数cpu_topo]:
  1. /*******************************************************************************
  2. * static int cpu_logical;                         logical cpus per core
  3.    static int cpu_cores;                         cores per package
  4.   
  5.    cpu_logical:
  6.    每个core包含几个logical cpu,对于支持超线程的cpu,cpu_logical的值为2;
  7.    对于不支持超线程的cpu,cpu_logical的值为1.根据前提假定,cpu_logical的值为1。

  8.    cpu_cores:
  9.    每个cpu包含的物理核心数目,根据前提假定,这里cpu_cores的值为4.

  10.    其实上面两个变量的值可以通过函数topo_probe_0xb计算得到。
  11. ******************************/
  12.    
  13.    415        struct cpu_group *
  14.    416        cpu_topo(void)
  15.    417        {
  16.    418                int cg_flags;
  17.    419       
  18.    420               
  19.    421
  20.    422
  21. /*******************************************************************************
  22. * Determine whether any threading flags are necessry。
  23. *
  24. * mp_ncpus:系统中cpu的数目,在初始化函数apic_init中被设置为有意义的值
  25. * 424:函数topo_probe确定变量cpu_logical和cpu_cores的值。
  26.         根据我们的假定,cpu_logical为1,cpu_cores为4.

  27.    425-430:cg_flags设置为0.

  28.    431-435:对logical cpu数目进行额外的检查。

  29.    436-440:单核心单线程cpu。

  30.    441-445:单核心多线程cpu。

  31.    446-450:多核心单线程cpu。

  32.    451-455:多核心多线程cpu。

  33.    根据我们的前提假定,这里将执行446-450之间的代码,smp_topo_1level函数
  34.    主要创建描述cpu拓扑信息的struct cpu_group对象,该函数没有什么特殊操作,
  35.    很容易理解,也没有进行特别的分析,下面列出了这个函数,大家可以看看。
  36. *****************************************************/
  37.    423                 
  38.    424                topo_probe();
  39.    425                if (cpu_logical > 1 && hyperthreading_cpus)
  40.    426                        cg_flags = CG_FLAG_HTT;
  41.    427                else if (cpu_logical > 1)
  42.    428                        cg_flags = CG_FLAG_SMT;
  43.    429                else
  44.    430                        cg_flags = 0;
  45.    431                if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
  46.    432                        printf("WARNING: Non-uniform processors.\n");
  47.    433                        printf("WARNING: Using suboptimal topology.\n");
  48.    434                        return (smp_topo_none());
  49.    435                }
  50.    436                /*
  51.    437                 * No multi-core or hyper-threaded.
  52.    438                 */
  53.    439                if (cpu_logical * cpu_cores == 1)
  54.    440                        return (smp_topo_none());
  55.    441                /*
  56.    442                 * Only HTT no multi-core.
  57.    443                 */
  58.    444                if (cpu_logical > 1 && cpu_cores == 1)
  59.    445                        return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags));
  60.    446                /*
  61.    447                 * Only multi-core no HTT.
  62.    448                 */
  63.    449                if (cpu_cores > 1 && cpu_logical == 1)
  64.    450                        return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags));
  65.    451                /*
  66.    452                 * Both HTT and multi-core.
  67.    453                 */
  68.    454                return (smp_topo_2level(CG_SHARE_L2, cpu_cores,
  69.    455                    CG_SHARE_L1, cpu_logical, cg_flags));
  70.    456        }
复制代码
[函数topo_probe]:
  1.    367        /*
  2.    368         * Both topology discovery code and code that consumes topology
  3.    369         * information assume top-down uniformity of the topology.
  4.    370         * That is, all physical packages must be identical and each
  5.    371         * core in a package must have the same number of threads.
  6.    372         * Topology information is queried only on BSP, on which this
  7.    373         * code runs and for which it can query CPUID information.
  8.    374         * Then topology is extrapolated on all packages using the
  9.    375         * uniformity assumption.
  10.    376         */
  11.    377        static void
  12.    378        topo_probe(void)
  13.    379        {
  14.    380                static int cpu_topo_probed = 0;
  15.    381       
  16.    382                if (cpu_topo_probed)
  17.    383                        return;
  18.    384       
  19. /***************************************************************************************************
  20. * 385:将变量logical_cpus_mask清零。
  21.    cpuset_t logical_cpus_mask;
  22.    变量logical_cpus_mask为logical cpu的位图,每个bit位对应系统中的每个logical cpu。

  23.    386-387:
  24.    mp_ncpus:系统中cpu的数目,在初始化函数apic_init中被设置为有意义的值。根据intel
  25.    芯片中对APIC的描述,LOCAL APIC的数目就为系统中cpu的数目,ACPI规范
  26.    中有一个专门的表来描述系统中的LOCAL APIC,apic_init函数读取这个表,
  27.    根据其中的数据信息来正确初始化mp_ncpus。根据前提假设,mp_ncpus的值
  28.    为8.
  29.    
  30.    388-389:AMD cpu? 这里忽略。

  31.    390-403:对应的是intel cpu。
  32.    cpu_high变量是在内核初始化的最初阶段,在locore.s中,eax寄存器设置为0,执行cpuid
  33.    指令设置的,cpuid指令用来获取cpu相关的信息。

  34.    cpu_high变量的具体含义如下:
  35.    Highest CPUID Source Operand for Intel 64 and IA-32 Processors。
  36.    具体大家可以参考一下intel 芯片手册中队cupid指令的详细介绍。


  37.    根据Intel 64 Architecture Processor Topology Enumeration中的描述:
  38.    The x2APIC extension in Intel 64 architecture defines a 32-bit x2APIC ID,
  39.    the CPUID instruction in future Intel 64 processors will allow software to
  40.    enumerate system topology using x2APIC IDs. The extended topology enumeration
  41.    leaf of CPUID (leaf 11) is the preferred interface for system topology
  42.    enumeration for future Intel 64 processor.

  43.    The maximum value of supported CPUID leaf can be determined by setting EAX = 0,
  44.    execute CPUID and examine the returned value in EAX, i.e. CPUID.0:EAX. If CPUID.0:EAX >= 11
  45.    
  46.    可以看出来,只有当cpu_high>= 11时,才会去检查x2APIC extension,即调用函数topo_probe_0xb。
  47.    这里假设支持x2APIC extension,可以更具体的分析问题。

  48.    函数用来确定变量cpu_logical和cpu_cores的值。

  49.    410-412:是单核心单线程cpu?

  50.    412:将变量cpu_topo_probed设置为1,表示已经调用过函数topo_probe。
  51. **********************************************************************/
  52.    385                CPU_ZERO(&logical_cpus_mask);
  53.    386                if (mp_ncpus <= 1)
  54.    387                        cpu_cores = cpu_logical = 1;
  55.    388                else if (cpu_vendor_id == CPU_VENDOR_AMD)
  56.    389                        topo_probe_amd();
  57.    390                else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
  58.    391                        /*
  59.    392                         * See Intel(R) 64 Architecture Processor
  60.    393                         * Topology Enumeration article for details.
  61.    394                         *
  62.    395                         * Note that 0x1 <= cpu_high < 4 case should be
  63.    396                         * compatible with topo_probe_0x4() logic when
  64.    397                         * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
  65.    398                         * or it should trigger the fallback otherwise.
  66.    399                         */
  67.    400                        if (cpu_high >= 0xb)
  68.    401                                topo_probe_0xb();
  69.    402                        else if (cpu_high >= 0x1)
  70.    403                                topo_probe_0x4();
  71.    404                }
  72.    405       
  73.    406                /*
  74.    407                 * Fallback: assume each logical CPU is in separate
  75.    408                 * physical package.  That is, no multi-core, no SMT.
  76.    409                 */
  77.    410                if (cpu_cores == 0 || cpu_logical == 0)
  78.    411                        cpu_cores = cpu_logical = 1;
  79.    412                cpu_topo_probed = 1;
  80.    413        }
复制代码
[函数topo_probe_0xb]:
  1.    319        static void
  2.    320        topo_probe_0xb(void)
  3.    321        {
  4.    322                u_int p[4];
  5.    323                int bits;
  6.    324                int cnt;
  7.    325                int i;
  8.    326                int logical;
  9.    327                int type;
  10.    328                int x;
  11.    329       
  12. /********************************************************************************************************
  13. * 对这个"We only support three levels for now."的解释如下,即以下三个level:
  14.    SMT_ID: each unique SMT_ID allows software to distinguish different logical processors
  15.            within a processor core,也就说这一个level可以确定每一个processor core包含的
  16.            logical processor的数目。

  17.    Core_ID: each unique Core_ID allows software to distinguish different processor cores
  18.             within a physical package,也就是说这个一个level可以确定每个物理cpu包含的
  19.             全部logical cpu的数目。

  20.    Pkg_ID: each unique Pkg_ID allows software to distinguish different physical packages
  21.            in a multi-processor system,这一个level可以确定系统中物理cpu的数目。

  22.    
  23.    cpuid_count函数完成下面的功能:
  24.    software can determine whether CPUID leaf 11 exists by setting EAX=11, ECX=0,
  25.    execute CPUID to examine the non-zero value returned in EBX。
  26.    
  27.    在SMP系统中,数组cpu_info用来描述系统中每个cpu相关信息,在初始化函数apic_init中会设置
  28.    该数组中的元素。

  29.    在SMP中,boot_cpu_id为BSP的APIC ID。

  30.    cpuid_count函数以下面的参数执行cpuid指令:
  31.    0xb->EAX寄存器
  32.    i->ECX寄存器
  33.    执行cpuid指令
  34.    EAX寄存器->p[0]
  35.    EBX寄存器->p[1]
  36.    ECX寄存器->p[2]
  37.    EDX寄存器->p[3]

  38.    331-361:执行三次for循环,如下:
  39.       
  40.    第一次循环---确定cpu_logical变量的值:
  41.    CPUID.(EAX=11, ECX=0)这样执行cpuid指令,对应的level为0,level type为CPUID_TYPE_SMT:

  42.    335-338:忽略,没有分析意义。

  43.    340:bits为一个位移量,

  44.    341:logical为Number of logical processors at this level type,可以忽略。

  45.    342:type为level type,此次循环时,type为CPUID_TYPE_SMT。

  46.    350-356:
  47.    检查系统中每个cpu的APIC ID,如果x >> bits == boot_cpu_id >> bits为真,就表示cpu x和boot_cpu_id
  48.    在同一个processor core上,当这段for循环执行完后cnt变量就表示每个processor core上的logical cpu的
  49.    数目;如果支持超线程等技术,cnt的值为2;如果不支持超线程等技术,cnt的值为1.
  50.    
  51.    357-360:
  52.    此次循环,type为CPUID_TYPE_SMT,将cnt赋值给cpu_logical,根据我们前提,cpu_logical的值为1.

  53.    
  54.    第二次循环---确定变量cpu_cores的值:
  55.    CPUID.(EAX=11, ECX=1)这样执行cpuid指令,对应的level为1,level type为CPUID_TYPE_CORE:

  56.    335-338:忽略,没有分析意义。

  57.    340:bits为一个位移量,

  58.    341:logical为Number of logical processors at this level type,可以忽略。

  59.    342:type为level type,此次次循环时,type为CPUID_TYPE_CORE。

  60.    350-356:
  61.    检查系统中每个cpu的APIC ID,如果x >> bits == boot_cpu_id >> bits为真,就表示cpu x和boot_cpu_id
  62.    在同一个物理cpu上,当这段for循环执行完后cnt变量就表示每个物理cpu包含的logical cpu数目;对于4核心
  63.    8线程的cpu,cnt的值为8;对于4核心4线程的cpu,cnt的值为4.
  64.    
  65.    
  66.    357-360:
  67.    此次循环,type为CPUID_TYPE_CORE,将cnt赋值给cpu_cores,根据我们前提,cpu_cores的值为4.


  68.    第三次循环-没有分析意义。

  69.    362-364:确定变量cpu_cores和cpu_logical的最终值。

  70. *****************************************************************/
  71.    330                /* We only support three levels for now. */
  72.    331                for (i = 0; i < 3; i++) {
  73.    332                        cpuid_count(0x0b, i, p);
  74.    333       
  75.    334                        /* Fall back if CPU leaf 11 doesn't really exist. */
  76.    335                        if (i == 0 && p[1] == 0) {
  77.    336                                topo_probe_0x4();
  78.    337                                return;
  79.    338                        }
  80.    339       
  81.    340                        bits = p[0] & 0x1f;
  82.    341                        logical = p[1] &= 0xffff;
  83.    342                        type = (p[2] >> 8) & 0xff;
  84.    343                        if (type == 0 || logical == 0)
  85.    344                                break;
  86.    345                        /*
  87.    346                         * Because of uniformity assumption we examine only
  88.    347                         * those logical processors that belong to the same
  89.    348                         * package as BSP.
  90.    349                         */
  91.    350                        for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) {
  92.    351                                if (!cpu_info[x].cpu_present ||
  93.    352                                    cpu_info[x].cpu_disabled)
  94.    353                                        continue;
  95.    354                                if (x >> bits == boot_cpu_id >> bits)
  96.    355                                        cnt++;
  97.    356                        }
  98.    357                        if (type == CPUID_TYPE_SMT)
  99.    358                                cpu_logical = cnt;
  100.    359                        else if (type == CPUID_TYPE_CORE)
  101.    360                                cpu_cores = cnt;
  102.    361                }
  103.    362                if (cpu_logical == 0)
  104.    363                        cpu_logical = 1;
  105.    364                cpu_cores /= cpu_logical;
  106.    365        }
复制代码
[函数smp_topo_1level]:
  1. /***************************************************************
  2. * 参数描述:
  3.    share:CG_SHARE_L2
  4.    count:cpu_cores,即每个物理cpu上的核心数目,这里为4.
  5.    flags:为0.

  6.    static struct cpu_group group[MAXCPU];
  7. *******************************/
  8.    593        struct cpu_group *
  9.    594        smp_topo_1level(int share, int count, int flags)
  10.    595        {
  11.    596                struct cpu_group *child;
  12.    597                struct cpu_group *top;
  13.    598                int packages;
  14.    599                int cpu;
  15.    600                int i;
  16.    601       
  17. /***********************************************************************
  18. * mp_ncpus:系统中cpu的数目,在初始化函数apic_init中被设置为有意义的值。

  19.    604:packages为系统中物理cpu的数目。
  20. *****************************/
  21.    602                cpu = 0;
  22.    603                top = &group[0];
  23.    604                packages = mp_ncpus / count;
  24.    605                top->cg_child = child = &group[1];
  25.    606                top->cg_level = CG_SHARE_NONE;
  26.    607                for (i = 0; i < packages; i++, child++)
  27.    608                        cpu = smp_topo_addleaf(top, child, share, count, flags, cpu);
  28.    609                return (top);
  29.    610        }
复制代码
[函数smp_topo_addleaf]:
  1.    561        static int
  2.    562        smp_topo_addleaf(struct cpu_group *parent, struct cpu_group *child, int share,
  3.    563            int count, int flags, int start)
  4.    564        {
  5.    565                char cpusetbuf[CPUSETBUFSIZ], cpusetbuf2[CPUSETBUFSIZ];
  6.    566                cpuset_t mask;
  7.    567                int i;
  8.    568       
  9.    569                CPU_ZERO(&mask);
  10.    570                for (i = 0; i < count; i++, start++)
  11.    571                        CPU_SET(start, &mask);
  12.    572                child->cg_parent = parent;
  13.    573                child->cg_child = NULL;
  14.    574                child->cg_children = 0;
  15.    575                child->cg_level = share;
  16.    576                child->cg_count = count;
  17.    577                child->cg_flags = flags;
  18.    578                child->cg_mask = mask;
  19.    579                parent->cg_children++;
  20.    580                for (; parent != NULL; parent = parent->cg_parent) {
  21.    581                        if (CPU_OVERLAP(&parent->cg_mask, &child->cg_mask))
  22.    582                                panic("Duplicate children in %p.  mask (%s) child (%s)",
  23.    583                                    parent,
  24.    584                                    cpusetobj_strprint(cpusetbuf, &parent->cg_mask),
  25.    585                                    cpusetobj_strprint(cpusetbuf2, &child->cg_mask));
  26.    586                        CPU_OR(&parent->cg_mask, &child->cg_mask);
  27.    587                        parent->cg_count += child->cg_count;
  28.    588                }
  29.    589       
  30.    590                return (start);
  31.    591        }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP