- 论坛徽章:
- 0
|
本帖最后由 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:- /***************************************************************************************
- * Topology of a NUMA or HTT system.
- *
- * The top level topology is an array of pointers to groups. Each group
- * contains a bitmask of cpus in its group or subgroups. It may also
- * contain a pointer to an array of child groups.
- *
- * The bitmasks at non leaf groups may be used by consumers who support
- * a smaller depth than the hardware provides.
- *
- * The topology may be omitted by systems where all CPUs are equal.
-
- static struct cpu_group group[MAXCPU];
- struct cpu_group *cpu_top; CPU topology
- 在我们假定的前提下,描述一下各个成员,部分成员通过看图,其含义将一目了然:
- cg_parent:指向parent group。
- cg_child:指向children group。
- cgmask:一个cpu位图,位图中的bit以logical cpu id为索引,在每一个group
- 中,cg_mask中以该group中包含的cpu的logicl cpu id为索引的bit位
- 被设置为1.cpu_top指向的group中cgmask成员设置了系统中全部
- cpu对应的bit位。
-
- cg_count:该group中logical cpu的数目,cpu_top指向的group中cg_count
- 成员为系统中全部logical cpu的数目。
- cg_children:children group的数目。
-
- cg_level:描述每个group中cpu的高速缓存属性,可以取值如下:
- #define CG_SHARE_NONE 0
- #define CG_SHARE_L1 1
- #define CG_SHARE_L2 2
- #define CG_SHARE_L3 3
-
- cg_flags:可以取值如下,不清楚其具体用处:
- #define CG_FLAG_HTT 0x01 Schedule the alternate core last.
- #define CG_FLAG_SMT 0x02 New age htt, less crippled.
- #define CG_FLAG_THREAD (CG_FLAG_HTT | CG_FLAG_SMT) Any threading.
- 这里再谈一下每cpu的运行队列即tdq_cpu,假设cpu的logicl id为2,那么
- tdq_cpu[2]对象的tdq_cg成员就指向group[1].
- **************************/
- 34 struct cpu_group {
- 35 struct cpu_group *cg_parent; /* Our parent group. */
- 36 struct cpu_group *cg_child; /* Optional children groups. */
- 37 cpuset_t cg_mask; /* Mask of cpus in this group. */
- 38 int32_t cg_count; /* Count of cpus in this group. */
- 39 int16_t cg_children; /* Number of children groups. */
- 40 int8_t cg_level; /* Shared cache level. */
- 41 int8_t cg_flags; /* Traversal modifiers. */
- 42 };
- 43
- 44 typedef struct cpu_group *cpu_group_t;
复制代码 先看看函数smp_topo执行完后所创建的使用struct cpu_group对象描述cpu拓扑信息的数据结构图,这样更清楚一点:
[函数smp_topo]:- 487 struct cpu_group *
- 488 smp_topo(void)
- 489 {
- 490 char cpusetbuf[CPUSETBUFSIZ], cpusetbuf2[CPUSETBUFSIZ];
- 491 struct cpu_group *top;
- 492
- 493
- 494
- 495
- /*******************************************************************
- * Check for a fake topology request for debugging purposes.
- int smp_topology = 0; Which topology we're using.
- 496-530:这里将调用cpu_topo函数进行探测,这个探测过程挺有意思,
- 下面重点分析这个函数,这个函数完成了描述cpu拓扑信息
- 的大部分工作。
-
- 531-540:进行额外的有效性检查。
- *********************************/
- 496 switch (smp_topology) {
- 497 case 1:
- 498 /* Dual core with no sharing. */
- 499 top = smp_topo_1level(CG_SHARE_NONE, 2, 0);
- 500 break;
- 501 case 2:
- 502 /* No topology, all cpus are equal. */
- 503 top = smp_topo_none();
- 504 break;
- 505 case 3:
- 506 /* Dual core with shared L2. */
- 507 top = smp_topo_1level(CG_SHARE_L2, 2, 0);
- 508 break;
- 509 case 4:
- 510 /* quad core, shared l3 among each package, private l2. */
- 511 top = smp_topo_1level(CG_SHARE_L3, 4, 0);
- 512 break;
- 513 case 5:
- 514 /* quad core, 2 dualcore parts on each package share l2. */
- 515 top = smp_topo_2level(CG_SHARE_NONE, 2, CG_SHARE_L2, 2, 0);
- 516 break;
- 517 case 6:
- 518 /* Single-core 2xHTT */
- 519 top = smp_topo_1level(CG_SHARE_L1, 2, CG_FLAG_HTT);
- 520 break;
- 521 case 7:
- 522 /* quad core with a shared l3, 8 threads sharing L2. */
- 523 top = smp_topo_2level(CG_SHARE_L3, 4, CG_SHARE_L2, 8,
- 524 CG_FLAG_SMT);
- 525 break;
- 526 default:
- 527 /* Default, ask the system what it wants. */
- 528 top = cpu_topo();
- 529 break;
- 530 }
- 531 /*
- 532 * Verify the returned topology.
- 533 */
- 534 if (top->cg_count != mp_ncpus)
- 535 panic("Built bad topology at %p. CPU count %d != %d",
- 536 top, top->cg_count, mp_ncpus);
- 537 if (CPU_CMP(&top->cg_mask, &all_cpus))
- 538 panic("Built bad topology at %p. CPU mask (%s) != (%s)",
- 539 top, cpusetobj_strprint(cpusetbuf, &top->cg_mask),
- 540 cpusetobj_strprint(cpusetbuf2, &all_cpus));
- 541 return (top);
- 542 }
复制代码 [函数cpu_topo]:- /*******************************************************************************
- * static int cpu_logical; logical cpus per core
- static int cpu_cores; cores per package
-
- cpu_logical:
- 每个core包含几个logical cpu,对于支持超线程的cpu,cpu_logical的值为2;
- 对于不支持超线程的cpu,cpu_logical的值为1.根据前提假定,cpu_logical的值为1。
- cpu_cores:
- 每个cpu包含的物理核心数目,根据前提假定,这里cpu_cores的值为4.
- 其实上面两个变量的值可以通过函数topo_probe_0xb计算得到。
- ******************************/
-
- 415 struct cpu_group *
- 416 cpu_topo(void)
- 417 {
- 418 int cg_flags;
- 419
- 420
- 421
- 422
- /*******************************************************************************
- * Determine whether any threading flags are necessry。
- *
- * mp_ncpus:系统中cpu的数目,在初始化函数apic_init中被设置为有意义的值
- * 424:函数topo_probe确定变量cpu_logical和cpu_cores的值。
- 根据我们的假定,cpu_logical为1,cpu_cores为4.
- 425-430:cg_flags设置为0.
- 431-435:对logical cpu数目进行额外的检查。
- 436-440:单核心单线程cpu。
- 441-445:单核心多线程cpu。
- 446-450:多核心单线程cpu。
- 451-455:多核心多线程cpu。
- 根据我们的前提假定,这里将执行446-450之间的代码,smp_topo_1level函数
- 主要创建描述cpu拓扑信息的struct cpu_group对象,该函数没有什么特殊操作,
- 很容易理解,也没有进行特别的分析,下面列出了这个函数,大家可以看看。
- *****************************************************/
- 423
- 424 topo_probe();
- 425 if (cpu_logical > 1 && hyperthreading_cpus)
- 426 cg_flags = CG_FLAG_HTT;
- 427 else if (cpu_logical > 1)
- 428 cg_flags = CG_FLAG_SMT;
- 429 else
- 430 cg_flags = 0;
- 431 if (mp_ncpus % (cpu_cores * cpu_logical) != 0) {
- 432 printf("WARNING: Non-uniform processors.\n");
- 433 printf("WARNING: Using suboptimal topology.\n");
- 434 return (smp_topo_none());
- 435 }
- 436 /*
- 437 * No multi-core or hyper-threaded.
- 438 */
- 439 if (cpu_logical * cpu_cores == 1)
- 440 return (smp_topo_none());
- 441 /*
- 442 * Only HTT no multi-core.
- 443 */
- 444 if (cpu_logical > 1 && cpu_cores == 1)
- 445 return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags));
- 446 /*
- 447 * Only multi-core no HTT.
- 448 */
- 449 if (cpu_cores > 1 && cpu_logical == 1)
- 450 return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags));
- 451 /*
- 452 * Both HTT and multi-core.
- 453 */
- 454 return (smp_topo_2level(CG_SHARE_L2, cpu_cores,
- 455 CG_SHARE_L1, cpu_logical, cg_flags));
- 456 }
复制代码 [函数topo_probe]:- 367 /*
- 368 * Both topology discovery code and code that consumes topology
- 369 * information assume top-down uniformity of the topology.
- 370 * That is, all physical packages must be identical and each
- 371 * core in a package must have the same number of threads.
- 372 * Topology information is queried only on BSP, on which this
- 373 * code runs and for which it can query CPUID information.
- 374 * Then topology is extrapolated on all packages using the
- 375 * uniformity assumption.
- 376 */
- 377 static void
- 378 topo_probe(void)
- 379 {
- 380 static int cpu_topo_probed = 0;
- 381
- 382 if (cpu_topo_probed)
- 383 return;
- 384
- /***************************************************************************************************
- * 385:将变量logical_cpus_mask清零。
- cpuset_t logical_cpus_mask;
- 变量logical_cpus_mask为logical cpu的位图,每个bit位对应系统中的每个logical cpu。
- 386-387:
- mp_ncpus:系统中cpu的数目,在初始化函数apic_init中被设置为有意义的值。根据intel
- 芯片中对APIC的描述,LOCAL APIC的数目就为系统中cpu的数目,ACPI规范
- 中有一个专门的表来描述系统中的LOCAL APIC,apic_init函数读取这个表,
- 根据其中的数据信息来正确初始化mp_ncpus。根据前提假设,mp_ncpus的值
- 为8.
-
- 388-389:AMD cpu? 这里忽略。
- 390-403:对应的是intel cpu。
- cpu_high变量是在内核初始化的最初阶段,在locore.s中,eax寄存器设置为0,执行cpuid
- 指令设置的,cpuid指令用来获取cpu相关的信息。
- cpu_high变量的具体含义如下:
- Highest CPUID Source Operand for Intel 64 and IA-32 Processors。
- 具体大家可以参考一下intel 芯片手册中队cupid指令的详细介绍。
- 根据Intel 64 Architecture Processor Topology Enumeration中的描述:
- The x2APIC extension in Intel 64 architecture defines a 32-bit x2APIC ID,
- the CPUID instruction in future Intel 64 processors will allow software to
- enumerate system topology using x2APIC IDs. The extended topology enumeration
- leaf of CPUID (leaf 11) is the preferred interface for system topology
- enumeration for future Intel 64 processor.
- The maximum value of supported CPUID leaf can be determined by setting EAX = 0,
- execute CPUID and examine the returned value in EAX, i.e. CPUID.0:EAX. If CPUID.0:EAX >= 11
-
- 可以看出来,只有当cpu_high>= 11时,才会去检查x2APIC extension,即调用函数topo_probe_0xb。
- 这里假设支持x2APIC extension,可以更具体的分析问题。
- 函数用来确定变量cpu_logical和cpu_cores的值。
- 410-412:是单核心单线程cpu?
- 412:将变量cpu_topo_probed设置为1,表示已经调用过函数topo_probe。
- **********************************************************************/
- 385 CPU_ZERO(&logical_cpus_mask);
- 386 if (mp_ncpus <= 1)
- 387 cpu_cores = cpu_logical = 1;
- 388 else if (cpu_vendor_id == CPU_VENDOR_AMD)
- 389 topo_probe_amd();
- 390 else if (cpu_vendor_id == CPU_VENDOR_INTEL) {
- 391 /*
- 392 * See Intel(R) 64 Architecture Processor
- 393 * Topology Enumeration article for details.
- 394 *
- 395 * Note that 0x1 <= cpu_high < 4 case should be
- 396 * compatible with topo_probe_0x4() logic when
- 397 * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1)
- 398 * or it should trigger the fallback otherwise.
- 399 */
- 400 if (cpu_high >= 0xb)
- 401 topo_probe_0xb();
- 402 else if (cpu_high >= 0x1)
- 403 topo_probe_0x4();
- 404 }
- 405
- 406 /*
- 407 * Fallback: assume each logical CPU is in separate
- 408 * physical package. That is, no multi-core, no SMT.
- 409 */
- 410 if (cpu_cores == 0 || cpu_logical == 0)
- 411 cpu_cores = cpu_logical = 1;
- 412 cpu_topo_probed = 1;
- 413 }
复制代码 [函数topo_probe_0xb]:[函数smp_topo_1level]:- /***************************************************************
- * 参数描述:
- share:CG_SHARE_L2
- count:cpu_cores,即每个物理cpu上的核心数目,这里为4.
- flags:为0.
- static struct cpu_group group[MAXCPU];
- *******************************/
- 593 struct cpu_group *
- 594 smp_topo_1level(int share, int count, int flags)
- 595 {
- 596 struct cpu_group *child;
- 597 struct cpu_group *top;
- 598 int packages;
- 599 int cpu;
- 600 int i;
- 601
- /***********************************************************************
- * mp_ncpus:系统中cpu的数目,在初始化函数apic_init中被设置为有意义的值。
- 604:packages为系统中物理cpu的数目。
- *****************************/
- 602 cpu = 0;
- 603 top = &group[0];
- 604 packages = mp_ncpus / count;
- 605 top->cg_child = child = &group[1];
- 606 top->cg_level = CG_SHARE_NONE;
- 607 for (i = 0; i < packages; i++, child++)
- 608 cpu = smp_topo_addleaf(top, child, share, count, flags, cpu);
- 609 return (top);
- 610 }
复制代码 [函数smp_topo_addleaf]:- 561 static int
- 562 smp_topo_addleaf(struct cpu_group *parent, struct cpu_group *child, int share,
- 563 int count, int flags, int start)
- 564 {
- 565 char cpusetbuf[CPUSETBUFSIZ], cpusetbuf2[CPUSETBUFSIZ];
- 566 cpuset_t mask;
- 567 int i;
- 568
- 569 CPU_ZERO(&mask);
- 570 for (i = 0; i < count; i++, start++)
- 571 CPU_SET(start, &mask);
- 572 child->cg_parent = parent;
- 573 child->cg_child = NULL;
- 574 child->cg_children = 0;
- 575 child->cg_level = share;
- 576 child->cg_count = count;
- 577 child->cg_flags = flags;
- 578 child->cg_mask = mask;
- 579 parent->cg_children++;
- 580 for (; parent != NULL; parent = parent->cg_parent) {
- 581 if (CPU_OVERLAP(&parent->cg_mask, &child->cg_mask))
- 582 panic("Duplicate children in %p. mask (%s) child (%s)",
- 583 parent,
- 584 cpusetobj_strprint(cpusetbuf, &parent->cg_mask),
- 585 cpusetobj_strprint(cpusetbuf2, &child->cg_mask));
- 586 CPU_OR(&parent->cg_mask, &child->cg_mask);
- 587 parent->cg_count += child->cg_count;
- 588 }
- 589
- 590 return (start);
- 591 }
复制代码 |
|