요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
============
x86 Topology
============
This documents and clarifies the main aspects of x86 topology modelling and
representation in the kernel. Update/change when doing changes to the
respective code.
The architecture-agnostic topology definitions are in
Documentation/admin-guide/cputopology.rst. This file holds x86-specific
differences/specialities which must not necessarily apply to the generic
definitions. Thus, the way to read up on Linux topology on x86 is to start
with the generic one and look at this one in parallel for the x86 specifics.
Needless to say, code should use the generic functions - this file is *only*
here to *document* the inner workings of x86 topology.
Started by Thomas Gleixner <tglx@linutronix.de> and Borislav Petkov <bp@alien8.de>.
The main aim of the topology facilities is to present adequate interfaces to
code which needs to know/query/use the structure of the running system wrt
threads, cores, packages, etc.
The kernel does not care about the concept of physical sockets because a
socket has no relevance to software. It's an electromechanical component. In
the past a socket always contained a single package (see below), but with the
advent of Multi Chip Modules (MCM) a socket can hold more than one package. So
there might be still references to sockets in the code, but they are of
historical nature and should be cleaned up.
The topology of a system is described in the units of:
- packages
- cores
- threads
Package
=======
Packages contain a number of cores plus shared resources, e.g. DRAM
controller, shared caches etc.
Modern systems may also use the term 'Die' for package.
AMD nomenclature for package is 'Node'.
Package-related topology information in the kernel:
- topology_num_threads_per_package()
The number of threads in a package.
- topology_num_cores_per_package()
The number of cores in a package.
- topology_max_dies_per_package()
The maximum number of dies in a package.
- cpuinfo_x86.topo.die_id:
The physical ID of the die.
- cpuinfo_x86.topo.pkg_id:
The physical ID of the package. This information is retrieved via CPUID
and deduced from the APIC IDs of the cores in the package.
Modern systems use this value for the socket. There may be multiple
packages within a socket. This value may differ from topo.die_id.
- cpuinfo_x86.topo.logical_pkg_id:
The logical ID of the package. As we do not trust BIOSes to enumerate the
packages in a consistent way, we introduced the concept of logical package
ID so we can sanely calculate the number of maximum possible packages in
the system and have the packages enumerated linearly.
- topology_max_packages():
The maximum possible number of packages in the system. Helpful for per
package facilities to preallocate per package information.
- cpuinfo_x86.topo.llc_id:
- On Intel, the first APIC ID of the list of CPUs sharing the Last Level
Cache
- On AMD, the Node ID or Core Complex ID containing the Last Level
Cache. In general, it is a number identifying an LLC uniquely on the
system.
Cores
=====
A core consists of 1 or more threads. It does not matter whether the threads
are SMT- or CMT-type threads.
AMDs nomenclature for a CMT core is "Compute Unit". The kernel always uses
"core".
Threads
=======
A thread is a single scheduling unit. It's the equivalent to a logical Linux
CPU.
AMDs nomenclature for CMT threads is "Compute Unit Core". The kernel always
uses "thread".
Thread-related topology information in the kernel:
- topology_core_cpumask():
The cpumask contains all online threads in the package to which a thread
belongs.
The number of online threads is also printed in /proc/cpuinfo "siblings."
- topology_sibling_cpumask():
The cpumask contains all online threads in the core to which a thread
belongs.
- topology_logical_package_id():
The logical package ID to which a thread belongs.
- topology_physical_package_id():
The physical package ID to which a thread belongs.
- topology_core_id();
The ID of the core to which a thread belongs. It is also printed in /proc/cpuinfo
"core_id."
- topology_logical_core_id();
The logical core ID to which a thread belongs.
System topology enumeration
===========================
The topology on x86 systems can be discovered using a combination of vendor
specific CPUID leaves which enumerate the processor topology and the cache
hierarchy.
The CPUID leaves in their preferred order of parsing for each x86 vendor is as
follows:
1) AMD
1) CPUID leaf 0x80000026 [Extended CPU Topology] (Core::X86::Cpuid::ExCpuTopology)
The extended CPUID leaf 0x80000026 is the extension of the CPUID leaf 0xB
and provides the topology information of Core, Complex, CCD (Die), and
Socket in each level.
Support for the leaf is discovered by checking if the maximum extended
CPUID level is >= 0x80000026 and then checking if `LogProcAtThisLevel`
in `EBX[15:0]` at a particular level (starting from 0) is non-zero.
The `LevelType` in `ECX[15:8]` at the level provides the topology domain
the level describes - Core, Complex, CCD(Die), or the Socket.
The kernel uses the `CoreMaskWidth` from `EAX[4:0]` to discover the
number of bits that need to be right-shifted from `ExtendedLocalApicId`
in `EDX[31:0]` in order to get a unique Topology ID for the topology
level. CPUs with the same Topology ID share the resources at that level.
CPUID leaf 0x80000026 also provides more information regarding the power
and efficiency rankings, and about the core type on AMD processors with
heterogeneous characteristics.
If CPUID leaf 0x80000026 is supported, further parsing is not required.
2) CPUID leaf 0x0000000B [Extended Topology Enumeration] (Core::X86::Cpuid::ExtTopEnum)
The extended CPUID leaf 0x0000000B is the predecessor on the extended
CPUID leaf 0x80000026 and only describes the core, and the socket domains
of the processor topology.
The support for the leaf is discovered by checking if the maximum supported
CPUID level is >= 0xB and then if `EBX[31:0]` at a particular level
(starting from 0) is non-zero.
The `LevelType` in `ECX[15:8]` at the level provides the topology domain
that the level describes - Thread, or Processor (Socket).
The kernel uses the `CoreMaskWidth` from `EAX[4:0]` to discover the
number of bits that need to be right-shifted from the `ExtendedLocalApicId`
in `EDX[31:0]` to get a unique Topology ID for that topology level. CPUs
sharing the Topology ID share the resources at that level.
If CPUID leaf 0xB is supported, further parsing is not required.
3) CPUID leaf 0x80000008 ECX [Size Identifiers] (Core::X86::Cpuid::SizeId)
If neither the CPUID leaf 0x80000026 nor 0xB is supported, the number of
CPUs on the package is detected using the Size Identifier leaf
0x80000008 ECX.
The support for the leaf is discovered by checking if the supported
extended CPUID level is >= 0x80000008.
The shifts from the APIC ID for the Socket ID is calculated from the
`ApicIdSize` field in `ECX[15:12]` if it is non-zero.
If `ApicIdSize` is reported to be zero, the shift is calculated as the
order of the `number of threads` calculated from `NC` field in
`ECX[7:0]` which describes the `number of threads - 1` on the package.
Unless Extended APIC ID is supported, the APIC ID used to find the
Socket ID is from the `LocalApicId` field of CPUID leaf 0x00000001
`EBX[31:24]`.
The topology parsing continues to detect if Extended APIC ID is
supported or not.
4) CPUID leaf 0x8000001E [Extended APIC ID, Core Identifiers, Node Identifiers]
(Core::X86::Cpuid::{ExtApicId,CoreId,NodeId})
The support for Extended APIC ID can be detected by checking for the
presence of `TopologyExtensions` in `ECX[22]` of CPUID leaf 0x80000001
[Feature Identifiers] (Core::X86::Cpuid::FeatureExtIdEcx).
If Topology Extensions is supported, the APIC ID from `ExtendedApicId`
from CPUID leaf 0x8000001E `EAX[31:0]` should be preferred over that from
`LocalApicId` field of CPUID leaf 0x00000001 `EBX[31:24]` for topology
enumeration.
On processors of Family 0x17 and above that do not support CPUID leaf
0x80000026 or CPUID leaf 0xB, the shifts from the APIC ID for the Core
ID is calculated using the order of `number of threads per core`
calculated using the `ThreadsPerCore` field in `EBX[15:8]` which
describes `number of threads per core - 1`.
On Processors of Family 0x15, the Core ID from `EBX[7:0]` is used as the
`cu_id` (Compute Unit ID) to detect CPUs that share the compute units.
All AMD processors that support the `TopologyExtensions` feature store the
`NodeId` from the `ECX[7:0]` of CPUID leaf 0x8000001E
(Core::X86::Cpuid::NodeId) as the per-CPU `node_id`. On older processors,
the `node_id` was discovered using MSR_FAM10H_NODE_ID MSR (MSR
0x0xc001_100c). The presence of the NODE_ID MSR was detected by checking
`ECX[19]` of CPUID leaf 0x80000001 [Feature Identifiers]
(Core::X86::Cpuid::FeatureExtIdEcx).
2) Intel
On Intel platforms, the CPUID leaves that enumerate the processor
topology are as follows:
1) CPUID leaf 0x1F (V2 Extended Topology Enumeration Leaf)
The CPUID leaf 0x1F is the extension of the CPUID leaf 0xB and provides
the topology information of Core, Module, Tile, Die, DieGrp, and Socket
in each level.
The support for the leaf is discovered by checking if the supported
CPUID level is >= 0x1F and then `EBX[31:0]` at a particular level
(starting from 0) is non-zero.
The `Domain Type` in `ECX[15:8]` of the sub-leaf provides the topology
domain that the level describes - Core, Module, Tile, Die, DieGrp, and
Socket.
The kernel uses the value from `EAX[4:0]` to discover the number of
bits that need to be right shifted from the `x2APIC ID` in `EDX[31:0]`
to get a unique Topology ID for the topology level. CPUs with the same
Topology ID share the resources at that level.
If CPUID leaf 0x1F is supported, further parsing is not required.
2) CPUID leaf 0x0000000B (Extended Topology Enumeration Leaf)
The extended CPUID leaf 0x0000000B is the predecessor of the V2 Extended
Topology Enumeration Leaf 0x1F and only describes the core, and the
socket domains of the processor topology.
The support for the leaf is iscovered by checking if the supported CPUID
level is >= 0xB and then checking if `EBX[31:0]` at a particular level
(starting from 0) is non-zero.
CPUID leaf 0x0000000B shares the same layout as CPUID leaf 0x1F and
should be enumerated in a similar manner.
If CPUID leaf 0xB is supported, further parsing is not required.
3) CPUID leaf 0x00000004 (Deterministic Cache Parameters Leaf)
On Intel processors that support neither CPUID leaf 0x1F, nor CPUID leaf
0xB, the shifts for the SMT domains is calculated using the number of
CPUs sharing the L1 cache.
Processors that feature Hyper-Threading is detected using `EDX[28]` of
CPUID leaf 0x1 (Basic CPUID Information).
The order of `Maximum number of addressable IDs for logical processors
sharing this cache` from `EAX[25:14]` of level-0 of CPUID 0x4 provides
the shifts from the APIC ID required to compute the Core ID.
The APIC ID and Package information is computed using the data from
CPUID leaf 0x1.
4) CPUID leaf 0x00000001 (Basic CPUID Information)
The mask and shifts to derive the Physical Package (socket) ID is
computed using the `Maximum number of addressable IDs for logical
processors in this physical package` from `EBX[23:16]` of CPUID leaf
0x1.
The APIC ID on the legacy platforms is derived from the `Initial APIC
ID` field from `EBX[31:24]` of CPUID leaf 0x1.
3) Centaur and Zhaoxin
Similar to Intel, Centaur and Zhaoxin use a combination of CPUID leaf
0x00000004 (Deterministic Cache Parameters Leaf) and CPUID leaf 0x00000001
(Basic CPUID Information) to derive the topology information.
System topology examples
========================
.. note::
The alternative Linux CPU enumeration depends on how the BIOS enumerates the
threads. Many BIOSes enumerate all threads 0 first and then all threads 1.
That has the "advantage" that the logical Linux CPU numbers of threads 0 stay
the same whether threads are enabled or not. That's merely an implementation
detail and has no practical impact.
1) Single Package, Single Core::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
2) Single Package, Dual Core
a) One thread per core::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-> [core 1] -> [thread 0] -> Linux CPU 1
b) Two threads per core::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-> [thread 1] -> Linux CPU 1
-> [core 1] -> [thread 0] -> Linux CPU 2
-> [thread 1] -> Linux CPU 3
Alternative enumeration::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-> [thread 1] -> Linux CPU 2
-> [core 1] -> [thread 0] -> Linux CPU 1
-> [thread 1] -> Linux CPU 3
AMD nomenclature for CMT systems::
[node 0] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 0
-> [Compute Unit Core 1] -> Linux CPU 1
-> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 2
-> [Compute Unit Core 1] -> Linux CPU 3
4) Dual Package, Dual Core
a) One thread per core::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-> [core 1] -> [thread 0] -> Linux CPU 1
[package 1] -> [core 0] -> [thread 0] -> Linux CPU 2
-> [core 1] -> [thread 0] -> Linux CPU 3
b) Two threads per core::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-> [thread 1] -> Linux CPU 1
-> [core 1] -> [thread 0] -> Linux CPU 2
-> [thread 1] -> Linux CPU 3
[package 1] -> [core 0] -> [thread 0] -> Linux CPU 4
-> [thread 1] -> Linux CPU 5
-> [core 1] -> [thread 0] -> Linux CPU 6
-> [thread 1] -> Linux CPU 7
Alternative enumeration::
[package 0] -> [core 0] -> [thread 0] -> Linux CPU 0
-> [thread 1] -> Linux CPU 4
-> [core 1] -> [thread 0] -> Linux CPU 1
-> [thread 1] -> Linux CPU 5
[package 1] -> [core 0] -> [thread 0] -> Linux CPU 2
-> [thread 1] -> Linux CPU 6
-> [core 1] -> [thread 0] -> Linux CPU 3
-> [thread 1] -> Linux CPU 7
AMD nomenclature for CMT systems::
[node 0] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 0
-> [Compute Unit Core 1] -> Linux CPU 1
-> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 2
-> [Compute Unit Core 1] -> Linux CPU 3
[node 1] -> [Compute Unit 0] -> [Compute Unit Core 0] -> Linux CPU 4
-> [Compute Unit Core 1] -> Linux CPU 5
-> [Compute Unit 1] -> [Compute Unit Core 0] -> Linux CPU 6
-> [Compute Unit Core 1] -> Linux CPU 7
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
x86 topology 모델의 범위
1-38이 문서는 `SPDX-License-Identifier: GPL-2.0`으로 배포됩니다. kernel에서 x86 topology를 model하고 표현하는 주요 측면을 문서화하고 명확히 설명합니다. 관련 code를 변경할 때 이 문서도 갱신해야 합니다.
architecture-independent topology 정의는 `Documentation/admin-guide/cputopology.rst`에 있습니다. 이 문서는 generic 정의에 반드시 적용되지는 않는 x86-specific 차이와 특성을 다룹니다. Linux x86 topology를 이해하려면 generic 문서를 먼저 읽고 x86-specific 내용은 이 문서와 나란히 확인해야 합니다.
code에서는 generic function을 사용해야 합니다. 이 문서는 x86 topology의 내부 동작을 문서화하기 위한 것일 뿐입니다.
Thomas Gleixner `<tglx@linutronix.de>`와 Borislav Petkov `<bp@alien8.de>`가 이 문서를 시작했습니다.
topology facility의 주 목적은 실행 중인 system의 thread, core, package 등의 구조를 알아야 하거나 query·사용해야 하는 code에 적절한 interface를 제공하는 것입니다.
kernel은 physical socket 개념을 중요하게 여기지 않습니다. socket은 software와 무관한 electromechanical component입니다. 과거에는 socket 하나가 항상 package 하나를 담았지만 Multi Chip Modules(MCM)가 등장하면서 socket 하나에 package가 여러 개 들어갈 수 있게 됐습니다. code에 남은 socket 참조는 역사적인 것이며 정리해야 합니다.
system topology는 다음 단위로 설명합니다.
- package
- core
- thread
package와 kernel topology 정보
39-94package는 여러 core와 DRAM controller, shared cache 같은 shared resource를 포함합니다. 현대 system에서는 package를 `Die`라고 부르기도 하며 AMD 명칭은 `Node`입니다.
kernel의 package 관련 topology 정보는 다음과 같습니다.
| interface 또는 field | 의미 |
|---|---|
| `topology_num_threads_per_package()` | package에 포함된 thread 수입니다. |
| `topology_num_cores_per_package()` | package에 포함된 core 수입니다. |
| `topology_max_dies_per_package()` | package 하나에 들어갈 수 있는 최대 die 수입니다. |
| `cpuinfo_x86.topo.die_id` | die의 physical ID입니다. |
| `cpuinfo_x86.topo.pkg_id` | package의 physical ID입니다. CPUID로 얻고 package 안 core의 APIC ID에서 유도합니다. 현대 system은 이 값을 socket에 사용하지만 socket 하나에 package가 여러 개 있을 수 있어 `topo.die_id`와 다를 수 있습니다. |
| `cpuinfo_x86.topo.logical_pkg_id` | package의 logical ID입니다. BIOS가 package를 일관되게 enumerate한다고 신뢰할 수 없으므로, 최대 possible package 수를 합리적으로 계산하고 package를 선형으로 enumerate하기 위해 도입했습니다. |
| `topology_max_packages()` | system에 존재할 수 있는 최대 package 수입니다. package별 facility가 정보를 미리 allocate할 때 유용합니다. |
| `cpuinfo_x86.topo.llc_id` | Intel에서는 Last Level Cache를 공유하는 CPU 목록의 첫 APIC ID입니다. AMD에서는 LLC를 포함하는 Node ID 또는 Core Complex ID이며, 일반적으로 system에서 LLC 하나를 고유하게 식별하는 값입니다. |
core와 thread
95-143core는 하나 이상의 thread로 구성됩니다. thread가 SMT type인지 CMT type인지는 중요하지 않습니다. AMD는 CMT core를 `Compute Unit`이라고 부르지만 kernel은 항상 `core`라는 용어를 사용합니다.
thread는 단일 scheduling unit이며 logical Linux CPU와 같습니다. AMD는 CMT thread를 `Compute Unit Core`라고 부르지만 kernel은 항상 `thread`라고 부릅니다.
kernel의 thread 관련 topology 정보는 다음과 같습니다.
| interface | 의미 |
|---|---|
| `topology_core_cpumask()` | thread가 속한 package의 online thread를 모두 포함하는 cpumask입니다. online thread 수는 `/proc/cpuinfo`의 `siblings`에도 출력됩니다. |
| `topology_sibling_cpumask()` | thread가 속한 core의 online thread를 모두 포함하는 cpumask입니다. |
| `topology_logical_package_id()` | thread가 속한 logical package ID입니다. |
| `topology_physical_package_id()` | thread가 속한 physical package ID입니다. |
| `topology_core_id()` | thread가 속한 core ID입니다. `/proc/cpuinfo`의 `core_id`에도 출력됩니다. |
| `topology_logical_core_id()` | thread가 속한 logical core ID입니다. |
AMD CPUID 0x80000026 enumeration
144-179x86 system topology는 processor topology와 cache hierarchy를 enumerate하는 vendor-specific CPUID leaf 조합으로 탐색합니다. 각 vendor에 대해 아래 우선순위로 CPUID leaf를 parse합니다.
AMD에서 첫 번째 선택은 CPUID leaf `0x80000026` Extended CPU Topology(`Core::X86::Cpuid::ExCpuTopology`)입니다. 이 extended leaf는 CPUID leaf `0xB`를 확장하며 level마다 Core, Complex, CCD(Die), Socket topology 정보를 제공합니다.
maximum extended CPUID level이 `>= 0x80000026`인지 확인한 뒤 0부터 시작하는 특정 level의 `EBX[15:0]`에 있는 `LogProcAtThisLevel`이 0이 아닌지 검사해 지원 여부를 판별합니다.
해당 level의 `ECX[15:8]`에 있는 `LevelType`은 그 level이 설명하는 topology domain이 Core, Complex, CCD(Die), Socket 중 무엇인지 알려 줍니다.
kernel은 `EAX[4:0]`의 `CoreMaskWidth`로 `EDX[31:0]`의 `ExtendedLocalApicId`를 몇 bit right shift해야 해당 topology level의 고유 Topology ID를 얻는지 계산합니다. 같은 Topology ID를 가진 CPU는 그 level의 resource를 공유합니다.
CPUID leaf `0x80000026`은 heterogeneous characteristic을 가진 AMD processor에서 power·efficiency ranking과 core type 정보도 제공합니다. 이 leaf를 지원하면 추가 parsing은 필요하지 않습니다.
AMD CPUID 0xB와 0x80000008 fallback
180-224AMD의 두 번째 선택은 CPUID leaf `0x0000000B` Extended Topology Enumeration(`Core::X86::Cpuid::ExtTopEnum`)입니다. `0x80000026`의 predecessor이며 processor topology의 core와 socket domain만 설명합니다.
maximum supported CPUID level이 `>= 0xB`인지 확인하고 0부터 시작하는 특정 level의 `EBX[31:0]`이 0이 아닌지 검사해 지원 여부를 판별합니다. 그 level의 `ECX[15:8]`에 있는 `LevelType`은 Thread 또는 Processor(Socket) topology domain을 나타냅니다.
kernel은 `EAX[4:0]`의 `CoreMaskWidth`로 `EDX[31:0]`의 `ExtendedLocalApicId`를 right shift할 bit 수를 알아내고 해당 topology level의 고유 Topology ID를 얻습니다. 같은 Topology ID를 공유하는 CPU는 해당 level의 resource도 공유합니다. CPUID leaf `0xB`를 지원하면 추가 parsing은 필요하지 않습니다.
`0x80000026`과 `0xB`를 모두 지원하지 않으면 세 번째로 CPUID leaf `0x80000008 ECX` Size Identifiers(`Core::X86::Cpuid::SizeId`)를 사용해 package의 CPU 수를 감지합니다. supported extended CPUID level이 `>= 0x80000008`이면 이 leaf를 지원합니다.
`ECX[15:12]`의 `ApicIdSize`가 0이 아니면 이 field로 APIC ID에서 Socket ID를 얻기 위한 shift를 계산합니다. `ApicIdSize`가 0이면 `ECX[7:0]`의 `NC` field에서 계산한 `number of threads`의 order를 shift로 사용합니다. `NC`는 package의 `number of threads - 1`을 나타냅니다.
Extended APIC ID를 지원하지 않으면 Socket ID를 찾는 APIC ID로 CPUID leaf `0x00000001`의 `EBX[31:24]`에 있는 `LocalApicId`를 사용합니다. 이후 topology parsing은 Extended APIC ID 지원 여부를 확인하기 위해 계속됩니다.
AMD Extended APIC ID와 Node ID
225-255네 번째 AMD source는 CPUID leaf `0x8000001E` Extended APIC ID, Core Identifiers, Node Identifiers(`Core::X86::Cpuid::{ExtApicId,CoreId,NodeId}`)입니다.
CPUID leaf `0x80000001` Feature Identifiers(`Core::X86::Cpuid::FeatureExtIdEcx`)의 `ECX[22]`에 `TopologyExtensions`가 있는지 확인해 Extended APIC ID 지원 여부를 감지합니다.
Topology Extensions를 지원하면 topology enumeration에서 CPUID leaf `0x00000001`의 `EBX[31:24]`에 있는 `LocalApicId`보다 CPUID leaf `0x8000001E`의 `EAX[31:0]`에 있는 `ExtendedApicId`를 우선해야 합니다.
CPUID leaf `0x80000026`이나 `0xB`를 지원하지 않는 Family `0x17` 이상 processor에서는 `EBX[15:8]`의 `ThreadsPerCore`로 계산한 `number of threads per core`의 order를 사용해 APIC ID에서 Core ID를 얻는 shift를 계산합니다. 이 field는 `number of threads per core - 1`을 나타냅니다.
Family `0x15` processor에서는 `EBX[7:0]`의 Core ID를 `cu_id`(Compute Unit ID)로 사용해 compute unit을 공유하는 CPU를 감지합니다.
`TopologyExtensions`를 지원하는 모든 AMD processor는 CPUID leaf `0x8000001E`(`Core::X86::Cpuid::NodeId`)의 `ECX[7:0]`에 있는 `NodeId`를 per-CPU `node_id`로 저장합니다.
구형 processor에서는 `MSR_FAM10H_NODE_ID` MSR(`0x0xc001_100c`)로 `node_id`를 탐색했습니다. NODE_ID MSR의 존재 여부는 CPUID leaf `0x80000001` Feature Identifiers의 `ECX[19]`를 확인해 감지했습니다.
Intel CPUID 0x1F와 0xB enumeration
256-298Intel platform에서 첫 번째 선택은 CPUID leaf `0x1F` V2 Extended Topology Enumeration Leaf입니다. CPUID leaf `0xB`를 확장하며 level마다 Core, Module, Tile, Die, DieGrp, Socket topology 정보를 제공합니다.
supported CPUID level이 `>= 0x1F`인지 확인하고 0부터 시작하는 특정 level의 `EBX[31:0]`이 0이 아닌지 검사해 지원 여부를 판별합니다.
sub-leaf의 `ECX[15:8]`에 있는 `Domain Type`은 그 level이 Core, Module, Tile, Die, DieGrp, Socket 중 어떤 topology domain을 설명하는지 알려 줍니다.
kernel은 `EAX[4:0]` 값으로 `EDX[31:0]`의 `x2APIC ID`를 몇 bit right shift해야 해당 topology level의 고유 Topology ID를 얻는지 계산합니다. 같은 Topology ID를 가진 CPU는 그 level의 resource를 공유합니다. CPUID leaf `0x1F`를 지원하면 추가 parsing은 필요하지 않습니다.
두 번째 선택인 CPUID leaf `0x0000000B` Extended Topology Enumeration Leaf는 V2 leaf `0x1F`의 predecessor이며 processor topology의 core와 socket domain만 설명합니다.
supported CPUID level이 `>= 0xB`인지 확인한 뒤 특정 level의 `EBX[31:0]`이 0이 아닌지 검사해 지원 여부를 판별합니다. CPUID leaf `0x0000000B`는 `0x1F`와 layout이 같으므로 같은 방식으로 enumerate해야 합니다. `0xB`를 지원하면 추가 parsing은 필요하지 않습니다.
Intel fallback과 Centaur·Zhaoxin
299-334Intel processor가 CPUID leaf `0x1F`와 `0xB`를 모두 지원하지 않으면 세 번째로 CPUID leaf `0x00000004` Deterministic Cache Parameters Leaf를 사용합니다. SMT domain의 shift는 L1 cache를 공유하는 CPU 수로 계산합니다.
Hyper-Threading을 제공하는 processor는 CPUID leaf `0x1` Basic CPUID Information의 `EDX[28]`로 감지합니다. CPUID `0x4` level 0의 `EAX[25:14]`에 있는 `Maximum number of addressable IDs for logical processors sharing this cache`의 order가 APIC ID에서 Core ID를 계산할 때 필요한 shift를 제공합니다.
APIC ID와 package 정보는 CPUID leaf `0x1`의 data로 계산합니다. physical package(socket) ID를 유도하는 mask와 shift는 CPUID leaf `0x1`의 `EBX[23:16]`에 있는 `Maximum number of addressable IDs for logical processors in this physical package`로 계산합니다.
legacy platform의 APIC ID는 CPUID leaf `0x1`의 `EBX[31:24]`에 있는 `Initial APIC ID` field에서 유도합니다.
Centaur와 Zhaoxin은 Intel과 비슷하게 CPUID leaf `0x00000004` Deterministic Cache Parameters Leaf와 CPUID leaf `0x00000001` Basic CPUID Information을 조합해 topology 정보를 유도합니다.
system topology 구조화 예시
335-421대안 Linux CPU enumeration은 BIOS가 thread를 enumerate하는 방법에 따라 달라집니다. 많은 BIOS는 모든 thread 0을 먼저 enumerate한 뒤 모든 thread 1을 enumerate합니다. 그러면 thread 활성화 여부와 관계없이 thread 0의 logical Linux CPU number가 유지된다는 `장점`이 있지만, 이는 구현 세부 사항일 뿐 실제 영향은 없습니다.
package 하나, core 하나, thread 하나인 최소 topology입니다.
각 core에 thread가 하나씩 있는 기본 enumeration입니다.
core별로 두 thread를 연속 enumerate하는 기본 순서입니다.
모든 thread 0을 먼저 배정한 뒤 thread 1을 배정하는 BIOS 순서입니다.
같은 2-core/2-thread 구조를 AMD CMT 명칭으로 나타냈습니다.
package 두 개에 core가 두 개씩 있고 thread가 하나씩 있는 topology입니다.
package, core, thread 순으로 연속 enumerate하는 기본 순서입니다.
모든 package와 core의 thread 0을 먼저 배정한 뒤 thread 1을 배정합니다.
dual-package topology를 AMD CMT의 Node, Compute Unit, Compute Unit Core로 표현했습니다.
요약과 해설
topology.rst:1-421x86 topology는 software에 의미 없는 physical socket 대신 package, core, thread 단위로 표현합니다. kernel은 generic topology API와 `cpuinfo_x86.topo` field로 physical·logical package, die, LLC와 sibling 관계를 제공합니다.
AMD와 Intel은 최신 extended topology CPUID leaf부터 legacy cache·APIC field까지 우선순위대로 parse합니다. 마지막 구조화 표는 BIOS의 thread enumeration 순서와 AMD CMT 명칭이 Linux CPU 번호에 어떻게 대응하는지 보여 줍니다.