CPU 토폴로지 (CPU Topology)
CPU 토폴로지를 커널 스케줄러 관점에서 심층적으로 다룹니다. AMD Chiplet(CCD/CCX), Intel Hybrid(P-core/E-core), ARM DynamIQ/DSU 구조가 커널 topology 탐지와 sched_domain 계층에 반영되는 과정을 분석하고, 비대칭 용량 스케줄링과 NUMA 연계 배치, 관측 도구를 활용한 성능 진단 절차까지 종합적으로 설명합니다.
현대 프로세서는 단순한 "코어 수 × 스레드 수" 이상의 복잡한 계층 구조를 가집니다. AMD의 칩렛(Chiplet), Intel의 타일(Tile)/하이브리드, ARM의 DynamIQ 등 각 아키텍처는 고유한 토폴로지를 형성하며, 리눅스 커널은 이를 정확히 인식하고 스케줄링·메모리 배치에 반영해야 최적 성능을 달성할 수 있습니다.
핵심 요약
- Socket → Die → Core → Thread — CPU의 물리적 계층 구조입니다.
- SMT(Hyper-Threading) — 하나의 코어가 두 개 이상의 논리 CPU로 동작합니다.
- CPUID — 프로세서가 자신의 토폴로지 정보를 소프트웨어에 알려주는 명령어입니다.
- sched_domain — 커널 스케줄러가 토폴로지를 인식하여 부하를 분산하는 계층 구조입니다.
- lscpu / sysfs —
lscpu명령어와/sys/devices/system/cpu/로 토폴로지를 확인합니다. - EAS (Energy-Aware Scheduling) — 이종 코어 시스템에서 성능과 전력의 균형을 맞추는 스케줄러 알고리즘입니다.
- CPU 격리 (isolcpus) — 특정 코어를 OS 스케줄러에서 분리하여 실시간/레이턴시 중요 태스크 전용으로 사용합니다.
- SMT 보안 — Spectre V2, L1TF 등 투기적 실행 취약점은 SMT의 자원 공유 구조와 직접 연관됩니다.
단계별 이해
- 토폴로지 확인 —
lscpu를 실행하여 소켓 수, 코어 수, 스레드 수를 확인합니다./sys/devices/system/cpu/cpu0/topology/에서 상세 정보를 볼 수 있습니다. - 계층 이해 — 같은 코어의 SMT 스레드는 L1 캐시를, 같은 다이의 코어는 L3 캐시를 공유합니다.
이 공유 관계가 스케줄링과 성능에 직접적인 영향을 줍니다.
- 스케줄링 도메인 — 커널은 토폴로지를 기반으로 SMT → Core → LLC → NUMA 순의 스케줄링 도메인을 구성합니다.
부하 균형 시 가까운 도메인부터 먼 도메인 순으로 태스크를 이동합니다.
- 성능 최적화 —
taskset이나 cgroup의 cpuset으로 프로세스를 특정 코어에 바인딩할 수 있습니다.캐시 공유 관계를 고려한 바인딩이 성능 최적화의 핵심입니다.
- 전력 관리 — EAS는 에너지 모델(Energy Model)을 사용해 태스크를 가장 전력 효율적인 코어에 배치합니다.
/sys/kernel/debug/energy_model/로 EM 등록 상태를 확인할 수 있습니다. - 보안과 격리 — SMT 비활성화(
nosmt)나 CPU 격리(isolcpus)로 사이드채널 공격 위험을 줄입니다./sys/devices/system/cpu/vulnerabilities/에서 취약점 완화 상태를 확인합니다.
AMD Chiplet 아키텍처
AMD는 Zen 아키텍처부터 칩렛(Chiplet) 설계를 도입하여, 하나의 패키지에 여러 개의 소형 다이를 조합하는 방식으로 프로세서를 구성합니다. 이 접근법은 제조 수율 향상, 유연한 코어 수 확장, 비용 효율성이라는 장점을 제공합니다.
CCX (Core CompleX)
CCX는 AMD 프로세서의 기본 컴퓨팅 단위로, 일정 수의 코어가 L3 캐시를 공유하는 클러스터입니다.
| 세대 | CCX 구성 | L3 캐시/CCX | 비고 |
|---|---|---|---|
| Zen1 / Zen+ | 4코어/CCX | 8MB | 2 CCX = 1 CCD |
| Zen2 | 4코어/CCX | 16MB | 2 CCX = 1 CCD, L3 2배 증가 |
| Zen3 | 8코어/CCX | 32MB | 1 CCX = 1 CCD, 통합 L3 |
| Zen4 | 8코어/CCX | 32MB | 5nm, AVX-512 |
| Zen5 | 8코어/CCX | 32MB | 프론트엔드 2-wide 디코드 |
CCX 내부의 코어들은 L3 캐시를 공유하므로 inter-core 지연이 매우 낮습니다. 커널의 스케줄링 도메인에서 MC(Multi-Core) 레벨에 해당합니다.
CCD (Core Chiplet Die)
CCD는 코어가 집적된 물리적 다이(die)입니다.
- Zen1/Zen2: 1 CCD = 2 CCX. 같은 CCD 내 두 CCX 간 통신은 Infinity Fabric을 통하지만, IOD를 경유하지 않아 비교적 빠릅니다.
- Zen3 이후: 1 CCD = 1 CCX. CCX-CCD 구분이 사라지고, 8코어 전체가 32MB L3를 공유합니다.
IOD (I/O Die)
IOD는 I/O 기능을 전담하는 별도의 다이입니다. Zen2부터 컴퓨팅 다이(CCD)와 I/O 다이(IOD)를 물리적으로 분리하여, 각각 최적의 공정을 적용합니다.
IOD가 담당하는 주요 기능:
- 메모리 컨트롤러(UMC): DDR4/DDR5 채널 관리. EPYC 9004 기준 12채널
- PCIe 컨트롤러: PCIe Gen4/Gen5 레인
- Infinity Fabric 스위치: CCD 간, 소켓 간 통신 라우팅
- xGMI 링크: 멀티소켓 연결 (socket-to-socket)
- 보안 프로세서(PSP): AMD Platform Security Processor
/* 커널에서 AMD IOD 토폴로지 확인 (dmesg) */
// [ 0.123456] node 0 deferred pages: init 2097152
// AMD EPYC 9654 (Genoa): 12 UMC channels, 128 PCIe Gen5 lanes
/* arch/x86/kernel/cpu/amd.c - 토폴로지 파싱 */
static void amd_get_topology(struct cpuinfo_x86 *c)
{
int cpu = c->cpu_index;
/* CPUID Fn8000_001E: Node/Core/Thread 토폴로지 */
if (c->extended_cpuid_level >= 0x8000001e) {
u32 eax, ebx, ecx, edx;
cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
c->cpu_core_id = eax; /* Compute Unit ID */
c->cpu_die_id = ecx & 0xff; /* Node(CCD) ID */
c->threads_per_core = ((ebx >> 8) & 0xff) + 1;
}
}
Infinity Fabric
Infinity Fabric(IF)는 AMD의 온-다이/온-패키지/인터-소켓 인터커넥트입니다. Scalable Data Fabric(SDF)과 Scalable Control Fabric(SCF)으로 구성됩니다.
| 통신 경로 | 경유 | 대략적 지연 | 대역폭 |
|---|---|---|---|
| intra-CCX (코어 간) | L3 직접 | ~10-15ns | L3 대역폭 |
| inter-CCX, same CCD (Zen1/2) | IF on-die | ~25-40ns | IF 대역폭 |
| inter-CCD (same socket) | IF → IOD → IF | ~50-80ns | IF 대역폭 |
| inter-socket | xGMI | ~120-180ns | xGMI 대역폭 |
NPS (Nodes Per Socket)
AMD EPYC 프로세서는 NPS(Nodes Per Socket) BIOS 설정으로 단일 소켓 내부를 여러 NUMA 노드로 분할합니다.
| 모드 | NUMA 노드/소켓 | CCD→메모리 매핑 | 적합한 워크로드 |
|---|---|---|---|
| NPS1 | 1 | 모든 CCD → 전체 메모리 채널 | 범용, 대용량 메모리 풀 |
| NPS2 | 2 | CCD 절반씩 → 메모리 채널 절반 | VM 2개 분할 |
| NPS4 | 4 | CCD 1/4씩 → 메모리 채널 1/4 | HPC, 지연 최소화 |
# NPS 모드 확인 (NUMA 노드 수로 추정)
$ numactl --hardware
available: 4 nodes (0-3) # NPS4 모드
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 64169 MB
node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
node 1 size: 64256 MB
...
node distances:
node 0 1 2 3
0: 10 12 12 12
1: 12 10 12 12
2: 12 12 10 12
3: 12 12 12 10
Zen 세대별 진화
| 세대 | 공정 | CCX/CCD | 최대 CCD | L3/CCX | IF 세대 | 메모리 |
|---|---|---|---|---|---|---|
| Zen1 | 14nm | 2 CCX(4c)/CCD | 4 (EPYC 7001) | 8MB | IF 1.0 | DDR4-2666 |
| Zen2 | 7nm CCD / 14nm IOD | 2 CCX(4c)/CCD | 8 (EPYC 7002) | 16MB | IF 2.0 | DDR4-3200 |
| Zen3 | 7nm | 1 CCX(8c)=CCD | 8 (EPYC 7003) | 32MB | IF 3.0 | DDR4-3200 |
| Zen4 | 5nm CCD / 6nm IOD | 1 CCX(8c)=CCD | 12 (EPYC 9004) | 32MB | IF 4.0 | DDR5-4800 |
| Zen5 | 4nm/3nm | 1 CCX(8c)=CCD | 16 (EPYC 9005) | 32MB | IF 5.0 | DDR5-6000 |
EPYC / Ryzen / Threadripper 비교
| 제품군 | 소켓 | 최대 CCD | 최대 코어 | 메모리 채널 | PCIe 레인 | NPS 지원 |
|---|---|---|---|---|---|---|
| EPYC 9004 (Genoa) | SP5 | 12 | 96 | 12×DDR5 | 128 Gen5 | NPS1/2/4 |
| EPYC 9005 (Turin) | SP5 | 16 | 128 | 12×DDR5 | 128 Gen5 | NPS1/2/4 |
| Threadripper 7000 | sTR5 | 8 | 64 | 4×DDR5 | 48 Gen5 | NPS1 |
| Ryzen 9000 (Granite Ridge) | AM5 | 2 | 16 | 2×DDR5 | 28 Gen5 | N/A |
| Ryzen 9000 (Strix Point) | FP8 | 1 (모놀리식) | 12 | LPDDR5X | 내장 | N/A |
Intel 아키텍처
2.1 Tile 아키텍처
Intel은 서버 프로세서(Sapphire Rapids, Granite Rapids)에서 EMIB(Embedded Multi-die Interconnect Bridge)를 사용한 타일 기반 설계를 도입했습니다.
- Sapphire Rapids (SPR): 4타일 구성, 각 타일에 코어 + LLC 슬라이스 + UPI + PCIe. 최대 60코어.
- Granite Rapids (GNR): Performance-core(P-core) 전용 3타일 + I/O 타일, 최대 128코어.
- SNC(Sub-NUMA Clustering): 타일 경계를 따라 소켓 내부를 NUMA 노드로 분할. SNC2(2 NUMA) 또는 SNC4(4 NUMA) 모드로 지연 최소화.
클라이언트 프로세서에서도 Meteor Lake부터 분리형 타일 설계(Foveros 3D 패키징)가 도입되어, Compute/SoC/GFX/IOE 타일로 구성됩니다(자세한 내용은 2.12 분리형 SoC 설계 참조).
# SNC 모드 확인 (Sapphire Rapids, SNC4)
$ lscpu | grep -i numa
NUMA node(s): 4
NUMA node0 CPU(s): 0-14,60-74
NUMA node1 CPU(s): 15-29,75-89
NUMA node2 CPU(s): 30-44,90-104
NUMA node3 CPU(s): 45-59,105-119
2.2 P-core / E-core 하이브리드
Alder Lake(12세대)부터 클라이언트 프로세서에 하이브리드 아키텍처를 도입했습니다. 이는 단일 다이(또는 패키지)에 고성능 P-core(Performance)와 고효율 E-core(Efficient)를 혼합 배치하는 설계입니다.
하이브리드 도입 배경:
- 전력 효율: 무어의 법칙 둔화로 단순히 코어를 늘리는 것만으로는 성능/와트 개선이 한계에 도달. 경량 워크로드를 소형 코어로 처리하면 전체 패키지 전력을 대폭 절감
- 열 제약: 데스크탑 65~125W, 랩탑 15~45W TDP 내에서 코어 수 확장. E-core는 P-core 대비 1/4~1/5 면적으로 동일 다이에 더 많은 코어 집적 가능
- 멀티태스킹 최적화: 포그라운드(게임, 컴파일)는 P-core, 백그라운드(인덱싱, 업데이트)는 E-core에서 처리하여 체감 성능 향상
| 특성 | P-core (Performance) | E-core (Efficient) |
|---|---|---|
| 마이크로아키텍처 | Golden Cove / Raptor Cove / Lion Cove | Gracemont / Crestmont / Skymont |
| SMT | 지원 (2 스레드/코어) | 미지원 (1 스레드/코어) |
| L2 캐시 | 1.25~3MB/코어 (개별) | 2~4MB/4코어 클러스터 (공유) |
| ISA 차이 | AVX-512 (세대별 상이) | AVX-512 미지원 |
| IPC | 높음 | P-core 대비 ~70-85% (세대별 향상) |
| 전력 효율 | 성능 우선 | 와트당 성능 우수 |
| 다이 면적 | 크다 (~4mm² @Intel 7) | 작다 (~1mm² @Intel 7) |
E-core 클러스터 토폴로지: E-core 4개가 하나의 클러스터(Cluster)를 이루며, 클러스터 내 L2 캐시를 공유합니다. 커널에서는 이 클러스터를 CL(Cluster) 스케줄링 도메인 레벨로 인식합니다. 같은 클러스터 내 E-core 간 데이터 교환은 L2를 통해 이루어지므로 지연이 매우 낮지만, 다른 클러스터의 E-core나 P-core와의 통신은 링 버스/LLC를 경유합니다.
2.3 P-core 마이크로아키텍처
P-core는 Intel의 고성능 마이크로아키텍처 계열로, 넓은 프론트엔드와 깊은 OoO(Out-of-Order) 파이프라인을 특징으로 합니다.
| 마이크로아키텍처 | 세대 | 디코드 폭 | ROB 크기 | 실행 포트 | L2/코어 | 주요 특징 |
|---|---|---|---|---|---|---|
| Golden Cove | Alder Lake (12th) | 6-wide | 512 | 12 | 1.25MB | 최초 하이브리드 P-core, 10-wide alloc |
| Raptor Cove | Raptor Lake (13th) | 6-wide | 512 | 12 | 2MB | L2 확대, 클럭 개선 (최대 6.0GHz) |
| Redwood Cove | Meteor Lake (Core Ultra 1) | 6-wide | 512 | 12 | 2MB | 전력 게이팅 향상, Compute tile 분리 |
| Lion Cove | Arrow/Lunar Lake (Core Ultra 2) | 8-wide | 576 | 12 | 2.5~3MB | 디코드 폭 확대, AVX-512 복원(P-core 한정) |
Golden Cove (Alder Lake) — P-core의 첫 하이브리드 설계입니다. 6-wide 디코드, 512-entry ROB(Reorder Buffer), 12개 실행 포트를 갖추어 이전 세대(Cypress Cove) 대비 ~19% IPC 향상을 달성했습니다. L2 캐시는 코어당 1.25MB이며, 프리페칭 개선과 브랜치 예측기 확장이 적용되었습니다.
Raptor Cove (Raptor Lake) — Golden Cove의 파이프라인을 유지하면서 L2를 2MB로 확대하고, 클럭 스케일링을 개선하여 최대 부스트 6.0GHz를 달성했습니다. 캐시 프리페칭 개선으로 메모리 집약적 워크로드에서 추가 IPC 향상이 있습니다.
Redwood Cove (Meteor Lake) — 분리형 Compute tile(Intel 4 공정)에 탑재됩니다. 파이프라인은 Golden Cove와 유사하지만, 타일 단위 전력 게이팅으로 유휴 시 P-core 타일 전체를 전력 차단할 수 있어 배터리 수명이 크게 개선됩니다.
Lion Cove (Arrow Lake / Lunar Lake) — 디코드 폭을 8-wide로 확대하고 ROB를 576개로 늘렸습니다. 가장 주목할 변화는 P-core 한정으로 AVX-512를 복원한 것입니다. E-core에서는 여전히 AVX-512를 지원하지 않으므로, 커널은 ISA 비대칭성을 처리해야 합니다(2.9 ISA 호환성 참조).
2.4 E-core 마이크로아키텍처
E-core는 "느린 코어"가 아닌 "효율 코어"입니다. Skylake급 IPC를 달성하면서 훨씬 낮은 전력과 작은 다이 면적으로 동작하도록 설계되었습니다.
| 마이크로아키텍처 | 세대 | 디코드 | 클러스터 구성 | L2/클러스터 | IPC (vs P-core) |
|---|---|---|---|---|---|
| Gracemont | Alder Lake / Raptor Lake | 2-wide × 2 파이프 | 4코어/클러스터 | 2MB (ADL) / 4MB (RPL) | ~70% |
| Crestmont | Meteor Lake / Lunar Lake LP | 향상된 프론트엔드 | 4코어/클러스터 | 4MB | ~80-85% |
| Skymont | Arrow Lake / Lunar Lake | 추가 IPC 개선 | 4코어/클러스터 | 4MB | ~85% |
Gracemont (Alder Lake/Raptor Lake) — 2개의 독립적인 2-wide 디코드 파이프를 사용하는 독특한 클러스터 구조입니다. SMT를 지원하지 않는 대신 코어 자체를 소형화하여, P-core 1개의 다이 면적에 E-core 4개를 집적합니다. 4코어가 하나의 클러스터를 이루어 L2 캐시를 공유하며, 이 공유 구조가 커널에서 CL(Cluster) 스케줄링 도메인을 형성합니다.
Crestmont (Meteor Lake) — 프론트엔드 분기 예측 개선과 백엔드 실행 유닛 확장으로 IPC가 P-core 대비 ~80-85% 수준으로 향상되었습니다. Meteor Lake SoC tile의 LP E-core(2.5절 참조)로도 사용되며, 이 경우 낮은 클럭(1~2GHz)으로 동작합니다.
Skymont (Arrow Lake / Lunar Lake) — 추가적인 IPC 개선으로 Gracemont 대비 최대 ~38% 향상을 달성했습니다. 벡터 처리 능력도 강화되어 256-bit SIMD 처리량이 증가했습니다.
2.5 LP E-core와 3계층 코어
Meteor Lake부터 SoC tile에 LP E-core(Low-Power Efficient core)가 추가되어, 프로세서가 3계층 코어 구조를 갖게 되었습니다.
| 계층 | 코어 타입 | 위치 | 특성 | 용도 |
|---|---|---|---|---|
| 1 (최고성능) | P-core | Compute tile | 높은 클럭, 넓은 파이프라인 | 게임, 컴파일, 싱글스레드 집약 |
| 2 (효율) | E-core | Compute tile | 중간 클럭, 4코어 클러스터 | 멀티스레드, 백그라운드 |
| 3 (초저전력) | LP E-core | SoC tile | 1~2GHz, 2코어 구성 | 경량 작업, 대기 시 유지 |
LP E-core의 특성:
- 위치: SoC tile(TSMC N6 공정)에 위치하여, Compute tile이 전력 차단(power gate)된 상태에서도 독립 동작 가능
- 구성: 2코어, Crestmont 마이크로아키텍처 기반이지만 낮은 클럭(1~2GHz)으로 동작
- 시나리오: 메신저 알림, 음악 재생, 시스템 유지 관리 등 Compute tile을 깨울 필요 없는 경량 작업
- Lunar Lake: LP E-core 2코어(Crestmont)가 SoC tile에 위치, Compute tile에는 P-core 4개 + E-core 4개
커널 영향: 3계층 코어 구조에서 스케줄러는 추가적인 우선순위 레벨을 관리해야 합니다. ITMT(2.8절)에서 LP E-core는 가장 낮은 우선순위를 받으며, 스케줄링 도메인에서도 별도의 Module 레벨로 인식될 수 있습니다.
2.6 세대별 진화
| 세대 | 공정 | P-core | E-core | LP E | P수 | E수 | P-L2 | E-L2/CL | L3 | 메모리 | 설계 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Alder Lake (12th) | Intel 7 | Golden Cove | Gracemont | - | 8 | 8 | 1.25MB | 2MB | 30MB | DDR5-4800 | 모놀리식 |
| Raptor Lake (13th) | Intel 7 | Raptor Cove | Gracemont | - | 8 | 16 | 2MB | 4MB | 36MB | DDR5-5600 | 모놀리식 |
| Meteor Lake (Ultra 1) | Intel 4/N6/N5 | Redwood Cove | Crestmont | Crestmont | 6 | 8 | 2MB | 4MB | 12MB | LPDDR5X | 분리형(Foveros) |
| Arrow Lake (Ultra 2) | TSMC N3/N6 | Lion Cove | Skymont | - | 8 | 16 | 3MB | 4MB | 36MB | DDR5-5600 | 분리형 |
| Lunar Lake (Ultra 2) | TSMC N3/N6 | Lion Cove | Skymont | Crestmont | 4 | 4 | 2.5MB | 4MB | 12MB | LPDDR5X | 분리형 |
2.7 코어 타입 탐지 — CPUID Leaf 0x1A
하이브리드 프로세서에서 커널은 각 논리 CPU가 P-core인지 E-core인지 식별해야 합니다. Intel은 CPUID Leaf 0x1A (Native Model ID Enumeration)를 통해 이 정보를 제공합니다.
| EAX 비트 | 필드 | 값 | 의미 |
|---|---|---|---|
| [31:24] | Core Type | 0x20 | Atom (E-core) |
| [31:24] | Core Type | 0x40 | Core (P-core) |
| [23:0] | Native Model ID | - | 마이크로아키텍처별 고유 ID |
/* arch/x86/kernel/cpu/intel.c — 하이브리드 코어 타입 탐지 */
static void detect_hybrid_cpu(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
if (!cpu_has(c, X86_FEATURE_HYBRID_CPU))
return;
cpuid(0x1a, &eax, &ebx, &ecx, &edx);
/* EAX[31:24] = Core Type
* 0x20 = Intel Atom (E-core)
* 0x40 = Intel Core (P-core) */
c->topo.core_type = (eax >> 24) & 0xff;
c->topo.native_model_id = eax & 0xffffff;
}
/* X86_FEATURE_HYBRID_CPU는 CPUID Leaf 7, ECX bit 15로 탐지
* (CPUID.07H:EDX[15] = Hybrid 지원 여부) */
CPUID 0x1F V2 Extended Topology와의 연동: Leaf 0x1F에서 Module 레벨(level_type=3)을 통해 E-core 클러스터를 식별할 수 있습니다. 같은 Module에 속한 E-core들은 L2를 공유하며, 커널은 이를 CL 스케줄링 도메인으로 매핑합니다.
# 코어 타입 확인 (sysfs)
$ for cpu in /sys/devices/system/cpu/cpu*/topology; do
if [ -f "$cpu/core_type" ]; then
echo "$(basename $(dirname $cpu)): $(cat $cpu/core_type)"
fi
done
cpu0: 64 # 0x40 = P-core (Intel Core)
cpu1: 64
...
cpu16: 32 # 0x20 = E-core (Intel Atom)
cpu17: 32
...
2.8 ITMT 비대칭 스케줄링
ITMT(Intel Turbo Boost Max Technology 3.0)는 코어별 성능 차이를 커널 스케줄러에 반영하는 메커니즘입니다. 하이브리드 프로세서에서 P-core > E-core > LP E-core 우선순위를 설정하여 비대칭 스케줄링을 구현합니다.
/* arch/x86/kernel/itmt.c — ITMT 우선순위 설정 */
/* 코어별 성능 우선순위를 스케줄러에 등록 */
void sched_set_itmt_core_prio(int prio, int cpu)
{
per_cpu(sched_core_priority, cpu) = prio;
}
/* ITMT 활성화 — sched_domain에 SD_ASYM_PACKING 플래그 설정 */
void sched_set_itmt_support(void)
{
sysctl_sched_itmt_enabled = 1;
rebuild_sched_domains();
}
/*
* 동작 원리:
* 1. intel_pstate 또는 HFI 드라이버가 각 코어의 성능 순위를 파악
* 2. sched_set_itmt_core_prio()로 코어별 우선순위 설정
* 예: P-core = 200, E-core = 100, LP E-core = 50
* 3. SD_ASYM_PACKING이 설정된 도메인에서 스케줄러는
* 높은 우선순위 코어를 먼저 채움
* 4. 워크로드가 줄어들면 낮은 우선순위 코어에서 먼저 제거
*/
주요 커널 인터페이스:
/proc/sys/kernel/sched_itmt_enabled: ITMT 활성화/비활성화 (0 또는 1)SD_ASYM_PACKING: 스케줄링 도메인 플래그로, 비대칭 코어 배치 시 우선순위 기반 태스크 이동- HFI 드라이버가
perf_cap값을 ITMT 우선순위로 변환하여, Thread Director의 실시간 판단이 스케줄러에 반영됨
# ITMT 활성 상태 확인
$ cat /proc/sys/kernel/sched_itmt_enabled
1
# 스케줄링 도메인에서 ASYM_PACKING 플래그 확인
$ cat /proc/sys/kernel/sched_domain/cpu0/domain0/flags
... SD_ASYM_PACKING ...
2.9 ISA 호환성
하이브리드 아키텍처의 핵심 과제 중 하나는 P-core와 E-core 간 ISA(Instruction Set Architecture) 차이입니다. 특히 AVX-512가 세대별로 달라지는 점이 커널과 사용자 공간 모두에 영향을 줍니다.
| 세대 | P-core AVX-512 | E-core AVX-512 | OS에 노출 |
|---|---|---|---|
| Alder Lake (12th) | 하드웨어 존재 | 미지원 | E-core 비활성 시 일부 SKU에서 사용 가능 (BIOS) |
| Raptor Lake (13th) | 퓨즈 차단 | 미지원 | 완전 비활성 |
| Meteor Lake | 미지원 | 미지원 | 비활성 |
| Arrow Lake / Lunar Lake | 복원 (지원) | 미지원 | P-core에서만 사용 가능 |
커널의 ISA 처리 원칙 — 최소 공통 분모:
기본적으로 커널은 모든 코어가 지원하는 ISA의 교집합만 사용자 공간에 노출합니다. E-core가 AVX-512를 지원하지 않으면, CPUID를 통해 OS에 AVX-512가 광고되지 않습니다. 따라서 Alder Lake~Meteor Lake에서는 AVX-512를 사용할 수 없습니다.
Arrow Lake+에서의 변화: Lion Cove P-core에서 AVX-512가 복원되었지만, Skymont E-core는 여전히 미지원입니다. Intel은 이 비대칭 ISA를 처리하기 위해:
- AVX-512 명령어가 E-core에서 실행되면
#UD(Undefined Instruction) 예외 발생 - 커널은 AVX-512를 사용하는 스레드를 P-core에 고정(pin)하거나, 사용자 공간에서
sched_setaffinity()로 P-core만 지정해야 함 - CPUID Leaf 0x1A의 코어 타입 정보와 연동하여 ISA 능력을 코어별로 구분
taskset이나 sched_setaffinity()로 P-core에 명시적으로 고정하지 않으면, 스케줄러가 E-core로 마이그레이션할 때 SIGILL이 발생할 수 있습니다. 커널 6.x에서 이를 자동 처리하는 패치가 진행 중이지만, 현재는 사용자 공간에서 주의가 필요합니다.
2.10 Intel Thread Director
Intel Thread Director(ITD)는 하드웨어 기반의 스레드 분류기로, 각 스레드의 명령어 mix를 실시간 분석하여 P-core/E-core 배치를 최적화합니다.
IPC 클래스 분류: Thread Director는 스레드가 실행하는 명령어 패턴을 모니터링하여 4개 IPC 클래스 중 하나를 할당합니다:
| IPC 클래스 | 명령어 특성 | 권장 코어 | 예시 |
|---|---|---|---|
| Class 0 | 범용 코드 | P-core 또는 E-core | 일반 애플리케이션 |
| Class 1 | 정수 연산 중심 | E-core 충분 | 웹 브라우징, 스크립트 |
| Class 2 | 벡터/SIMD 연산 | P-core 선호 | 미디어 인코딩 |
| Class 3 | FP/AVX 집중 | P-core 강력 선호 | 과학 계산, 게임 물리 |
/* HFI (Hardware Feedback Interface) 테이블 구조 */
struct hfi_cpu_data {
u8 perf_cap; /* 성능 능력: 0(최저)~255(최고) */
u8 ee_cap; /* 에너지 효율: 0(최저)~255(최고) */
};
/*
* 커널 드라이버: drivers/thermal/intel/intel_hfi.c
*
* HFI 테이블은 MMIO 영역에 매핑되며, 인터럽트로 갱신 알림.
* 갱신 주기: 약 ~100ms (워크로드 변화 시 동적 조절)
*
* 열 제한(thermal throttling) 시 perf_cap이 동적으로 감소:
* 정상 → P-core perf_cap=255, E-core perf_cap=128
* 열 제한 → P-core perf_cap=180, E-core perf_cap=100
* 이를 통해 스케줄러가 열 상태에 따라 배치를 자동 조절
*/
static void intel_hfi_process_event(struct work_struct *work)
{
struct hfi_instance *hfi = container_of(work, ...);
/* HFI 테이블에서 각 CPU의 perf_cap/ee_cap 읽기 */
raw_spin_lock_irq(&hfi->table_lock);
memcpy(hfi->local_table, hfi->hw_table, hfi->table_size);
raw_spin_unlock_irq(&hfi->table_lock);
/* ITMT 우선순위 갱신 → 스케줄러에 용량 변경 알림 */
sched_update_cpu_topology();
}
HFI → ITMT → 스케줄러 연동 흐름:
- Thread Director가 IPC 클래스를 계산하여 HFI 테이블에 기록
- HFI 인터럽트 →
intel_hfi_process_event()→ HFI 테이블 복사 perf_cap/ee_cap값을 ITMT 우선순위로 변환 →sched_set_itmt_core_prio()sched_update_cpu_topology()→ 스케줄링 도메인 재구축- CFS 스케줄러가
SD_ASYM_PACKING플래그에 따라 높은 우선순위 코어에 태스크 배치
2.11 캐시 토폴로지
Intel의 LLC(Last-Level Cache)는 슬라이스 형태로 분산되어 있으며, 링 버스 또는 메시 인터커넥트로 연결됩니다.
- 링 버스: 클라이언트 및 초기 서버(~Broadwell). 코어마다 LLC 슬라이스가 링에 연결.
- 메시 인터커넥트: Skylake-SP 이후 서버. 2D 메시에 코어·LLC·Home Agent 분산.
- SNC 모드: 메시를 2~4개 영역으로 분할하여, 각 영역이 로컬 메모리 컨트롤러와 매핑. NUMA 노드로 노출.
2.12 분리형 SoC 설계 — Meteor Lake+
Meteor Lake부터 Intel은 Foveros 3D 패키징을 사용하여 여러 타일을 하나의 패키지에 조합하는 분리형(disaggregated) 설계를 클라이언트 프로세서에 도입했습니다.
4-Tile 구조 (Meteor Lake):
- Compute tile (Intel 4): P-core(Redwood Cove) + E-core(Crestmont) + L3 캐시
- SoC tile (TSMC N6): LP E-core(Crestmont 2코어) + NPU(AI 엔진) + 미디어 엔진 + 디스플레이 엔진
- GFX tile (TSMC N5): Xe-LPG GPU (128 EU)
- IOE tile (TSMC N6): PCIe Gen5, Thunderbolt 4, USB 4, 기타 I/O
각 타일은 독립적인 FIVR(Fully Integrated Voltage Regulator)를 탑재하여 전압/주파수를 개별 제어합니다. Compute tile이 유휴 상태이면 전력을 완전히 차단하고, SoC tile의 LP E-core만으로 경량 작업을 처리할 수 있습니다.
Lunar Lake 변형: GPU를 SoC tile에 통합하고, 메모리(LPDDR5X)를 패키지 위에 직접 적층(Package-on-Package)하여 더 작은 폼팩터를 달성했습니다.
커널 토폴로지 영향:
- CPUID 0x1F에서
Tile레벨(level_type=4)이 보고되어, 커널이 크로스 타일 코어 간 높은 지연을 인식 - Compute tile과 SoC tile의 코어 간 통신은 Foveros 인터커넥트를 경유하므로, 같은 tile 내 코어 간 통신보다 지연이 높음
- 캐시 코히런시: L3는 Compute tile에만 존재하며, LP E-core(SoC tile)는 L3 없이 동작
ARM 아키텍처
big.LITTLE / DynamIQ
ARM은 이기종 멀티프로세싱(HMP)의 선구자입니다.
| 기술 | 세대 | 특징 |
|---|---|---|
| big.LITTLE | 2011~ | big/LITTLE 코어가 별도 클러스터, 클러스터 단위 전환 또는 HMP |
| DynamIQ | 2017~ | 단일 클러스터 내 이종 코어 혼합 가능, DSU 기반 L3 공유 |
DynamIQ에서는 하나의 클러스터에 Cortex-X4 + Cortex-A720 + Cortex-A520 같은 3종 코어를 혼합할 수 있습니다.
DSU (DynamIQ Shared Unit)
DSU는 DynamIQ 클러스터의 핵심 IP로, L3 캐시 관리와 클러스터 내 코히런시를 담당합니다.
- DSU-AE (Automotive Enhanced): 자율주행 등 안전 등급 요구사항 충족
- DSU-110: 최대 8코어, L3 최대 16MB
- DSU-120: 최대 12코어, L3 최대 32MB, 3종 코어 지원
- Snoop Filter를 내장하여 코히런시 트래픽 최적화
CMN (Coherent Mesh Network)
ARM 서버 SoC(Neoverse)에서는 CMN(Coherent Mesh Network)으로 다수의 클러스터를 연결합니다.
| 노드 유형 | 역할 |
|---|---|
| XP (Crosspoint) | 메시 라우터, 패킷 라우팅 |
| RN-F (Request Node - Full) | 코어 클러스터 연결점, 풀 코히런시 |
| HN-F (Home Node - Full) | SLC(System-Level Cache) 슬라이스, 디렉토리 기반 코히런시 |
| SN-F (Slave Node - Full) | 메모리 컨트롤러, PCIe 인터페이스 |
| MN (Miscellaneous Node) | DVM(Distributed Virtual Memory) 브로드캐스트 |
/* ARM CMN PMU 드라이버: drivers/perf/arm-cmn.c
* CMN 메시 토폴로지를 런타임에 탐지 */
static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset)
{
void __iomem *reg;
u64 val;
/* Configuration 영역에서 메시 크기, 노드 수 읽기 */
val = readq_relaxed(cmn->base + CMN_CFGM_INFO_GLOBAL);
cmn->mesh_x = FIELD_GET(CMN_INFO_MESH_X, val);
cmn->mesh_y = FIELD_GET(CMN_INFO_MESH_Y, val);
...
}
Cortex-X/A 시리즈
| 코어 | 등급 | 특징 | 대표 SoC |
|---|---|---|---|
| Cortex-X4/X925 | 초고성능 | 넓은 OoO, 대형 L2 | Snapdragon 8 Gen 3, Dimensity 9300 |
| Cortex-A720/A725 | 고성능 | A78 후속, 균형 잡힌 IPC | 대부분의 플래그십 SoC |
| Cortex-A520 | 효율 | A510 후속, 인오더→아웃오브오더 전환 | 모든 최신 모바일 SoC |
| Neoverse V2/V3 | 서버 | SVE2, 넓은 파이프라인, 대형 캐시 | Graviton 4, Ampere |
| Neoverse N2/N3 | 서버(효율) | 코어 수 확장 최적화 | Graviton 3, Cobalt 100 |
ARM 아키텍처 심화
ARM 비대칭 멀티프로세싱 시스템은 코어 종류별 OPP(Operating Performance Point), 에너지 모델, ACPI PPTT 구조가 복합적으로 맞물립니다. 이 섹션에서는 DynamIQ 클러스터 내부 구조, ACPI PPTT 상세, ARM OPP 커널 구현, CPU 용량 계산 방법을 심화 분석합니다.
DynamIQ 클러스터 내부 구조
DynamIQ 클러스터는 하나의 DSU(DynamIQ Shared Unit)가 최대 12개의 이종 코어를 관리합니다. 각 코어는 독립적인 OPP(Operating Performance Point) 테이블을 가질 수 있어, X4/A720/A520 코어가 동시에 서로 다른 주파수로 동작할 수 있습니다.
| DSU 버전 | 최대 코어 | 최대 L3 | Snoop Filter | 비고 |
|---|---|---|---|---|
| DSU-110 | 8코어 | 16MB | 내장 | A55/A75/A77 기반 SoC |
| DSU-120 | 12코어 | 32MB | 내장 (확장) | X4/A720/A520 혼합, Dimensity 9300+ |
| DSU-AE | 4코어 | 8MB | 내장 | 자율주행 ISO 26262 등급 |
| CMN-600 | 128코어 | — | HN-F 디렉토리 | Neoverse 서버 메시 |
| CMN-700 | 256코어 | — | HN-F 확장 | 최신 서버 SoC (Neoverse V2 기반) |
DynamIQ의 핵심 특징은 독립 전압/주파수 도메인(DVFS Island)입니다. 각 코어(또는 코어 그룹)가 별도의 OPP 테이블을 가지므로, 조성이 다른 코어들이 각자의 최적 주파수에서 동작할 수 있습니다.
ACPI PPTT 상세 구조
PPTT(Processor Properties Topology Table)는 ARM64 ACPI 시스템에서 코어의 계층 구조, 캐시 공유 관계, CPU 능력(capacity)을 기술합니다.
/* drivers/acpi/pptt.c - PPTT 캐시 탐지 */
static struct acpi_pptt_cache *acpi_pptt_find_cache(
struct acpi_table_header *table,
struct acpi_pptt_processor *cpu_node,
int level, int type)
{
struct acpi_pptt_processor *node = cpu_node;
while (node) {
struct acpi_pptt_cache *cache;
cache = acpi_find_cache_node(table, node, level, type);
if (cache)
return cache;
node = fetch_pptt_node(table, node->parent);
}
return NULL;
}
PPTT 계층 레벨과 커널 매핑:
| 레벨 | 의미 | 커널 필드 | 캐시 |
|---|---|---|---|
| 0 (Thread) | SMT 스레드 | cpu_topology[cpu].thread_id | — |
| 1 (Core) | 물리 코어 | cpu_topology[cpu].core_id | L1/L2 공유 |
| 2 (Cluster) | DynamIQ 클러스터 | cpu_topology[cpu].cluster_id | DSU L3 공유 |
| 3 (Package) | SoC 패키지 | cpu_topology[cpu].package_id | SLC(서버) |
OPP 커널 구현
리눅스 OPP(Operating Performance Point) 프레임워크는 각 전압/주파수 쌍을 추상화하여 DVFS를 구현합니다.
/* include/linux/pm_opp.h - OPP 데이터 구조 */
struct dev_pm_opp {
struct list_head node;
bool available;
unsigned long rate; /* 주파수 (Hz) */
unsigned long u_volt; /* 전압 (μV) */
unsigned long power; /* 소비전력 (μW) */
};
/* OPP 테이블 API */
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(
struct device *dev, unsigned long *freq);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
/* Cortex-A55 OPP 테이블 (Device Tree 예시) */
cpu0_opp_table: opp-table-0 {
compatible = "operating-points-v2";
opp-shared;
opp-400000000 {
opp-hz = /bits/ 64 <400000000>;
opp-microvolt = <600000>;
opp-microwatt = <35000>;
};
opp-1800000000 {
opp-hz = /bits/ 64 <1800000000>;
opp-microvolt = <850000>;
opp-microwatt = <480000>;
};
};
CPU 용량 계산
이종 코어 시스템에서 스케줄러는 각 코어의 상대적 성능을 CPU 용량(capacity)으로 추상화합니다. SCHED_CAPACITY_SCALE = 1024가 최대값이며, 가장 강력한 코어(big 코어)가 1024를 가집니다.
/* drivers/base/arch_topology.c - CPU 용량 정규화 */
void topology_normalize_cpu_scale(void)
{
unsigned long capacity, max_capacity = 0;
int cpu;
for_each_possible_cpu(cpu) {
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
max_capacity = max(max_capacity, capacity);
}
for_each_possible_cpu(cpu) {
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
capacity = capacity * SCHED_CAPACITY_SCALE / max_capacity;
topology_set_cpu_scale(cpu, capacity);
}
}
/* arch_scale_cpu_capacity() — 스케줄러가 현재 CPU 용량을 조회 */
static inline unsigned long arch_scale_cpu_capacity(int cpu)
{
return per_cpu(cpu_scale, cpu);
}
Snapdragon 8 Gen 3 (SM8650) 기준 코어별 용량 예시:
| 코어 | 수 | 최대 주파수 | capacity-dmips-mhz | CPU capacity |
|---|---|---|---|---|
| Cortex-X4 | 1 | 3.3GHz | 1024 | 1024 |
| Cortex-A720 | 3 | 3.15GHz | 870 | ~895 |
| Cortex-A520 | 4 | 2.27GHz | 480 | ~450 |
ARM Energy Model 드라이버
Energy Model(EM) 프레임워크는 OPP별 소비전력 정보를 커널에 등록하여 EAS가 에너지 비용을 계산할 수 있도록 합니다.
/* include/linux/energy_model.h - EM 퍼포먼스 상태 */
struct em_perf_state {
unsigned long frequency; /* 주파수 (KHz) */
unsigned long power; /* 소비전력 (mW) */
unsigned long cost; /* power / frequency (에너지 비용 계수) */
};
struct em_perf_domain {
struct em_perf_state *table;
int nr_perf_states;
struct cpumask cpus;
};
/* EM 등록 — drivers/cpufreq/cpufreq-dt.c 등 */
int em_dev_register_perf_domain(struct device *dev,
unsigned int nr_states,
struct em_data_callback *cb,
struct cpumask *cpus,
bool microwatts);
아키텍처 간 비교
토폴로지 구조 비교
| 항목 | AMD (Zen4/5) | Intel (SPR/RPL) | ARM (Neoverse/DynamIQ) |
|---|---|---|---|
| 기본 단위 | CCX (8코어+L3) | 코어 (P/E 구분) | 클러스터 (DSU) |
| 중간 단위 | CCD (물리 다이) | Tile / E-core 클러스터 | CMN 메시 노드 |
| 인터커넥트 | Infinity Fabric (IOD 경유) | Ring Bus / Mesh | CMN 메시 / NoC |
| 이종 코어 | 없음 (동종) | P-core + E-core | X + A(big) + A(LITTLE) |
| NUMA 분할 | NPS1/2/4 | SNC2/4 | ACPI PPTT |
| 소켓 간 | xGMI (IF) | UPI | CCIX / CXL / 커스텀 |
| 칩렛/타일 | CCD + IOD 분리 | EMIB 타일 | 모놀리식 (서버 일부 칩렛) |
캐시 계층 · 코히런시 프로토콜
| 항목 | AMD | Intel | ARM |
|---|---|---|---|
| L1D/L1I | 32K/32K (Zen4: 48K/32K) | 48K/32K (P), 32K/64K (E) | 코어별 상이 |
| L2 | 1MB/코어 | 1.25-2MB/P, 2-4MB/4E | 256K~2MB/코어 |
| L3/LLC | 32MB/CCD | 슬라이스 분산 (1.875MB/코어) | DSU L3 + SLC(서버) |
| 코히런시 | MOESI | MESIF | MESI / AMBA CHI |
| 디렉토리 | Probe Filter | Snoop Filter | HN-F 디렉토리 |
커널의 토폴로지 탐지
x86 CPUID 기반 탐지
x86 커널은 CPUID 명령어를 사용하여 CPU 토폴로지를 탐지합니다. 핵심 Leaf:
| Leaf | 용도 | 제공 정보 |
|---|---|---|
| 0x0B | Extended Topology | SMT/Core 레벨 ID, 토폴로지 유형 |
| 0x1F | V2 Extended Topology | Module/Tile/Die 레벨 추가 (SPR+) |
| 0x8000001E | AMD 토폴로지 | Compute Unit ID, Node(CCD) ID |
| 0x04 / 0x8000001D | 캐시 토폴로지 | 캐시 레벨별 공유 범위 |
/* arch/x86/kernel/cpu/topology.c - detect_extended_topology() */
int detect_extended_topology(struct cpuinfo_x86 *c)
{
unsigned int eax, ebx, ecx, edx;
unsigned int sub_index = 0;
unsigned int leaf;
/* Leaf 0x1F를 우선 시도 (V2), 없으면 0x0B 사용 */
leaf = 0x1f;
cpuid_count(leaf, 0, &eax, &ebx, &ecx, &edx);
if (ebx == 0) {
leaf = 0x0b;
cpuid_count(leaf, 0, &eax, &ebx, &ecx, &edx);
if (ebx == 0)
return -1;
}
/* ECX[15:8] = 토폴로지 레벨 유형
* 1=SMT, 2=Core, 3=Module, 4=Tile, 5=Die */
do {
cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
unsigned level_type = (ecx >> 8) & 0xff;
unsigned shift = eax & 0x1f;
switch (level_type) {
case 1: /* SMT */
c->x86_max_threads = ebx & 0xffff;
break;
case 2: /* Core */
c->x86_max_cores = ebx & 0xffff;
break;
case 5: /* Die */
c->x86_max_dies = ebx & 0xffff;
break;
}
sub_index++;
} while (level_type != 0);
/* x2APIC ID로 고유 ID 설정 */
c->topo.apicid = edx;
return 0;
}
ARM DT/ACPI 기반 탐지
ARM64 시스템은 Device Tree 또는 ACPI PPTT(Processor Properties Topology Table)로 토폴로지를 기술합니다.
/* Device Tree 예시: cpu-map 노드 */
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu-map {
cluster0 { /* big 클러스터 */
core0 { cpu = <&cpu0>; };
core1 { cpu = <&cpu1>; };
core2 { cpu = <&cpu2>; };
core3 { cpu = <&cpu3>; };
};
cluster1 { /* LITTLE 클러스터 */
core0 { cpu = <&cpu4>; };
core1 { cpu = <&cpu5>; };
core2 { cpu = <&cpu6>; };
core3 { cpu = <&cpu7>; };
};
};
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-x4";
capacity-dmips-mhz = <1024>; /* 상대적 성능 */
};
cpu4: cpu@100 {
device_type = "cpu";
compatible = "arm,cortex-a520";
capacity-dmips-mhz = <480>; /* big 대비 ~47% */
};
};
/* ACPI PPTT 파싱: drivers/acpi/pptt.c */
static int topology_get_acpi_cpu_tag(struct acpi_table_header *table,
unsigned int cpu,
int level, int flag)
{
struct acpi_pptt_processor *node;
/* PPTT에서 CPU의 프로세서 노드를 탐색
* level 0 = thread, 1 = core, 2 = cluster, 3 = package */
node = acpi_find_processor_node(table, cpu);
while (node && level--) {
node = fetch_pptt_node(table, node->parent);
}
return node ? node->acpi_processor_id : -1;
}
/* arch/arm64/kernel/topology.c - parse_acpi_topology() */
int __init parse_acpi_topology(void)
{
int cpu;
for_each_possible_cpu(cpu) {
int topology_id;
topology_id = find_acpi_cpu_topology(cpu, 0); /* thread */
cpu_topology[cpu].thread_id = topology_id;
topology_id = find_acpi_cpu_topology(cpu, 1); /* core */
cpu_topology[cpu].core_id = topology_id;
topology_id = find_acpi_cpu_topology(cpu, 2); /* cluster */
cpu_topology[cpu].cluster_id = topology_id;
topology_id = find_acpi_cpu_topology_package(cpu);
cpu_topology[cpu].package_id = topology_id;
}
return 0;
}
초기화 흐름
커널 부팅 시 토폴로지 구축 순서:
- BSP(Bootstrap Processor)에서
identify_cpu()→ CPUID/PPTT 파싱 - 각 AP(Application Processor) 깨움 →
smp_callin()에서 개별 토폴로지 ID 설정 topology_init()→/sys/devices/system/cpu/cpuN/topology/sysfs 노출sched_init_domains()→ 토폴로지 기반 스케줄링 도메인 구축
start_kernel()
→ setup_arch()
→ early_cpu_init() /* x86: CPUID 기본 파싱 */
→ init_intel_cacheinfo() /* 캐시 토폴로지 */
→ smp_init()
→ cpu_up() (per AP)
→ identify_secondary_cpu()
→ set_cpu_sibling_map() /* SMT 형제 설정 */
→ sched_init_domains() /* 스케줄링 도메인 */
→ topology_init() /* sysfs 노출 */
sysfs 토폴로지 인터페이스
cpu topology
커널은 /sys/devices/system/cpu/cpuN/topology/에 각 논리 CPU의 토폴로지 정보를 노출합니다.
| 파일 | 설명 | 예시 (AMD EPYC) |
|---|---|---|
physical_package_id | 물리 소켓 ID | 0 |
die_id | 다이(CCD) ID | 0~11 |
cluster_id | 클러스터 ID (ARM, Intel E-core) | 0 |
core_id | 물리 코어 ID | 0~95 |
thread_siblings | SMT 형제 CPU 비트맵 | 00000003 |
thread_siblings_list | SMT 형제 CPU 목록 | 0,96 |
core_siblings | 같은 패키지 내 CPU 비트맵 | (전체) |
die_cpus_list | 같은 다이의 CPU 목록 | 0-7,96-103 |
# CPU 0의 토폴로지 정보 확인
$ for f in /sys/devices/system/cpu/cpu0/topology/*; do
echo "$(basename $f): $(cat $f)"
done
physical_package_id: 0
die_id: 0
cluster_id: 0
core_id: 0
thread_siblings_list: 0,96
cache hierarchy
# CPU 0의 캐시 계층 확인
$ ls /sys/devices/system/cpu/cpu0/cache/
index0 index1 index2 index3
$ for idx in 0 1 2 3; do
dir=/sys/devices/system/cpu/cpu0/cache/index${idx}
echo "L$(cat $dir/level) $(cat $dir/type): $(cat $dir/size), shared: $(cat $dir/shared_cpu_list)"
done
L1 Data: 32K, shared: 0,96 # SMT 형제 공유
L1 Instruction: 32K, shared: 0,96
L2 Unified: 1024K, shared: 0,96 # 코어 단위
L3 Unified: 32768K, shared: 0-7,96-103 # CCD(CCX) 단위
확인 도구
# lscpu: 가장 간단한 토폴로지 요약
$ lscpu
Architecture: x86_64
CPU(s): 192
Thread(s) per core: 2
Core(s) per socket: 96
Socket(s): 1
NUMA node(s): 4
...
# lstopo (hwloc): 그래픽 토폴로지 뷰
$ lstopo --of ascii
$ lstopo --of png topology.png
# /proc/cpuinfo: 상세 CPU 정보
$ grep -m1 "siblings\|cpu cores\|physical id\|core id" /proc/cpuinfo
# numactl: NUMA 토폴로지 + 메모리
$ numactl --hardware
SMT/Hyper-Threading 심화
SMT(Simultaneous Multi-Threading)는 하나의 물리 코어가 두 개 이상의 논리 스레드를 동시에 실행하는 기술입니다. Intel의 구현을 Hyper-Threading(HT)라고 부릅니다. 공유 자원에서 발생하는 성능 특성과 보안 취약점, 커널 스케줄링 알고리즘을 심화 분석합니다.
공유/분리 자원 비교
SMT의 핵심은 물리 코어 자원을 두 논리 스레드가 어떻게 공유하거나 분리하는지입니다.
| 자원 | 공유/분리 | Intel HT | AMD SMT | 비고 |
|---|---|---|---|---|
| 실행 유닛 (ALU/FPU/SIMD) | 공유 | 동적 할당 | 동적 할당 | 스레드별 발행 슬롯 경쟁 |
| ROB (Reorder Buffer) | 공유 | 절반씩 분할 | 절반씩 분할 | ROB 크기의 절반만 사용 가능 |
| RS (Reservation Station) | 공유 | 동적 할당 | 동적 할당 | 두 스레드 합산 → 단일 스레드보다 넓음 |
| 분기 예측기 (BTB) | 공유 ⚠ | 공유 | 공유 | Spectre V2 취약점의 원인 |
| L1 명령어 캐시 | 공유 | 공유 | 공유 | 코드 밀도 높으면 경합 |
| L1 데이터 캐시 | 공유 ⚠ | 공유 | 공유 | L1TF 취약점의 원인 |
| TLB (L1 DTLB/ITLB) | 공유 | 공유 | 공유 | 페이지 테이블 워크 경합 가능 |
| 레지스터 파일 | 분리 | 개별 | 개별 | 각 스레드가 완전한 레지스터 집합 보유 |
| 프로그램 카운터(IP/PC) | 분리 | 개별 | 개별 | 독립적인 실행 흐름 |
| LAPIC | 분리 | 개별 | 개별 | 각 논리 CPU가 독립 APIC ID |
커널 SMT 스케줄링
커널은 SMT 형제(sibling) 코어를 인식하고 select_idle_sibling()으로 태스크 배치를 최적화합니다.
/* kernel/sched/fair.c - SMT 형제 idle CPU 탐색 */
static int select_idle_sibling(struct task_struct *p,
int prev, int target)
{
struct sched_domain *sd;
int i, recent_used_cpu;
/* 1. target CPU가 idle이면 바로 반환 */
if (available_idle_cpu(target) || sched_idle_cpu(target))
return target;
/* 2. prev CPU의 SMT 형제 중 idle 탐색
* → L1/L2 캐시를 공유하므로 캐시 온도(warm) 유지 가능 */
for_each_cpu(i, cpu_smt_mask(prev)) {
if (available_idle_cpu(i))
return i;
}
/* 3. LLC 도메인 내 idle CPU 탐색 */
sd = rcu_dereference(per_cpu(sd_llc, target));
if (sd)
return select_idle_cpu(p, sd, prev == target, target);
return target;
}
/* sched_smt_power_savings: SMT 코어 내 두 번째 스레드를
* 활성화하기 전에 idle 코어를 먼저 채우는 정책 (기본 비활성화) */
SMT 제어
# SMT 상태 확인
$ cat /sys/devices/system/cpu/smt/control
on # on | off | forceoff | notsupported | notimplemented
$ cat /sys/devices/system/cpu/smt/active
1 # 1=활성화, 0=비활성화
# SMT 런타임 비활성화 (보안/전력 절약 목적)
$ echo off > /sys/devices/system/cpu/smt/control
# 부팅 시 SMT 비활성화 (Spectre/L1TF 완화)
# GRUB_CMDLINE_LINUX="nosmt" ← /etc/default/grub에 추가
# SMT 비활성화 시 성능 영향 확인
$ lscpu | grep -E "Thread|CPU\(s\)"
Thread(s) per core: 1 # nosmt 시 1
CPU(s): 48 # 물리 코어 수만 활성
SMT와 보안 취약점
SMT의 자원 공유 구조는 여러 사이드채널 공격의 근본 원인입니다. 상세 내용은 13. 보안 취약점과 토폴로지 섹션을 참조하세요.
| 취약점 | SMT 공유 자원 | 영향 | 완화 |
|---|---|---|---|
| Spectre V2 | BTB (Branch Target Buffer) | sibling 스레드의 분기 패턴 유출 | IBRS/IBPB/STIBP, Retpoline |
| L1TF (Foreshadow) | L1D 캐시 | 가상 메모리 내용 유출 | PTI, L1D 플러시, nosmt |
| MDS (RIDL/Fallout) | 내부 버퍼 (LFB/SB) | 파이프라인 버퍼 내용 유출 | VERW, MD_CLEAR |
스케줄링 도메인 계층
SMT → MC → DIE → NUMA
커널 스케줄러는 토폴로지를 기반으로 스케줄링 도메인(sched_domain)의 계층 구조를 구축합니다. 각 레벨은 캐시 공유 범위와 통신 비용을 반영합니다.
| 도메인 레벨 | 의미 | SD 플래그 | 대표 예 |
|---|---|---|---|
| SMT | 하이퍼스레드 형제 | SD_SHARE_CPUCAPACITY | CPU 0 ↔ CPU 96 |
| MC (Multi-Core) | L3 공유 코어 | SD_SHARE_PKG_RESOURCES | CCD 내 8코어 |
| CL (Cluster) | L2 공유 클러스터 | SD_SHARE_CLS_RESOURCES | Intel E-core 4개 |
| DIE | 같은 다이 | — | Intel Tile |
| NUMA | NUMA 노드 | SD_NUMA | NPS 분할 영역 |
NUMA 경계를 넘는 밸런싱의 구체적인 메커니즘 — Automatic NUMA Balancing, 태스크 선호 노드 결정, NUMA 그룹, 메모리 정책(mbind/set_mempolicy) 등은 NUMA 심화 — NUMA-aware 스케줄링에서 상세히 다룹니다.
도메인 구축
/* kernel/sched/topology.c - 스케줄링 도메인 구축 */
/* 기본 토폴로지 레벨 정의 */
static struct sched_domain_topology_level default_topology[] = {
#ifdef CONFIG_SCHED_SMT
{ cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
#endif
#ifdef CONFIG_SCHED_CLUSTER
{ cpu_clustergroup_mask, cpu_cluster_flags, SD_INIT_NAME(CL) },
#endif
#ifdef CONFIG_SCHED_MC
{ cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
#endif
{ cpu_cpu_mask, SD_INIT_NAME(PKG) },
{ NULL, },
};
/* cpu_coregroup_mask: L3를 공유하는 코어 그룹 반환 */
static const struct cpumask *cpu_coregroup_mask(int cpu)
{
return topology_core_cpumask(cpu);
}
/* build_sched_domains: 도메인 트리 구축 */
static int build_sched_domains(const struct cpumask *cpu_map,
struct sched_domain_attr *attr)
{
/* 각 토폴로지 레벨에 대해:
* 1. sched_domain 할당
* 2. sched_group 링 구성
* 3. 로드 밸런싱 파라미터 초기화 */
for_each_sd_topology(tl) {
for_each_cpu(i, cpu_map) {
sd = __build_sched_domain(tl, cpu_map, attr, ...);
...
}
}
...
}
도메인 확인
# 스케줄링 도메인 계층 확인
$ ls /sys/kernel/debug/sched/domains/cpu0/
domain0 domain1 domain2 domain3
# 또는 /proc/sys/kernel/sched_domain/
$ ls /proc/sys/kernel/sched_domain/cpu0/
domain0 domain1 domain2 domain3
# 각 도메인의 이름과 범위
$ cat /proc/sys/kernel/sched_domain/cpu0/domain0/name
SMT
$ cat /proc/sys/kernel/sched_domain/cpu0/domain1/name
MC
$ cat /proc/sys/kernel/sched_domain/cpu0/domain2/name
DIE
$ cat /proc/sys/kernel/sched_domain/cpu0/domain3/name
NUMA
# 밸런싱 간격, 플래그 확인
$ cat /proc/sys/kernel/sched_domain/cpu0/domain1/min_interval
4
$ cat /proc/sys/kernel/sched_domain/cpu0/domain1/flags
559
비대칭 스케줄링
ASYM_PACKING
SD_ASYM_PACKING은 SMT 레벨에서 사용되는 플래그로, 하이퍼스레드 형제 코어에 태스크를 비대칭적으로 배치합니다.
/* kernel/sched/fair.c - SMT 비대칭 패킹 로직 */
/*
* ASYM_PACKING 정책:
* - SMT 형제 중 높은 우선순위(smt_gain이 큰) 스레드를 먼저 채움
* - 두 번째 스레드는 가능하면 다른 물리 코어로 이동
* - 결과: 물리 코어를 최대한 활용하여 IPC 극대화
*
* Intel: 보통 thread 0이 우선순위 높음
* AMD: Preferred Core 기능으로 최적 코어 선별
*/
static int find_busiest_group(struct lb_env *env,
struct sd_lb_stats *sds)
{
if (env->sd->flags & SD_ASYM_PACKING) {
/* 우선순위가 낮은 CPU에서 높은 CPU로 태스크 이동 */
if (sched_asym_prefer(env->dst_cpu, busiest->asym_prefer_cpu))
return busiest;
}
...
}
ASYM_CPUCAPACITY (EAS)
Energy-Aware Scheduling(EAS)은 이종 코어 시스템에서 성능과 에너지 효율의 균형을 맞추는 스케줄러 기능입니다.
/* kernel/sched/fair.c - find_energy_efficient_cpu() */
static int find_energy_efficient_cpu(struct task_struct *p,
int prev_cpu)
{
struct root_domain *rd = cpu_rq(prev_cpu)->rd;
unsigned long best_delta = ULONG_MAX;
int best_cpu = -1;
for_each_cpu_and(cpu, sched_domain_span(sd), p->cpus_ptr) {
unsigned long cur_delta;
/* 각 CPU(performance domain)별 에너지 소비 예측 */
cur_delta = compute_energy(p, cpu, pd);
if (cur_delta < best_delta) {
best_delta = cur_delta;
best_cpu = cpu;
}
}
/* 에너지 절감량이 6% 미만이면 prev_cpu 유지 (마이그레이션 비용) */
if ((prev_delta - best_delta) * 100 < prev_delta * 6)
return prev_cpu;
return best_cpu;
}
/* EAS 활성화 조건:
* 1. SD_ASYM_CPUCAPACITY 플래그 설정
* 2. Energy Model(EM) 등록 (em_dev_register_perf_domain)
* 3. CPU 수가 너무 많지 않을 것 (기본 256 이하) */
Intel Thread Director 커널 통합
/* drivers/thermal/intel/intel_hfi.c - HFI 커널 통합 */
/* HFI 인터럽트 핸들러: 하드웨어가 성능/효율 테이블 갱신 시 호출 */
static void intel_hfi_online(unsigned int cpu)
{
struct hfi_instance *hfi = per_cpu(hfi_instance, cpu);
/* CPU별 성능 능력(perf_cap)과 에너지 효율(ee_cap) 읽기 */
u8 perf_cap = hfi->local_table[cpu].perf_cap;
u8 ee_cap = hfi->local_table[cpu].ee_cap;
/* 스케줄러에 CPU 용량 업데이트 알림
* → CFS의 capacity_of()에 반영
* → 높은 perf_cap = P-core, 높은 ee_cap = E-core 선호 */
topology_set_cpu_capacity(cpu, perf_cap);
}
/* IPC 클래스 기반 코어 선택 (커널 6.6+) */
/* Thread Director가 실시간으로 IPC 클래스를 업데이트하면,
* 스케줄러가 해당 태스크에 적합한 코어 유형을 선택 */
ARM cpu-capacity
ARM에서는 Device Tree의 capacity-dmips-mhz 속성으로 각 코어의 상대적 성능을 지정합니다.
/* drivers/base/arch_topology.c - CPU 용량 설정 */
void topology_normalize_cpu_scale(void)
{
unsigned long capacity, max_capacity = 0;
int cpu;
/* DT의 capacity-dmips-mhz 기반 최대값 탐색 */
for_each_possible_cpu(cpu) {
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
max_capacity = max(max_capacity, capacity);
}
/* 최대 코어 = 1024, 나머지 비례 계산 */
for_each_possible_cpu(cpu) {
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
capacity = capacity * SCHED_CAPACITY_SCALE / max_capacity;
topology_set_cpu_scale(cpu, capacity);
}
}
/* 결과: big 코어 = 1024, LITTLE = ~480, mid = ~700 등
* → EAS가 이 값을 사용하여 태스크 배치 결정 */
전력 도메인과 EAS
Energy-Aware Scheduling(EAS)은 이종 코어 시스템에서 에너지 모델(Energy Model)을 기반으로 태스크를 가장 에너지 효율적인 CPU에 배치합니다. ARM 모바일 SoC에서 처음 도입되었으며, 리눅스 5.0부터 mainline에 포함되었습니다.
Energy Model 프레임워크 구조
EAS가 동작하려면 세 가지 조건이 모두 충족되어야 합니다:
SD_ASYM_CPUCAPACITY플래그 — 이종 코어 시스템임을 나타내는 스케줄링 도메인 플래그- Energy Model 등록 —
em_dev_register_perf_domain()으로 각 성능 도메인의 전력 정보 등록 - schedutil 거버너 — CPUFreq 거버너가 schedutil이어야 EAS와 연동 가능 (
ondemand/performance불가)
/* kernel/sched/fair.c - EAS 활성화 조건 확인 */
static bool sched_energy_enabled(void)
{
static int enabled = -1;
if (enabled == -1)
enabled = (sysctl_sched_energy_aware &&
cpufreq_get_hw_max_freq(0) &&
arch_scale_freq_capacity(0) != SCHED_CAPACITY_SCALE);
return enabled;
}
/* /proc/sys/kernel/sched_energy_aware = 1 이면 EAS 활성화 */
EAS 알고리즘
find_energy_efficient_cpu()는 태스크를 배치할 최적 CPU를 찾는 EAS의 핵심 함수입니다. 각 performance domain(PD)별로 에너지 소비를 예측하고 가장 낮은 PD를 선택합니다.
/* kernel/sched/fair.c - EAS 핵심 로직 */
static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu)
{
struct root_domain *rd = cpu_rq(prev_cpu)->rd;
unsigned long prev_delta, best_delta = ULONG_MAX;
int best_cpu = prev_cpu;
/* prev_cpu에서의 에너지 기준값 계산 */
prev_delta = compute_energy(p, prev_cpu, find_pd(rd, prev_cpu));
/* 각 performance domain 순회 */
rcu_read_lock();
for_each_pd(pd, rd) {
int cpu;
for_each_cpu_and(cpu, perf_domain_span(pd), p->cpus_ptr) {
unsigned long cur_delta = compute_energy(p, cpu, pd);
if (cur_delta < best_delta) {
best_delta = cur_delta;
best_cpu = cpu;
}
}
}
rcu_read_unlock();
/* 에너지 절감이 6% 미만이면 prev_cpu 유지 (마이그레이션 비용 방지) */
if ((prev_delta - best_delta) * 100 < prev_delta * 6)
return prev_cpu;
return best_cpu;
}
OPP와 전력 예산
EAS의 에너지 계산은 각 OPP(Operating Performance Point)의 주파수·전력 정보를 기반으로 합니다. Cortex-A55 기준 예시:
| 주파수 | 전압 | 전력 (mW) | capacity | cost (power/freq) |
|---|---|---|---|---|
| 400MHz | 0.60V | 35 | 180 | 87.5 |
| 800MHz | 0.70V | 105 | 360 | 131.3 |
| 1200MHz | 0.75V | 185 | 540 | 154.2 |
| 1600MHz | 0.80V | 310 | 720 | 193.8 |
| 1800MHz | 0.85V | 480 | 810 | 266.7 |
cost 값의 의미: cost = power / frequency가 낮을수록 주파수 단위당 에너지 효율이 높습니다. EAS는 태스크의 utilization에 맞는 OPP의 cost를 사용하여 에너지 예측값을 계산합니다.
DTPM 계층
DTPM(Dynamic Thermal Power Management)은 열/전력 제약 내에서 SoC 전체의 전력 분배를 관리합니다.
# powercap 인터페이스 확인 (Intel RAPL 포함)
$ ls /sys/class/powercap/
intel-rapl intel-rapl:0 intel-rapl:0:0 ...
# DTPM 계층 확인 (ARM 시스템)
$ ls /sys/class/powercap/dtpm/
constraint_0_max_power_uw constraint_0_name
constraint_0_power_limit_uw energy_uj ...
Energy Model 디버깅
# EAS 활성화 여부 확인
$ cat /proc/sys/kernel/sched_energy_aware
1
# Energy Model 등록 상태 (debugfs)
$ cat /sys/kernel/debug/energy_model/cpu0/nr_perf_states
5
$ cat /sys/kernel/debug/energy_model/cpu0/table
freq power cost
400000 35 87
800000 105 131
1200000 185 154
1600000 310 193
1800000 480 266
# schedutil 거버너 확인 (EAS 필수 조건)
$ cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
schedutil
CPU 격리 심화
CPU 격리(CPU Isolation)는 특정 코어를 리눅스 스케줄러의 일반 태스크 배치에서 제외하여, 실시간 처리나 레이턴시에 민감한 애플리케이션 전용으로 사용하는 기법입니다.
부팅 파라미터 비교
| 파라미터 | 역할 | 대상 | 완전 격리 여부 |
|---|---|---|---|
isolcpus=N | 일반 스케줄러 배치 제외 | CFS/RT 태스크 | 부분 (커널 스레드 미포함) |
nohz_full=N | 틱리스 모드 활성화 | 타이머 인터럽트 | 타이머 오버헤드 제거 |
rcu_nocbs=N | RCU 콜백 오프로드 | RCU 처리 | RCU 스레드 분리 |
irqaffinity=M | IRQ 친화도 기본값 설정 | 하드웨어 인터럽트 | IRQ 특정 코어 제한 |
kthread_cpus=M | 커널 스레드 친화도 | 커널 스레드 | 커널 스레드 격리 |
isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3 irqaffinity=0,1
IRQ 친화도 설정
# IRQ 목록과 현재 친화도 확인
$ cat /proc/interrupts | head -20
# 특정 IRQ를 코어 0,1에만 허용 (비트마스크)
$ echo 3 > /proc/irq/42/smp_affinity # 0b11 = CPU 0,1
# 또는 목록 형식으로
$ echo 0,1 > /proc/irq/42/smp_affinity_list
# 모든 IRQ를 코어 0,1로 제한 (격리 코어에서 IRQ 제거)
$ for irq in /proc/irq/[0-9]*/smp_affinity_list; do
echo "0-1" > "$irq" 2>/dev/null
done
# irqbalance 비활성화 (IRQ 친화도 자동 변경 방지)
$ systemctl stop irqbalance
$ systemctl disable irqbalance
CPU 피닝
/* sched_setaffinity() 시스템 콜 사용 예 */
#include <sched.h>
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(2, &mask); /* CPU 2 전용 */
CPU_SET(3, &mask); /* CPU 3 전용 */
if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
perror("sched_setaffinity");
/* 커널 내부: kernel/sched/core.c
* sys_sched_setaffinity() → __set_cpus_allowed_ptr()
* → migrate_task_to() (필요 시 즉시 마이그레이션) */
# taskset으로 CPU 친화도 설정/확인
$ taskset -c 2,3 ./realtime_app # 새 프로세스를 CPU 2,3에서 시작
$ taskset -cp 2,3 1234 # 기존 PID 1234를 CPU 2,3으로 이동
$ taskset -cp 1234 # 현재 친화도 확인
커널 스레드 격리
/* kernel/kthread.c - 커널 스레드 CPU 바인딩 */
/* 특정 CPU에서만 실행되는 커널 스레드 생성 */
struct task_struct *kthread_create_on_cpu(
int (*threadfn)(void *data),
void *data,
unsigned int cpu,
const char *namefmt);
/* 이미 생성된 커널 스레드를 특정 CPU에 바인딩 */
void kthread_bind(struct task_struct *p, unsigned int cpu);
/* 예: CPU 핫플러그 워커를 CPU 0에만 허용 */
kthread_bind(cpuhp_thread, 0);
격리 효과 측정
# cyclictest로 wakeup latency 측정 (isolcpus 적용 전후 비교)
# 격리 전:
$ cyclictest -t 1 -p 99 -n -i 1000 -l 100000 -q
T: 0 (12345) P:99 I:1000 C:100000 Min: 8 Act: 12 Avg: 15 Max: 245
# 격리 후 (isolcpus=2 nohz_full=2 rcu_nocbs=2):
$ taskset -c 2 cyclictest -t 1 -p 99 -n -i 1000 -l 100000 -q
T: 0 (12346) P:99 I:1000 C:100000 Min: 4 Act: 5 Avg: 5 Max: 18
# 격리 효과 확인 (최대 레이턴시 245us → 18us)
보안 취약점과 토폴로지
현대 CPU 아키텍처의 성능 최적화 기능(투기적 실행, 비순차 실행, 분기 예측)은 하드웨어 토폴로지(SMT, 캐시 공유)와 결합하여 심각한 보안 취약점을 만들어냈습니다.
Spectre V1/V2
Spectre V1 (CVE-2017-5753): 배열 범위 검사를 우회하는 조건부 분기 오예측을 통해 임의 메모리를 읽습니다. Spectre V2 (CVE-2017-5715): SMT 형제 스레드 간 BTB(Branch Target Buffer) 공유를 이용해 피해자 프로세스의 간접 분기를 조작합니다.
| 항목 | Spectre V1 | Spectre V2 |
|---|---|---|
| 원인 자원 | 조건부 분기 예측기 (PHT) | 간접 분기 예측기 (BTB) |
| 공격 방법 | Array Index Out-of-Bounds 투기 | BTB 중독(Poisoning) → 임의 가젯 실행 |
| SMT 연관성 | 낮음 | 높음 (sibling 스레드 BTB 공유) |
| 커널 완화 | array_index_nospec() 배리어 | IBRS/eIBRS, Retpoline, IBPB |
| 성능 영향 | ~1% | IBRS ~10-20%, eIBRS ~3% |
/* arch/x86/include/asm/barrier.h - Spectre V1 완화 */
/* array_index_nospec(): 투기적 실행 경로에서 배열 접근 방지 */
static inline unsigned long array_index_mask_nospec(
unsigned long index, unsigned long size)
{
/*
* index < size 이면 mask = ~0UL (모든 비트 1)
* index >= size 이면 mask = 0 (모든 비트 0)
* 투기적 실행 경로에서 부호 비트를 이용한 마스킹
*/
return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
}
#define array_index_nospec(index, size) (typeof(index))(array_index_mask_nospec(index, size) & (index))
Meltdown과 L1TF
Meltdown (CVE-2017-5754): 커널 메모리를 사용자 공간에서 읽는 취약점. PTI(Page Table Isolation)로 완화합니다. L1TF/Foreshadow (CVE-2018-3620/3646): L1D 캐시 플러시 없이 SMT sibling이 hyper-guest의 L1D 캐시 내용을 투기적으로 접근합니다.
| 항목 | Meltdown | L1TF |
|---|---|---|
| 원인 자원 | 페이지 테이블 검사 지연 | L1D 캐시 (SMT sibling 공유) |
| 완화 방법 | PTI (KPTI) | PTE inversion + L1D 플러시 |
| SMT 영향 | 낮음 | 높음 (nosmt 권장) |
| 성능 영향 | PTI ~5-30% (syscall 집약적) | L1D 플러시 ~10% |
# PTI 활성화 여부 확인
$ cat /sys/devices/system/cpu/vulnerabilities/meltdown
Mitigation: PTI
# L1TF 상태 확인
$ cat /sys/devices/system/cpu/vulnerabilities/l1tf
Mitigation: PTE Inversion; VMX: cache flushes, SMT vulnerable
MDS와 SRBDS
MDS(Microarchitectural Data Sampling, CVE-2018-12126/12127/12130): CPU 내부 버퍼(Line Fill Buffer, Store Buffer, Load Port)에서 데이터가 누출됩니다. SRBDS(Special Register Buffer Data Sampling, CVE-2020-0543): RDRAND/RDSEED/EGETKEY 명령어의 결과가 내부 버퍼를 통해 sibling에 노출됩니다.
| 취약점 | 영향 버퍼 | 완화 | SMT 영향 |
|---|---|---|---|
| MFBDS/RIDL | Line Fill Buffer | VERW + MD_CLEAR | 높음 |
| MLPDS/Fallout | Store Buffer | VERW + MD_CLEAR | 높음 |
| MDSUM | Load Port | VERW + MD_CLEAR | 높음 |
| SRBDS | 특수 레지스터 버퍼 | SRBDS_CTRL MSR | 중간 |
/* arch/x86/kernel/cpu/bugs.c - MDS/SRBDS 완화 */
/* VERW 명령어로 CPU 내부 버퍼 클리어
* 커널→사용자 전환 시 실행되어 버퍼 내용을 제거 */
static inline void mds_clear_cpu_buffers(void)
{
static const u16 ds = __KERNEL_DS;
/* VERW는 메모리 접근 없이 DS 세그먼트 검증 → CPU 버퍼 플러시 */
asm volatile("verw %[ds]" : : [ds] "m" (ds) : "cc");
}
취약점 sysfs 인터페이스
# 모든 취약점 상태 한 번에 확인
$ grep -r . /sys/devices/system/cpu/vulnerabilities/
/sys/devices/system/cpu/vulnerabilities/spectre_v1:Mitigation: usercopy/swapgs barriers and __user pointer sanitization
/sys/devices/system/cpu/vulnerabilities/spectre_v2:Mitigation: Enhanced / Automatic IBRS; IBPB: conditional; RSB filling; PBRSB-eIBRS: SW sequence
/sys/devices/system/cpu/vulnerabilities/meltdown:Mitigation: PTI
/sys/devices/system/cpu/vulnerabilities/l1tf:Mitigation: PTE Inversion; VMX: cache flushes, SMT vulnerable
/sys/devices/system/cpu/vulnerabilities/mds:Mitigation: Clear CPU buffers; SMT vulnerable
/sys/devices/system/cpu/vulnerabilities/tsx_async_abort:Mitigation: TSX disabled
/sys/devices/system/cpu/vulnerabilities/srbds:Mitigation: Microcode
/sys/devices/system/cpu/vulnerabilities/retbleed:Mitigation: IBRS
/sys/devices/system/cpu/vulnerabilities/spec_store_bypass:Mitigation: Speculative Store Bypass disabled via prctl
완화 오버헤드 종합표
| CVE | 취약점명 | 원인 자원 | 완화 기법 | SMT 영향 | 성능 오버헤드 |
|---|---|---|---|---|---|
| CVE-2017-5753 | Spectre V1 | PHT | array_index_nospec | 낮음 | ~1% |
| CVE-2017-5715 | Spectre V2 | BTB (SMT 공유) | eIBRS/Retpoline | 높음 | ~3-20% |
| CVE-2017-5754 | Meltdown | 페이지 테이블 | PTI (KPTI) | 낮음 | ~5-30% |
| CVE-2018-3620 | L1TF | L1D (SMT 공유) | PTE inversion + L1D flush | 매우 높음 | ~10% |
| CVE-2018-12126 | MFBDS/RIDL | LFB (SMT 공유) | VERW/MD_CLEAR | 높음 | ~3% |
| CVE-2020-0543 | SRBDS | 특수 레지스터 버퍼 | SRBDS_CTRL MSR | 중간 | ~1% |
| CVE-2022-29901 | Retbleed | RSB (RET 예측) | IBRS/RSB fill | 낮음 | ~14-39% |
nosmt 커널 파라미터로 SMT를 비활성화하는 것이 권장됩니다. 단, 멀티스레드 성능이 최대 50% 감소할 수 있습니다.
커널 소스 참조
x86 토폴로지
| 파일 | 역할 |
|---|---|
arch/x86/kernel/cpu/topology.c | CPUID 기반 토폴로지 탐지, detect_extended_topology() |
arch/x86/kernel/cpu/amd.c | AMD 전용 토폴로지 (CPUID 0x8000001E) |
arch/x86/kernel/cpu/intel.c | Intel 전용 토폴로지, Thread Director |
arch/x86/kernel/smpboot.c | SMP 부팅, AP 초기화, sibling map |
arch/x86/kernel/cpu/cacheinfo.c | CPUID 기반 캐시 토폴로지 |
ARM64 토폴로지
| 파일 | 역할 |
|---|---|
arch/arm64/kernel/topology.c | ARM64 토폴로지 초기화, PPTT 파싱 |
drivers/base/arch_topology.c | 아키텍처 공통: cpu-capacity, freq-factor |
drivers/acpi/pptt.c | ACPI PPTT 테이블 파서 |
drivers/perf/arm-cmn.c | CMN 메시 PMU 드라이버 |
스케줄러 토폴로지
| 파일 | 역할 |
|---|---|
kernel/sched/topology.c | sched_domain 구축, build_sched_domains() |
kernel/sched/fair.c | CFS 로드 밸런싱, EAS, ASYM_PACKING |
include/linux/topology.h | 토폴로지 매크로/함수 선언 |
drivers/thermal/intel/intel_hfi.c | Intel HFI/Thread Director 드라이버 |
전력/EAS 관련 파일
| 파일 | 역할 |
|---|---|
kernel/sched/cpufreq.c | schedutil 거버너, EAS-CPUFreq 연동 |
drivers/cpufreq/cpufreq-dt.c | OPP 테이블 기반 CPUFreq 드라이버 |
drivers/base/power/opp/core.c | OPP 프레임워크 핵심 구현 |
kernel/power/energy_model.c | Energy Model 프레임워크 |
drivers/powercap/intel_rapl_common.c | Intel RAPL 전력 측정 |
drivers/base/arch_topology.c | CPU 용량 정규화, freq-factor |
보안 취약점 완화 파일
| 파일 | 역할 |
|---|---|
arch/x86/kernel/cpu/bugs.c | Spectre/Meltdown/MDS 완화, 취약점 검출 |
arch/x86/kernel/cpu/amd.c | AMD 전용 취약점 완화 (Retbleed, IBPB) |
arch/x86/mm/pti.c | PTI (Page Table Isolation) 구현 |
arch/x86/kernel/itmt.c | ITMT/HFI 코어 우선순위 설정 |
arch/x86/include/asm/barrier.h | 투기적 실행 배리어, array_index_nospec |
실전 진단 명령 모음
토폴로지 확인
# 전체 토폴로지 요약
$ lscpu -e=CPU,SOCKET,NODE,CORE,L1d:,L1i:,L2:,L3:,ONLINE
# hwloc: 상세 그래픽 토폴로지 (텍스트)
$ lstopo-no-graphics --of ascii
# 특정 CPU의 상세 토폴로지
$ cat /sys/devices/system/cpu/cpu0/topology/die_id
$ cat /sys/devices/system/cpu/cpu0/topology/core_id
$ cat /sys/devices/system/cpu/cpu0/topology/thread_siblings_list
# 캐시 공유 관계 확인
$ cat /sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_list
# CPU 용량 확인 (ARM/하이브리드)
$ cat /sys/devices/system/cpu/cpu*/cpu_capacity
sched_domain 확인
# 스케줄링 도메인 이름 확인
$ for d in /proc/sys/kernel/sched_domain/cpu0/domain*/; do
echo "$(basename $d): $(cat ${d}name)"
done
domain0: SMT
domain1: MC
domain2: DIE
domain3: NUMA
# 도메인별 밸런싱 통계 (debugfs)
$ cat /proc/schedstat | head -20
# 태스크의 현재 CPU, 선호도 확인
$ taskset -cp $$
$ cat /proc/$$/status | grep Cpus_allowed
성능 측정
# inter-CCD vs intra-CCD 지연 비교 (perf)
$ perf stat -e cache-misses,cache-references,L1-dcache-load-misses \
taskset -c 0,1 ./benchmark # 같은 CCX 내 코어
$ perf stat -e cache-misses,cache-references,L1-dcache-load-misses \
taskset -c 0,16 ./benchmark # 다른 CCD 코어
# NUMA 지연 측정
$ numactl --hardware
$ numactl --cpunodebind=0 --membind=0 ./benchmark # 로컬
$ numactl --cpunodebind=0 --membind=1 ./benchmark # 리모트
# Intel Thread Director 상태 확인
$ cat /sys/devices/system/cpu/cpu*/topology/ppin 2>/dev/null
$ dmesg | grep -i "hfi\|thread director"
# 스케줄러 디버깅 (ftrace)
$ echo 1 > /sys/kernel/debug/tracing/events/sched/sched_migrate_task/enable
$ cat /sys/kernel/debug/tracing/trace_pipe | head -50
EAS 진단
# EAS 활성화 여부 확인
$ cat /proc/sys/kernel/sched_energy_aware
1
# EAS 비활성화 (디버깅용)
$ echo 0 > /proc/sys/kernel/sched_energy_aware
# Energy Model 등록 상태
$ ls /sys/kernel/debug/energy_model/
cpu0 cpu4 cpu7 # 각 performance domain 대표 CPU
$ cat /sys/kernel/debug/energy_model/cpu0/table
# schedutil 상태 확인
$ cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
schedutil
# CPU별 현재 utilization 확인 (cfs bandwidth)
$ cat /proc/sched_debug | grep -A 5 "cpu#0"
# perf로 EAS 동작 추적
$ perf sched record -g -- sleep 5
$ perf sched map
보안 취약점 진단
# 모든 취약점 상태 한 번에 확인
$ grep -r . /sys/devices/system/cpu/vulnerabilities/
# SMT 상태와 보안 권고 확인
$ cat /sys/devices/system/cpu/smt/active
$ dmesg | grep -i "SMT\|spectre\|meltdown\|mds"
# spectre_v2 완화 방법 확인
$ cat /sys/devices/system/cpu/vulnerabilities/spectre_v2
# 커널 부팅 파라미터에서 완화 설정 확인
$ cat /proc/cmdline | tr ' ' '
' | grep -E "spectre|mds|pti|ibrs|retpoline"
# 완화 비활성화 시 성능 차이 측정 (개발/테스트 환경 전용)
# GRUB에 mitigations=off 추가 후 비교
CPU 격리 진단
# 격리된 CPU 목록 확인
$ cat /sys/devices/system/cpu/isolated
2-3
# nohz_full 활성화 CPU 확인
$ cat /sys/devices/system/cpu/nohz_full
2-3
# 격리 CPU에서 실행 중인 프로세스 확인
$ ps -eo pid,psr,comm | awk '$2 == 2 || $2 == 3'
# IRQ 친화도 현황
$ for i in $(ls /proc/irq/); do
aff=$(cat /proc/irq/$i/smp_affinity_list 2>/dev/null)
[ -n "$aff" ] && echo "IRQ $i: $aff"
done
# 격리 효과 cyclictest 측정
$ taskset -c 2 cyclictest -t 1 -p 99 -n -i 1000 -l 10000 -q
관련 문서
CPU 토폴로지와 관련된 다른 주제를 더 깊이 이해하고 싶다면 다음 문서를 참고하세요.