Intel PCM (Performance Counter Monitor) 완전 가이드
Intel PCM(Performance Counter Monitor)을 사용해 CPU 코어·언코어·메모리·PCIe·전력을 실시간(Real-time) 통합 계측하는 방법을 다룹니다. pcm-memory/pcm-pcie/pcm-tpmi/pcm-power를 중심으로 CXL 대역폭(Bandwidth) 분석, NUMA 불균형 진단, 플랫폼별 카운터 해석, Grafana/Prometheus 대시보드 연동, perf/pmu-tools와 결합한 TMA Top-Down 병목(Bottleneck) 분석까지 Sapphire/Emerald/Granite Rapids 환경 기준으로 실무 흐름에 맞춰 설명합니다.
전제 조건: Intel PCM은 Intel CPU 전용 도구입니다. MSR 레지스터(Register) 직접 접근을 위해 root 권한(또는 CAP_SYS_RAWIO)과 msr 커널 모듈(Kernel Module)이 필요합니다. Secure Boot 환경에서는 perf_event 모드(PCM_USE_PERF=1) 또는 TPMI(6.3+) 경로를 사용하세요.
일상 비유: 자동차 계기판처럼, PCM은 CPU(엔진 회전수·연비), 메모리(연료 흐름), PCIe(도로 통행량), 전력(연료 소비량)의 모든 수치를 한눈에 보여주는 하드웨어 계기판입니다. perf가 특정 부품(함수/프로세스(Process))을 분석한다면, PCM은 시스템 전체 하드웨어 상태를 한 화면에 표시합니다.
핵심 요약
- PCM vs perf: perf는 프로세스/함수 수준 프로파일링(Profiling), PCM은 시스템 전체 언코어 카운터 모니터링
- 3가지 접근 경로: MSR 드라이버(
/dev/cpu/*/msr),perf_event_open(), sysfs/MMIO(TPMI) - pcm-memory: 소켓(Socket)/채널별 DRAM 대역폭을 iMC 카운터로 실시간 측정, BW 포화 진단
- pcm-tpmi: Sapphire Rapids+에서 MMIO 기반 언코어 접근 (Secure Boot 호환)
- CXL 모니터링:
pcm-pcie -cxl로 CXL Type 1/2/3 장치의 대역폭/레이턴시 측정 - REST API / Grafana:
pcm-sensor-server로 Prometheus 메트릭 노출, Grafana 대시보드 연동 - TMA 연계: pcm + toplev 조합으로 Frontend/Backend/Bad Speculation 자동 분류
- 커널 인프라:
msr,intel_uncore,intel_rapl,intel_vsec/tpmi드라이버 기반
단계별 이해
- 설치: GitHub 소스 빌드 또는 패키지 설치,
msr모듈 로드, NMI watchdog 비활성화 - 기본 모니터링:
sudo pcm으로 코어별 IPC/캐시(Cache) 히트율/주파수/온도 확인 - 메모리 BW:
sudo pcm-memory로 소켓별 읽기/쓰기 대역폭 → 이론값 대비 포화율 계산 - PCIe/CXL:
sudo pcm-pcie(표준) /sudo pcm-pcie -cxl(CXL 장치)로 인바운드/아웃바운드 BW - TPMI 활용:
sudo pcm-tpmi로 Sapphire Rapids+ 언코어 카운터 접근 (MSR 불필요) - Grafana 연동:
sudo pcm-sensor-server→ Prometheus scrape → Grafana 대시보드 임포트 - TMA 분석:
toplev.py -l1~l3으로 파이프라인(Pipeline) 병목 대분류 → PCM으로 하드웨어 수치 확인 - 진단 시나리오: IPC 저하 → 메모리 BW 포화, 주파수 스로틀링, NUMA 불균형, LLC 쓰레싱 순으로 확인
PCM 개요 및 아키텍처
Intel PCM은 Intel이 개발한 오픈소스 성능 모니터링 도구 모음으로, CPU 코어 성능 카운터, 메모리 대역폭, QPI/UPI 링크 사용률, PCIe 대역폭, 전력 소비량 등을 실시간으로 측정합니다. perf가 커널에 내장된 범용 프로파일링 프레임워크라면, PCM은 Intel 플랫폼에 특화된 시스템 수준 하드웨어 모니터링 도구입니다.
PCM vs perf: perf는 커널 perf_event 서브시스템을 통해 PMU에 접근하며 프로세스/함수 수준 프로파일링에 강합니다. 반면 PCM은 MSR/PCI config 레지스터에 직접 접근하여 언코어(Uncore) 카운터 — 메모리 컨트롤러, QPI/UPI 링크, PCIe, 전력 등 코어 외부 리소스 — 를 포함한 시스템 전체 관점의 모니터링에 특화되어 있습니다.
PCM은 세 가지 경로로 하드웨어 카운터에 접근합니다:
| 접근 경로 | 대상 카운터 | 커널 요구사항 | 용도 |
|---|---|---|---|
| MSR 드라이버 | Core PMU, Fixed CTR, RAPL | msr 커널 모듈 | 코어별 성능 카운터, 전력 측정 |
| perf_event | Core/Uncore PMU | CONFIG_PERF_EVENTS | perf 서브시스템 경유 (권한 제어 용이) |
| sysfs/MMIO | TPMI, PCI config space | TPMI 드라이버 (6.3+) | 언코어 카운터, PCIe/CXL 모니터링 |
설치 및 빌드
# 소스에서 빌드 (GitHub)
git clone --recursive https://github.com/intel/pcm.git
cd pcm
mkdir build && cd build
cmake ..
cmake --build . --parallel
# 패키지 매니저로 설치 (배포판별)
sudo apt install pcm # Ubuntu 22.04+ / Debian
sudo dnf install pcm # Fedora / RHEL 9+
# Docker로 실행 (권한 필요)
docker run --privileged -d \
--name pcm --ipc=host --pid=host \
-v /sys:/sys:rw \
ghcr.io/intel/pcm
커널 모듈 및 접근 권한 설정
PCM은 MSR 레지스터에 직접 접근하므로 msr 커널 모듈과 root 권한(또는 CAP_SYS_RAWIO)이 필요합니다:
# msr 커널 모듈 로드
sudo modprobe msr
# NMI watchdog 비활성화 (PMU 카운터 점유 방지)
# NMI watchdog가 고정 카운터를 사용하면 PCM과 충돌
sudo sysctl kernel.nmi_watchdog=0
# Secure Boot 환경에서 MSR 접근 허용
# /dev/cpu/*/msr 접근이 차단될 경우:
sudo modprobe msr allow_writes=on
# perf_event 기반 접근 사용 시 (MSR 직접 접근 대신)
# PCM은 perf_event 모드도 지원 (-e 옵션 또는 환경변수)
export PCM_USE_PERF=1
sudo sysctl kernel.perf_event_paranoid=-1
NMI watchdog 충돌: NMI watchdog는 고정 카운터(INST_RETIRED.ANY)를 점유합니다. PCM 실행 전 nmi_watchdog=0으로 비활성화하지 않으면 카운터 프로그래밍이 실패하거나 부정확한 결과가 나올 수 있습니다. PCM은 시작 시 이 충돌을 자동 감지하고 경고합니다.
핵심 도구 모음
PCM은 목적별로 분리된 여러 도구를 제공합니다. 각 도구는 Intel CPU의 특정 하드웨어 카운터에 최적화되어 있습니다.
pcm: 코어 성능 카운터
기본 도구로, 코어별 IPC(Instructions Per Cycle), L2/L3 캐시 히트율, 분기 예측(Branch Prediction)률 등 핵심 지표를 실시간 표시합니다.
# 기본 실행: 1초 간격으로 코어별 성능 카운터 표시
sudo pcm
# 측정 간격 및 반복 횟수 지정
sudo pcm 0.5 -i=20 # 0.5초 간격, 20회 측정
# CSV 출력 (후처리/시각화용)
sudo pcm 1 -csv=result.csv
# 특정 프로그램 실행 동안 측정
sudo pcm -- ./benchmark
# 코어 이벤트 커스텀 지정 (최대 4개 범용 카운터)
sudo pcm -e core/config=0x2e,config1=0x41,name=LLC_MISSES/
pcm 출력의 주요 지표:
| 지표 | 설명 | 정상 범위 | 이상 징후 |
|---|---|---|---|
| IPC | Instructions Per Cycle | 1.0~4.0 | < 0.5이면 심각한 메모리 스톨 |
| L2 Hit Ratio | L2 캐시 히트율 | > 95% | < 80%이면 작업 셋 > L2 |
| L3 Hit Ratio | L3 (LLC) 캐시 히트율 | > 80% | < 50%이면 메모리 대역폭 확인 필요 |
| FREQ | 실제 동작 주파수 (GHz) | 부스트 근처 | 기본 클럭 이하이면 전력/열 제한 |
| TEMP | 코어 온도 (°C) | < TjMax-10 | TjMax 도달 시 스로틀링 |
| INST | 은퇴된 명령어 수 | 워크로드 의존 | 코어 간 불균형 → 부하 분산(Load Balancing) 문제 |
| AFREQ | Active Frequency (활성 시 주파수) | ≈ Max Turbo | 기본 클럭 근처이면 전력 제한 |
| L3MISS | L3 캐시 미스 횟수 | 워크로드 의존 | 높으면 메모리 BW 병목 |
pcm-memory: 메모리 대역폭 모니터링
소켓/채널별 메모리 대역폭(Read/Write/Total)을 iMC(Integrated Memory Controller) 카운터로 실시간 측정합니다. NUMA 환경에서 메모리 병목 진단에 매우 중요한 지표입니다.
# 소켓/채널별 메모리 대역폭 측정
sudo pcm-memory
# 0.5초 간격, 파일 출력
sudo pcm-memory 0.5 -csv=mem_bw.csv
# 특정 소켓만 모니터링
sudo pcm-memory -s 0 # 소켓 0만
출력 예시:
| Socket | Read (GB/s) | Write (GB/s) | PMM Read | PMM Write | Total (GB/s) |
|---|---|---|---|---|---|
| 0 | 45.2 | 12.8 | N/A | N/A | 58.0 |
| 1 | 43.8 | 11.5 | N/A | N/A | 55.3 |
| System | 89.0 | 24.3 | N/A | N/A | 113.3 |
메모리 대역폭 포화 판단: 이론적 최대 대역폭은 채널 수 × DDR 전송률 × 8바이트로 계산됩니다. 예: 6채널 DDR5-4800 = 6 × 4800MT/s × 8B ≈ 230 GB/s. 측정값이 이론값의 70% 이상이면 메모리 BW 포화 상태입니다. perf stat -e LLC-load-misses와 함께 확인하세요.
pcm-pcie: PCIe 대역폭 모니터링
IIO(I/O 유닛) 언코어 카운터를 통해 PCIe 포트별 인바운드/아웃바운드 대역폭을 측정합니다. NVMe SSD, GPU, 네트워크 카드 등의 I/O 병목 진단에 사용합니다.
# PCIe 포트별 대역폭 (GB/s)
sudo pcm-pcie
# 이벤트 모드: Part0~Part3 상세 분류
sudo pcm-pcie -e
# 특정 BDF (Bus:Device.Function) 필터링
sudo pcm-pcie -B 0x3a:0x00.0
# CSV 출력
sudo pcm-pcie 1 -csv=pcie_bw.csv
# CXL 메모리 대역폭 모니터링 (지원 플랫폼)
sudo pcm-pcie -cxl
pcm-power: 전력 및 열 모니터링
RAPL(Running Average Power Limit) MSR과 온도 센서를 통해 패키지/DRAM/PP0/PP1별 전력 소비와 코어 온도, C-State 상주 비율을 실시간으로 표시합니다.
# 전력/온도/C-State 모니터링
sudo pcm-power
# 출력 예시:
# Package 0: Consumed energy (Joules): 85.2 | Thermal headroom: 23°C
# Package 0: C2 residency: 45.2% | C6 residency: 32.1%
# DRAM energy: 12.8 J
# 전력 변화 추세 관찰 (CSV)
sudo pcm-power 1 -csv=power.csv
pcm-latency: 메모리 레이턴시 측정
메모리 접근 레이턴시를 측정합니다. NUMA 환경에서 로컬/원격 메모리 접근 지연 차이를 정량적으로 파악할 수 있습니다.
# 메모리 레이턴시 측정
sudo pcm-latency
# 특정 소켓 대상
sudo pcm-latency -s 0
pcm-numa: NUMA 트래픽 분석
NUMA 환경에서 로컬/원격 메모리 접근 비율을 측정하여 메모리 배치 최적화 기회를 식별합니다.
# NUMA 로컬/원격 메모리 접근 비율 측정
sudo pcm-numa
# 출력 예시:
# Socket 0: Local Memory Accesses: 95.2% | Remote: 4.8%
# Socket 1: Local Memory Accesses: 87.3% | Remote: 12.7% ← 최적화 필요
# NUMA 최적화 확인: 원격 접근이 10% 이상이면
# numactl --membind 또는 cpuset으로 바인딩 조정 필요
pcm-iio: I/O 유닛 통계
IIO(I/O 유닛) 스택별 인바운드/아웃바운드 트래픽을 상세 분석합니다. PCIe 디바이스와 CPU 소켓 간 데이터 흐름을 파악합니다.
# I/O 유닛(IIO) 스택별 트래픽
sudo pcm-iio
# CSV 출력
sudo pcm-iio 1 -csv=iio.csv
pcm-raw: Raw 카운터 프로그래밍
사전 정의 도구로 측정할 수 없는 커스텀 이벤트를 JSON 기반 이벤트 정의 파일로 프로그래밍합니다. Intel SDM의 이벤트 코드를 직접 지정할 수 있습니다.
# JSON 이벤트 정의 파일 사용
sudo pcm-raw -e events.json
# 이벤트 정의 예시 (events.json):
# {
# "core": {
# "programmable": [
# { "name": "L2_MISS", "event": "0x2e", "umask": "0x41" },
# { "name": "DTLB_MISS", "event": "0x08", "umask": "0x20" }
# ]
# }
# }
# PCM 배포에 포함된 사전 정의 이벤트
ls /usr/share/pcm/PMURegisterDeclarations/
# → SPR/ ICX/ SKX/ ... (마이크로아키텍처별 이벤트 파일)
pcm-sensor-server: REST API 서버
pcm-sensor-server는 PCM 데이터를 HTTP/HTTPS REST API로 노출하여, Grafana, Prometheus, Telegraf 등 외부 모니터링 시스템과 통합합니다. 자세한 설정은 Grafana/Prometheus 대시보드 섹션을 참고하세요.
# REST API 서버 시작 (기본 포트: 9738)
sudo pcm-sensor-server
# HTTPS + 포트 지정
sudo pcm-sensor-server -p 19738 --https 443 \
--key server.key --cert server.crt
# JSON 데이터 조회
curl -s http://localhost:9738/metrics | head -20
pcm-tpmi 및 신규 플랫폼
Sapphire Rapids(SPR) 이후 Intel 서버 플랫폼은 TPMI(Topology Aware Register and PM Interface)를 도입했습니다. TPMI는 MSR 대신 MMIO 기반으로 동작하여 Secure Boot 환경에서도 사용 가능하며, 더 세밀한 토폴로지(Topology) 인식 레지스터 접근을 제공합니다.
TPMI 아키텍처
TPMI(Topology Aware Register and PM Interface)는 Intel Sapphire Rapids에서 도입된 새로운 하드웨어 인터페이스로, 다음과 같은 특징을 갖습니다:
- MMIO 기반: MSR
RDMSR/WRMSR명령어 대신 메모리 맵(Memory Map) I/O를 사용하여 CSR(Control and Status Register)에 접근 - 토폴로지 인식: 소켓/다이/타일/코어 계층 구조를 인식하는 레지스터 주소 공간(Address Space) 제공
- Secure Boot 호환:
msr드라이버 없이도intel_vsec드라이버를 통해 접근 가능 - 전력 관리 통합: RAPL, SST(Speed Select Technology), ISST 등 전력 관리 기능과 통합
# TPMI 기반 언코어 카운터 접근
sudo pcm-tpmi
# TPMI 지원 확인
ls /sys/bus/auxiliary/devices/ | grep intel_vsec
# intel_vsec 드라이버가 로드되어 있으면 TPMI 지원
# TPMI 관련 커널 드라이버 확인
lsmod | grep -E "intel_vsec|intel_tpmi|intel_pmt"
# intel_vsec: VSEC 기반 플랫폼 인터페이스
# intel_tpmi: TPMI 레지스터 MMIO 접근 (6.3+)
# intel_pmt_telemetry: PMT 텔레메트리
# TPMI sysfs 경로
ls /sys/bus/auxiliary/devices/intel_vsec.tpmi-*/
# → header, guid, num_entries, cap_offset 등
Sapphire Rapids / Emerald Rapids / Granite Rapids
PCM은 최신 Intel 서버 마이크로아키텍처를 완전히 지원합니다. 플랫폼별 주요 차이점:
| 플랫폼 | 코드명 | 출시 | PCM 주요 기능 | TPMI |
|---|---|---|---|---|
| Sapphire Rapids | SPR (Xeon 4th Gen) | 2023 | HBM 모니터링, CXL 1.1, TPMI 최초 도입, AMX 카운터 | ✅ 지원 |
| Emerald Rapids | EMR (Xeon 5th Gen) | 2024 | DDR5 6400MT/s 대역폭, 개선된 언코어 PMU, UPI 3.0 | ✅ 지원 |
| Granite Rapids | GNR (Xeon 6th Gen) | 2024 | 다수 다이 통합 (P-die + E-die), CXL 2.0, 확장 IIO | ✅ 지원 |
| Ice Lake-SP | ICX (Xeon 3rd Gen) | 2021 | UPI 2.0, PCIe Gen4, DDR4 채널 × 8 | ❌ |
| Skylake-SP | SKX/CLX | 2017~ | UPI 링크 카운터, 기본 iMC 카운터 | ❌ |
# Emerald Rapids: 향상된 메모리 대역폭 모니터링
# 소켓당 최대 12채널 DDR5-6400 ≈ 614 GB/s 이론값
sudo pcm-memory 0.5
# → 'Total Memory BW' 가 600+ GB/s에 근접하면 BW 포화 임박
# Granite Rapids: P-die / E-die 혼합 모니터링
# -die 옵션으로 다이별 분리 통계 (PCM 2.0+)
sudo pcm -die 0 # P-die 전용
sudo pcm -die 1 # E-die 전용
# SPR AMX (Advanced Matrix Extensions) 카운터
sudo pcm-raw -e /usr/share/pcm/PMURegisterDeclarations/SPR/core.json
# → AMX_OPS_SPEC, TMUL_COMPUTED_8BIT 등 행렬 연산 카운터
Sapphire Rapids HBM 모니터링: HBM(High Bandwidth Memory) 탑재 SPR-HBM 모델에서는 pcm-memory가 DDR5 채널과 HBM 채널을 구분하여 표시합니다. HBM은 소켓당 최대 1 TB/s의 이론 대역폭을 제공하며, HBM Read/Write 컬럼으로 별도 확인합니다.
CXL 메모리 모니터링
CXL(Compute Express Link)은 PCIe 물리 계층 위에 구축된 캐시/메모리 일관성 프로토콜로, CPU와 가속기/메모리 확장 장치 간의 고속 인터코넥트를 제공합니다. PCM은 IIO 카운터와 pcm-pcie -cxl 모드를 통해 CXL 장치 대역폭과 레이턴시를 측정합니다.
CXL 장치 유형과 PCM 지원
| CXL 유형 | 특징 | Linux NUMA 노드 | PCM 도구 | 대역폭 기준 |
|---|---|---|---|---|
| Type 1 | 가속기, 캐시 공유, 로컬 메모리 없음 | 별도 노드 없음 | pcm-pcie -cxl | PCIe Gen5 ×16 ≈ 128 GB/s |
| Type 2 | 가속기 + 캐시 + 로컬 메모리 | 별도 NUMA 노드 | pcm-pcie -cxl, pcm-numa | 장치 의존적 |
| Type 3 | 메모리 확장 전용 (DRAM/PMEM) | 별도 NUMA 노드 | pcm-memory, pcm-latency | CXL 1.1 ≈ 40 GB/s (Gen4 ×8) |
CXL 모니터링 실전 사용법
# 1. CXL 장치 감지 확인
ls /sys/bus/cxl/devices/
# → mem0, mem1 등 CXL 메모리 장치 나열
# → decoder0.0, region0 등 CXL 리전 표시
# 2. CXL 대역폭 모니터링 (IIO 카운터 기반)
sudo pcm-pcie -cxl
# → CXL_UPSTREAM_BANDWIDTH, CXL_DOWNSTREAM_BANDWIDTH 표시
# → IIO 스택별 CXL 포트 인바운드/아웃바운드 GB/s
# 3. CXL Type 3 메모리 대역폭 (pcm-memory)
# CXL 메모리는 NUMA 노드로 노출됨 (node 2, 3 등)
sudo pcm-memory
# → DDR 채널 외 'CXL Port' 행 확인
# 4. CXL 메모리 레이턴시 측정
sudo pcm-latency
# → Local DDR: ~75ns, Remote DDR: ~130ns, CXL: ~200-300ns (장치/토폴로지 의존)
# 5. NUMA 통계로 CXL 접근 비율 확인
sudo pcm-numa
# → CXL 노드 접근이 많으면 numactl --membind 로 바인딩 최적화
# 6. CXL 노드 정보 (커널 통합 정보)
numactl --hardware
# → CXL Type 3는 별도 NUMA 노드 (distance 매우 높음)
cat /sys/devices/system/node/node2/meminfo
# → CXL 메모리 노드의 MemTotal, MemFree 확인
CXL 레이턴시 특성: CXL Type 3 메모리는 로컬 DDR 대비 약 2~4배 높은 레이턴시(200~300ns)를 가집니다. pcm-latency로 CXL 노드 레이턴시를 측정하고, 레이턴시 민감 데이터는 numactl --membind=0으로 로컬 DDR에 할당하세요. 레이턴시 허용 가능한 대용량 데이터(캐시/버퍼(Buffer))는 CXL 노드를 활용합니다.
Grafana/Prometheus 대시보드
pcm-sensor-server는 PCM의 모든 측정값을 HTTP REST API로 노출합니다. Prometheus가 메트릭을 수집하고, Grafana가 시각화합니다. PCM 소스에는 사전 정의된 Grafana 대시보드 JSON이 포함되어 있어 즉시 임포트가 가능합니다.
스택 구성 — docker-compose
# docker-compose.yml — PCM 모니터링 스택
version: '3.8'
services:
pcm:
image: ghcr.io/intel/pcm
container_name: pcm-sensor
privileged: true
pid: host
ipc: host
volumes:
- /sys:/sys:rw
- /proc:/proc:ro
command: ["pcm-sensor-server", "-p", "9738"]
ports:
- "9738:9738"
restart: unless-stopped
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-storage:/var/lib/grafana
restart: unless-stopped
volumes:
grafana-storage:
# prometheus.yml — PCM 스크레이프 설정
global:
scrape_interval: 5s
scrape_configs:
- job_name: 'intel-pcm'
static_configs:
- targets: ['pcm:9738']
metrics_path: '/prometheus'
scrape_timeout: 4s
REST API 엔드포인트
pcm-sensor-server가 노출하는 주요 API 엔드포인트:
| 엔드포인트 | 설명 | 형식 |
|---|---|---|
GET / | 전체 PCM 메트릭 (JSON 계층 구조) | JSON |
GET /prometheus | Prometheus 형식 메트릭 | text/plain |
GET /package/{n} | 패키지 n의 상세 메트릭 | JSON |
GET /core/{n} | 코어 n의 상세 메트릭 | JSON |
GET /memory | 메모리 대역폭 메트릭 | JSON |
GET /pcie | PCIe 대역폭 메트릭 | JSON |
# Prometheus 메트릭 조회 예시
curl -s http://localhost:9738/prometheus | grep -E "pcm_(ipc|memory|freq)"
# pcm_ipc{socket="0",core="0"} 2.34
# pcm_memory_read_bandwidth{socket="0"} 45.2
# pcm_memory_write_bandwidth{socket="0"} 12.8
# pcm_freq_mhz{socket="0",core="0"} 3800
# JSON 전체 메트릭 구조 확인
curl -s http://localhost:9738/ | python3 -m json.tool | head -40
Grafana 대시보드 임포트
# PCM 소스의 Grafana 대시보드 JSON 위치
ls /path/to/pcm/grafana/
# → PCM-Core-Metrics.json (코어별 IPC, 캐시, 주파수)
# → PCM-Memory-Bandwidth.json (소켓/채널별 메모리 BW)
# → PCM-Power-Thermal.json (전력 소비, 온도, C-State)
# → PCM-PCIe-Bandwidth.json (PCIe 포트별 대역폭)
# Grafana API로 자동 임포트
curl -X POST http://admin:admin@localhost:3000/api/dashboards/import \
-H 'Content-Type: application/json' \
-d @PCM-Core-Metrics.json
Grafana 알람 설정: Prometheus + Grafana 조합에서 알람 규칙 예시: pcm_memory_read_bandwidth{socket="0"} > 200 (메모리 BW 포화), pcm_ipc < 0.5 (IPC 급락), pcm_freq_mhz < 2000 (주파수 스로틀링). Alertmanager를 통해 Slack/PagerDuty로 알림을 발송합니다.
실전 진단 시나리오
PCM 도구를 결합하여 실제 성능 문제를 단계별로 진단하는 시나리오입니다.
시나리오 1: 메모리 대역폭 포화 진단
애플리케이션이 CPU 사용률은 높지만 IPC가 낮은 경우, 메모리 대역폭 포화가 원인일 수 있습니다:
# 1단계: IPC 확인 → 메모리 바운드 여부 판단
sudo pcm 1 -i=5
# → IPC < 1.0 + L3 Hit Ratio < 50% → 메모리 바운드 의심
# 2단계: 메모리 대역폭 측정
sudo pcm-memory 0.5
# → Read BW가 이론값의 70% 이상이면 BW 포화
# → 채널 간 불균형이 크면 DIMM 구성 확인
# 3단계: NUMA 배치 확인
sudo pcm-numa
# → Remote Access > 10%이면 메모리 배치 최적화
# → numactl --membind=0 ./app 으로 로컬 바인딩
# 4단계: perf로 핫스팟 함수의 LLC 미스 확인
perf record -e LLC-load-misses:pp -c 10000 -- ./app
perf report
시나리오 2: PCIe I/O 병목 진단
# NVMe/GPU가 예상 성능에 미달할 때
# 1단계: PCIe 대역폭 측정
sudo pcm-pcie 1
# → 디바이스별 인바운드/아웃바운드 BW 확인
# → Gen4 x16: 이론 31.5 GB/s, 실측이 50% 미만이면 문제
# 2단계: IIO 스택별 상세 분석
sudo pcm-iio 1
# → 어느 IIO 스택에서 병목이 발생하는지 파악
# 3단계: 전력 제한 확인 (전력 제한으로 I/O 성능 저하 가능)
sudo pcm-power 1
# → PKG 전력이 TDP 근처이면 전력 스로틀링
시나리오 3: 코어 주파수 스로틀링 진단
# 성능이 간헐적으로 저하될 때 (열/전력 제한 의심)
sudo pcm 0.5 -csv=freq_trace.csv -i=60
# → FREQ/AFREQ 컬럼에서 주파수 변동 추적
# → TEMP가 TjMax에 근접하면 열 스로틀링
# → C6 residency가 높으면 idle 상태 비율 과다
# turbostat 병행 (PCM과 보완적)
sudo turbostat --interval 1 --show Core,CPU,Avg_MHz,Busy%,Bzy_MHz,PkgWatt
# Busy% 100%인데 Bzy_MHz < Max Turbo이면 전력/열 제한
시나리오 4: NUMA 불균형 진단
다소켓 서버에서 특정 소켓만 메모리 BW가 높거나, 원격 메모리 접근이 많은 경우:
# 1단계: 소켓별 메모리 대역폭 불균형 확인
sudo pcm-memory 1
# → Socket 0: 90 GB/s, Socket 1: 10 GB/s → 심각한 불균형
# → 원인: 특정 소켓에 스레드가 집중되거나 메모리가 쏠림
# 2단계: NUMA 로컬/원격 접근 비율 상세 확인
sudo pcm-numa 1
# → Remote Access > 20%이면 매우 비효율적
# 3단계: 프로세스 NUMA 배치 확인
numastat -p $(pgrep -d, myapp)
# → 프로세스가 사용하는 각 NUMA 노드 메모리량 표시
# 4단계: 해결 — numactl로 CPU+메모리 바인딩
numactl --cpunodebind=0 --membind=0 ./myapp
# 또는 인터리브로 균등 분산:
numactl --interleave=all ./myapp
# 5단계: Automatic NUMA Balancing 활성화 확인
cat /proc/sys/kernel/numa_balancing
# 0이면 비활성 → echo 1 로 활성화 (자동 페이지 마이그레이션)
시나리오 5: LLC 쓰레싱 진단
L3 캐시 히트율이 낮고 메모리 대역폭이 높은 경우, 여러 프로세스 간 LLC 경합(쓰레싱)이 원인일 수 있습니다:
# 1단계: LLC 쓰레싱 여부 확인 (IPC + L3 히트율)
sudo pcm 1
# → L3 Hit Ratio < 40% + pcm-memory가 높은 BW → LLC 쓰레싱 의심
# 2단계: perf c2c로 캐시 라인 경합 확인
sudo perf c2c record -- ./workload
sudo perf c2c report --call-graph none | head -30
# → 'Shared Cache Line Distribution' 에서 경합 심한 캐시 라인 확인
# 3단계: Intel RDT(Resource Director Technology)로 LLC 파티션
# 코어 별 LLC 사용량을 resctrl로 제한 (Intel CAT)
mount -t resctrl resctrl /sys/fs/resctrl
mkdir /sys/fs/resctrl/workload_A
echo "L3:0=0x0ff" > /sys/fs/resctrl/workload_A/schemata # 하위 8way 할당
echo $(pgrep workload_A) > /sys/fs/resctrl/workload_A/tasks
# 4단계: 캐시 친화적 재구성
# → 핫 데이터 구조체에 __cacheline_aligned 적용
# → 스레드 간 공유 데이터 최소화 (false sharing 제거)
# → 큰 배열을 청크로 나눠 한 번에 LLC에 맞게 처리 (타일링)
시나리오 6: C-State 레지던시 분석
서버 워크로드에서 레이턴시 급등(jitter)이 발생하는 경우, 깊은 C-State에 진입한 코어가 재활성화되는 시간이 원인일 수 있습니다:
# 1단계: C-State 분포 확인
sudo pcm-power 1 -csv=cstate.csv
# → C6/C7 residency > 50%이면 레이턴시 민감 워크로드에 위험
# 2단계: turbostat으로 코어별 C-State 상세 확인
sudo turbostat --interval 1 \
--show Core,CPU,Busy%,C1%,C3%,C6%,C7%,PkgWatt
# → 특정 코어가 C7에 자주 진입하면 wake-up latency 수십 µs 발생
# 3단계: C-State 제한으로 레이턴시 개선
# 방법 1: 커널 파라미터로 전역 제한
# intel_idle.max_cstate=1 (grub GRUB_CMDLINE_LINUX에 추가)
# 방법 2: per-CPU C-State 제한 (런타임)
cpupower idle-set -D 1 # 모든 코어 C-State ≤ C1으로 제한
# 방법 3: 특정 코어만 C-State 제한
echo 1 > /sys/devices/system/cpu/cpu0/cpuidle/state2/disable # C6 비활성화
# 4단계: 결과 검증
sudo pcm-power 1
# → C6 residency ≈ 0% 확인 → 레이턴시 측정으로 jitter 개선 확인
PMU 프로그래밍 내부 구조
PCM이 하드웨어 카운터에 접근하는 세부 메커니즘을 이해하면, 커스텀 이벤트 프로그래밍과 트러블슈팅에 큰 도움이 됩니다. Intel CPU의 PMU(Performance Monitoring Unit)는 코어 PMU와 언코어 PMU로 나뉘며, 각각 다른 MSR 주소와 이벤트 코딩 방식을 사용합니다.
코어 PMU 카운터 프로그래밍
코어 PMU는 고정 카운터(Fixed Counter) 3개와 범용 카운터(General-Purpose Counter) 4~8개로 구성됩니다. PCM은 이 카운터들을 프로그래밍하여 IPC, 캐시 히트율, 분기 예측률 등을 측정합니다.
/* 커널의 Core PMU 초기화 (arch/x86/events/intel/core.c)
* PCM은 user space에서 MSR을 직접 쓰지만, 커널 perf도 같은 레지스터를 사용 */
static void intel_pmu_enable_event(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
if (unlikely(idx == INTEL_PMC_IDX_FIXED_BTS)) {
/* BTS (Branch Trace Store) 특수 처리 */
intel_pmu_enable_bts(hwc->config);
return;
}
if (is_fixed_event(idx)) {
/* 고정 카운터: IA32_FIXED_CTR_CTRL에 모드 비트 설정 */
intel_pmu_enable_fixed(hwc);
} else {
/* 범용 카운터: IA32_PERFEVTSELx에 이벤트 코드 기록
* config = Event(7:0) | Umask(15:8) | USR(16) | OS(17) | EN(22) */
wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + idx, hwc->config);
}
/* IA32_PERF_GLOBAL_CTRL에서 해당 카운터 비트 활성화 */
intel_pmu_enable_counter(hwc, idx);
}
/* PERFEVTSELx 레지스터 비트 필드 구조:
* [7:0] Event Select — SDM에서 정의된 이벤트 번호
* [15:8] Unit Mask — 이벤트의 세부 분류
* [16] USR — User mode 카운트 여부
* [17] OS — Kernel mode 카운트 여부
* [18] Edge — 에지 디텍트 모드
* [22] EN — 카운터 활성화
* [23] INV — Threshold 반전
* [31:24] CounterMask — Threshold 값 */
언코어 PMU 등록 구조
언코어 PMU는 메모리 컨트롤러(iMC), QPI/UPI 링크, CBox(LLC 슬라이스), IIO(PCIe I/O) 등 코어 외부 하드웨어 유닛에 대한 성능 카운터를 제공합니다. 커널에서 intel_uncore 드라이버가 이들을 perf 서브시스템에 등록하는 구조를 살펴보겠습니다.
/* 언코어 PMU 타입 정의 (arch/x86/events/intel/uncore.h) */
struct intel_uncore_type {
const char *name; /* PMU 이름 (예: "imc", "upi") */
unsigned num_counters; /* 사용 가능 카운터 수 */
unsigned num_boxes; /* 인스턴스 수 (소켓당) */
unsigned perf_ctr_bits; /* 카운터 비트 폭 (48비트 등) */
unsigned perf_ctr; /* 카운터 MSR 베이스 주소 */
unsigned event_ctl; /* 이벤트 제어 MSR 베이스 주소 */
unsigned event_mask; /* 이벤트 선택 마스크 */
struct attribute_group *attr_groups[4]; /* sysfs 속성 */
const struct intel_uncore_ops *ops; /* HW 접근 콜백 */
};
/* Sapphire Rapids iMC(메모리 컨트롤러) 언코어 정의
* (arch/x86/events/intel/uncore_snbep.c) */
static struct intel_uncore_type spr_uncore_imc = {
.name = "imc",
.num_counters = 4,
.num_boxes = 12, /* SPR: 소켓당 최대 12채널 */
.perf_ctr_bits = 48,
.perf_ctr = SNR_IMC_MMIO_PMON_CTR0,
.event_ctl = SNR_IMC_MMIO_PMON_CTL0,
.event_mask = SNBEP_PMON_RAW_EVENT_MASK,
.ops = &spr_uncore_mmio_ops,
.attr_groups = spr_uncore_imc_formats_attr,
};
/* pcm-memory가 측정하는 것과 동일한 카운터:
* iMC의 CAS_COUNT.RD / CAS_COUNT.WR 이벤트로
* 채널별 DRAM Read/Write 트랜잭션을 카운트 */
카운터 오버플로와 멀티플렉싱: 코어 PMU의 범용 카운터는 4~8개로 제한됩니다. 측정하려는 이벤트가 카운터 수보다 많으면, PCM(및 perf)은 카운터를 시분할(멀티플렉싱)하여 통계적으로 추정합니다. 멀티플렉싱이 발생하면 값의 정밀도가 떨어지므로, pcm의 커스텀 이벤트 수를 범용 카운터 수(보통 4개) 이내로 유지하는 것이 좋습니다. perf stat에서 not counted 또는 appended 표시가 나타나면 멀티플렉싱이 발생한 것입니다.
perf_event 인터페이스를 통한 접근
PCM은 PCM_USE_PERF=1 환경 변수가 설정되면 MSR 직접 접근 대신 커널의 perf_event_open() 시스템 콜(System Call)을 사용합니다. 이 경로는 커널이 카운터 소유권을 관리하므로 다른 프로파일링 도구와 충돌을 방지할 수 있습니다.
/* perf_event_open()으로 언코어 iMC 카운터 접근하는 원리 */
struct perf_event_attr attr;
memset(&attr, 0, sizeof(attr));
attr.type = type_id; /* /sys/bus/event_source/devices/uncore_imc_0/type */
attr.config = 0x0304; /* CAS_COUNT.RD: event=0x04, umask=0x03 */
attr.size = sizeof(attr);
attr.disabled = 1;
/* cpu 파라미터: 언코어 PMU의 경우 NUMA 노드의 대표 CPU 지정
* pid = -1: 시스템 전체 (프로세스 무관) */
int fd = perf_event_open(&attr, -1 /* pid */, cpu, -1 /* group */, 0);
/* 카운터 활성화 */
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
/* 카운터 값 읽기 */
uint64_t count;
read(fd, &count, sizeof(count));
/* 언코어 PMU type_id 확인 방법:
* cat /sys/bus/event_source/devices/uncore_imc_0/type
* → 예: 15 (시스템마다 다름)
*
* 사용 가능 이벤트 확인:
* ls /sys/bus/event_source/devices/uncore_imc_0/events/
* → cas_count_read, cas_count_write, clockticks 등 */
# perf로 언코어 iMC 카운터 직접 접근 (pcm-memory와 동일 데이터)
sudo perf stat -e uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/ \
-a sleep 5
# → CAS_COUNT.RD × 64B = Read 바이트 수
# → CAS_COUNT.WR × 64B = Write 바이트 수
# 사용 가능한 언코어 PMU 목록 확인
ls /sys/bus/event_source/devices/ | grep uncore
# → uncore_arb, uncore_cbox_0, uncore_imc_0, uncore_upi_0 등
# UPI 링크 대역폭 (소켓 간 인터코넥트)
sudo perf stat -e uncore_upi_0/event=0x02,umask=0x0f/ -a sleep 5
# → UPI Data Flits × 8B = UPI 전송 바이트
보안 및 권한 모델
PCM은 하드웨어 레지스터에 직접 접근하므로 보안 관점에서 여러 고려사항이 있습니다. 프로덕션 환경에서의 안전한 배포 방법을 소개합니다.
접근 제어(Access Control) 계층
| 접근 경로 | 권한 요구사항 | 보안 수준 | 제약사항 |
|---|---|---|---|
| MSR 직접 접근 | root 또는 CAP_SYS_RAWIO | 최저 (전체 MSR 노출) | Secure Boot에서 차단 가능, MSR 레지스터 필터링 없음 |
| perf_event | perf_event_paranoid 설정 의존 | 중간 (커널 매개) | 일부 언코어 카운터 미지원 |
| TPMI/MMIO | intel_vsec 드라이버 권한 | 높음 (드라이버 매개) | SPR+ 전용, 드라이버 필요 |
# perf_event_paranoid 설정값별 의미
# -1: 제한 없음 (root와 동일)
# 0: CPU 이벤트 접근 허용, 트레이싱 제한
# 1: 커널 프로파일링 제한 (기본값)
# 2: 커널 프로파일링 + 시스템 전체 프로파일링 제한
# 3: 모든 perf_event 사용 제한 (Debian 계열 기본)
# 현재 설정 확인
cat /proc/sys/kernel/perf_event_paranoid
# PCM perf_event 모드에서 필요한 최소 설정
sudo sysctl kernel.perf_event_paranoid=0
# Secure Boot 환경에서 MSR 접근 상태 확인
dmesg | grep -i "msr\|lockdown"
# "Lockdown: msr: direct MSR access is restricted" → MSR 차단됨
# → PCM_USE_PERF=1 또는 pcm-tpmi 사용
# capabilities 기반 권한 부여 (root 없이 PCM 실행)
sudo setcap cap_sys_rawio+ep /usr/sbin/pcm
sudo setcap cap_sys_rawio+ep /usr/sbin/pcm-memory
# 주의: MSR 접근 권한이므로 신뢰할 수 있는 사용자에게만 부여
프로덕션 보안 주의: MSR 직접 접근(/dev/cpu/*/msr)은 임의의 MSR을 읽고 쓸 수 있어 보안 위험이 있습니다. 프로덕션 환경에서는 PCM_USE_PERF=1 모드를 사용하거나, pcm-sensor-server를 격리(Isolation)된 컨테이너(Container)에서 실행하고 REST API로만 데이터를 수집하는 것을 권장합니다. Secure Boot가 활성화된 환경에서는 MSR 쓰기가 커널 lockdown 정책에 의해 차단됩니다.
컨테이너 환경 배포
Kubernetes나 Docker 환경에서 PCM을 안전하게 운영하는 방법:
# Kubernetes DaemonSet — 각 노드에서 pcm-sensor-server 실행
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: pcm-sensor
namespace: monitoring
spec:
selector:
matchLabels:
app: pcm-sensor
template:
metadata:
labels:
app: pcm-sensor
spec:
hostPID: true
hostIPC: true
containers:
- name: pcm
image: ghcr.io/intel/pcm:latest
command: ["pcm-sensor-server", "-p", "9738"]
securityContext:
privileged: true # MSR 접근에 필요
volumeMounts:
- name: sys
mountPath: /sys
- name: proc
mountPath: /proc
readOnly: true
ports:
- containerPort: 9738
name: metrics
volumes:
- name: sys
hostPath:
path: /sys
- name: proc
hostPath:
path: /proc
이벤트 필터링과 고급 기법
PCM의 pcm-raw 도구와 커널 perf 서브시스템을 활용한 고급 이벤트 프로그래밍 기법을 소개합니다.
JSON 이벤트 정의 파일 상세
PCM은 Intel SDM(Software Developer's Manual)에 정의된 수백 개의 성능 이벤트를 JSON 파일로 관리합니다. 마이크로아키텍처별 이벤트 파일이 PCM 배포에 포함되어 있으며, 커스텀 이벤트를 직접 정의할 수도 있습니다.
{
"core": {
"fixed": true,
"programmable": [
{
"name": "L2_RQSTS.ALL_DEMAND_MISS",
"event": "0x24",
"umask": "0x27",
"description": "L2 캐시 수요 미스 (코드+데이터)"
},
{
"name": "MEM_LOAD_RETIRED.L3_MISS",
"event": "0xD1",
"umask": "0x20",
"description": "L3 미스로 DRAM까지 간 로드"
},
{
"name": "DTLB_LOAD_MISSES.WALK_COMPLETED",
"event": "0x08",
"umask": "0x0E",
"description": "DTLB 미스로 페이지 워크 완료"
}
]
},
"uncore": {
"imc": [
{
"name": "CAS_COUNT.RD",
"event": "0x04",
"umask": "0x03",
"description": "DRAM Read CAS 명령 횟수"
},
{
"name": "CAS_COUNT.WR",
"event": "0x04",
"umask": "0x0C",
"description": "DRAM Write CAS 명령 횟수"
}
]
}
}
# 커스텀 이벤트 파일로 pcm-raw 실행
sudo pcm-raw -e my_events.json -csv=result.csv 1 -i=10
# PCM 배포의 사전 정의 이벤트 파일 확인
ls /usr/share/pcm/PMURegisterDeclarations/
# → SPR/ EMR/ GNR/ ICX/ SKX/ CLX/
# 각 아키텍처별 이벤트 파일 구조
ls /usr/share/pcm/PMURegisterDeclarations/SPR/
# → core.json (코어 PMU 이벤트)
# → uncore_imc.json (메모리 컨트롤러)
# → uncore_upi.json (UPI 링크)
# → uncore_iio.json (PCIe I/O)
# → uncore_cha.json (CHA / LLC 슬라이스)
# Intel 이벤트 코드 온라인 참조
# https://perfmon-events.intel.com/ (공식 이벤트 DB)
카운팅 모드 vs 샘플링 모드
PCM은 기본적으로 카운팅 모드(일정 간격으로 카운터 값을 읽는 방식)를 사용합니다. 반면 perf record는 샘플링 모드(카운터 오버플로 시 인터럽트(Interrupt)를 발생시켜 IP/콜스택을 기록)를 사용합니다. 두 모드의 차이를 이해하면 적절한 도구를 선택할 수 있습니다.
| 특성 | 카운팅 모드 (PCM) | 샘플링 모드 (perf record) |
|---|---|---|
| 데이터 | 전체 이벤트 수 (정확) | 이벤트 발생 위치의 통계적 분포 |
| 오버헤드(Overhead) | 매우 낮음 (주기적 MSR 읽기) | 중간~높음 (인터럽트 + 콜스택 기록) |
| 출력 | 시스템 전체 집계 수치 | 함수/명령어별 이벤트 분포 |
| 용도 | 시스템 수준 병목 탐지 | 핫스팟 함수/코드 라인 식별 |
| 프로세스 지정 | 시스템 전체 (프로세스 무관) | 특정 프로세스/스레드(Thread) 가능 |
| 조합 전략 | PCM으로 시스템 병목 식별 → perf record로 핫스팟 드릴다운 | |
트러블슈팅 가이드
PCM 사용 중 자주 발생하는 오류와 해결 방법을 정리합니다.
주요 오류 메시지와 해결
| 오류 메시지 | 원인 | 해결 방법 |
|---|---|---|
Can not access MSR. Try to load the msr driver | msr 커널 모듈 미로드 | sudo modprobe msr |
Access to Intel different from different different performance monitoring unit | 다른 프로파일링 도구가 카운터 점유 | perf, VTune, likwid 등 종료 후 재시도 |
NMI watchdog is enabled. Consider disabling | NMI watchdog가 고정 카운터 점유 | sudo sysctl kernel.nmi_watchdog=0 |
Error: PMU counter programming | Secure Boot/lockdown에 의한 MSR 쓰기 차단 | export PCM_USE_PERF=1 또는 TPMI 모드 |
Unsupported processor model | PCM 버전이 CPU 모델 미지원 | PCM 최신 버전으로 업데이트 |
perf_event_open failed | perf_event_paranoid 값이 높음 | sudo sysctl kernel.perf_event_paranoid=-1 |
No uncore PMUs detected | VM 환경이거나 언코어 드라이버 미로드 | sudo modprobe intel_uncore, 베어메탈 확인 |
가상화(Virtualization) 환경에서의 PCM
가상 머신(VM)에서 PCM을 사용하려면 하이퍼바이저(Hypervisor)가 PMU 가상화를 지원해야 합니다:
# KVM에서 PMU passthrough 확인
# QEMU 실행 시 -cpu host,+pmu 옵션으로 PMU 노출
qemu-system-x86_64 -cpu host,+pmu -enable-kvm ...
# VM 내에서 PMU 지원 확인
dmesg | grep -i "performance monitoring"
# "Performance Events: Intel PMU driver" → PMU 사용 가능
# VM에서의 제약사항:
# - 코어 PMU: PMU passthrough 활성화 시 대부분 동작
# - 언코어 PMU: 일반적으로 동작하지 않음 (하이퍼바이저가 차단)
# - pcm-memory, pcm-pcie, pcm-numa: 언코어 접근 필요 → 베어메탈 전용
# - pcm (코어 카운터): PMU passthrough 시 동작 가능
# vPMU가 지원되는지 확인 (KVM)
cat /sys/module/kvm_intel/parameters/enable_pmu
# Y → KVM에서 PMU 활성화됨
# AWS/GCP/Azure 등 클라우드 환경:
# - AWS: 전용 호스트(Dedicated Host)에서 PMU 접근 가능
# - GCP: Sole-tenant 노드에서 제한적 지원
# - 공유 인스턴스: PMU 접근 불가 → perf stat 제한적 사용
VM에서의 PCM 제약: 언코어 카운터(메모리 컨트롤러, UPI, PCIe)는 소켓/물리 하드웨어에 종속되므로 가상 환경에서 접근할 수 없습니다. pcm-memory, pcm-pcie, pcm-numa 등은 베어메탈 환경 전용입니다. VM에서는 코어 PMU 기반인 pcm(IPC, 캐시 히트율)만 제한적으로 사용 가능합니다.
카운터 충돌 해결
여러 모니터링 도구가 동시에 PMU 카운터를 사용하려 하면 충돌이 발생합니다:
# 카운터를 점유 중인 프로세스 확인
sudo perf stat -e cycles:u true 2>&1 | grep -i "not counted\|error"
# 오류가 나면 다른 도구가 카운터를 점유 중
# PCM 강제 리셋 (다른 도구가 카운터를 놓지 않을 때)
sudo pcm -r
# → 모든 코어/언코어 PMU 카운터를 초기화
# 카운터 사용 현황 확인
cat /sys/bus/event_source/devices/cpu/nr_addr_filters
cat /sys/bus/event_source/devices/cpu/caps/max_precise
# PCM과 perf 동시 사용 권장 방법:
# 1. PCM_USE_PERF=1로 perf 경로 통해 접근 → 커널이 중재
# 2. perf와 PCM이 다른 카운터 세트를 사용하도록 조율
# 3. 시간을 나눠 번갈아 측정 (멀티플렉싱 없이 정확도 유지)
실무 자동화 스크립트
반복적인 PCM 측정을 자동화하는 셸 스크립트 예제입니다.
시스템 헬스 체크 스크립트
#!/bin/bash
# pcm-health-check.sh — PCM 기반 시스템 성능 헬스 체크
# 사용법: sudo ./pcm-health-check.sh [측정시간(초)]
DURATION=${1:-5}
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTDIR="/tmp/pcm-health-${TIMESTAMP}"
mkdir -p "${OUTDIR}"
# 1. 전제조건 확인
if ! lsmod | grep -q msr; then
echo "[WARN] msr 모듈이 로드되지 않았습니다. 로드합니다..."
modprobe msr
fi
if [[ $(cat /proc/sys/kernel/nmi_watchdog) -ne 0 ]]; then
echo "[WARN] NMI watchdog 활성 상태. 비활성화합니다..."
sysctl -w kernel.nmi_watchdog=0
fi
# 2. 코어 카운터 수집
echo "[INFO] 코어 성능 카운터 수집 (${DURATION}초)..."
pcm 1 -i=${DURATION} -csv="${OUTDIR}/core.csv" > /dev/null 2>&1
# 3. 메모리 대역폭 수집
echo "[INFO] 메모리 대역폭 수집..."
pcm-memory 1 -i=${DURATION} -csv="${OUTDIR}/memory.csv" > /dev/null 2>&1
# 4. 전력/온도 수집
echo "[INFO] 전력/온도 수집..."
pcm-power 1 -i=${DURATION} -csv="${OUTDIR}/power.csv" > /dev/null 2>&1
# 5. 간단한 판정
echo "=================================="
echo "PCM Health Check Report: ${TIMESTAMP}"
echo "=================================="
echo "결과 파일: ${OUTDIR}/"
echo " - core.csv : IPC, 캐시 히트율, 주파수"
echo " - memory.csv : 소켓별 메모리 대역폭"
echo " - power.csv : 패키지 전력, 온도, C-State"
echo "=================================="
메모리 대역폭 알림 스크립트
#!/bin/bash
# pcm-bw-alert.sh — 메모리 대역폭 임계값 초과 시 알림
# 사용법: sudo ./pcm-bw-alert.sh [임계값(GB/s)] [체크간격(초)]
THRESHOLD=${1:-150} # 기본 임계값: 150 GB/s
INTERVAL=${2:-5} # 기본 체크 간격: 5초
echo "[INFO] 메모리 대역폭 모니터링 시작 (임계: ${THRESHOLD} GB/s)"
while true; do
# pcm-memory 1회 측정, System Total BW 추출
BW=$(pcm-memory 1 -i=1 2>/dev/null | \
grep -i "system" | awk '{print $NF}' | head -1)
if [[ -n "${BW}" ]]; then
# 정수 비교를 위해 소수점 제거
BW_INT=${BW%.*}
if [[ ${BW_INT} -gt ${THRESHOLD} ]]; then
echo "[ALERT] $(date): 메모리 BW ${BW} GB/s > 임계값 ${THRESHOLD} GB/s!"
# 추가 동작: Slack/PagerDuty webhook 호출 등
else
echo "[OK] $(date): 메모리 BW ${BW} GB/s"
fi
fi
sleep ${INTERVAL}
done
TMA Top-Down 분석 연계
Intel의 Top-Down Microarchitecture Analysis (TMA) 방법론은 CPU 파이프라인의 병목을 4개 대분류(Frontend Bound, Backend Bound, Bad Speculation, Retiring)로 분류합니다. PCM과 pmu-tools/toplev을 결합하면 체계적인 병목 분석이 가능합니다.
# pmu-tools 설치
git clone https://github.com/andikleen/pmu-tools.git
cd pmu-tools
# toplev: TMA Level 1 (대분류) 분석
sudo python3 toplev.py --core S0-C0 -l1 -v -- ./benchmark
# 출력: FE(Frontend) 30%, BE(Backend) 45%, BadSpec 5%, Retiring 20%
# → Backend Bound가 지배적 → 메모리/코어 바운드 분석 필요
# Level 2: Backend Bound 상세 분해
sudo python3 toplev.py --core S0-C0 -l2 -v -- ./benchmark
# → Memory Bound 35%, Core Bound 10%
# Level 3+: Memory Bound 세부 원인
sudo python3 toplev.py --core S0-C0 -l3 --nodes '!+Memory*' -v -- ./benchmark
# → L3 Bound 8%, DRAM Bound 22%, Store Bound 5%
# → pcm-memory로 DRAM BW 포화 확인
# PCM + toplev 병행 워크플로
# 1. pcm: 전체 시스템 IPC/캐시/주파수 개요 → 이상 징후 파악
# 2. toplev -l1~l3: 병목 카테고리 좁히기
# 3. pcm-memory/pcm-pcie: 구체적 하드웨어 병목 수치 확인
# 4. perf record + annotate: 함수/명령어 수준 최적화
PCM vs 대안 도구 비교
| 도구 | 제공자 | 카운터 접근 | 강점 | 제한 |
|---|---|---|---|---|
| Intel PCM | Intel (오픈소스) | MSR, perf_event, MMIO | 언코어 카운터 (iMC, UPI, IIO) 통합, REST API, CXL 지원 | Intel CPU 전용 |
| perf | 커널 내장 | perf_event | 범용 프로파일링, 프로세스/함수 수준 분석 | 언코어 카운터 설정 복잡 |
| turbostat | 커널 소스 포함 | MSR | 주파수/전력/C-State 특화, 커널과 함께 배포 | 성능 카운터 제한적 |
| pmu-tools (toplev) | Andi Kleen | perf 위에 구축 | Top-Down 마이크로아키텍처 분석 (TMA) 자동화 | 설정 복잡, Intel 전용 |
| likwid | RRZE (독일) | MSR, perf_event | Intel + AMD 지원, 그룹 기반 측정 | 언코어 카운터 PCM보다 제한적 |
| AMD uProf | AMD | MSR, perf_event | AMD 전용 언코어 카운터, Infinity Fabric 모니터링 | AMD CPU 전용 |
커널 드라이버 및 관련 소스
PCM이 내부적으로 사용하는 커널 인프라:
| 커널 드라이버/인터페이스 | 경로 | 역할 |
|---|---|---|
msr 모듈 | arch/x86/kernel/msr.c | /dev/cpu/N/msr 문자 장치(Character Device) 제공 |
intel_uncore PMU | arch/x86/events/intel/uncore*.c | perf 서브시스템에 언코어 PMU 등록 |
intel_rapl | drivers/powercap/intel_rapl_*.c | RAPL 전력 측정 (powercap 프레임워크) |
intel_vsec/tpmi | drivers/platform/x86/intel/tpmi.c | TPMI 레지스터 MMIO 접근 (6.3+) |
intel-cstate PMU | arch/x86/events/intel/cstate.c | C-State 상주 시간 카운터 |
| PCI config space | /sys/bus/pci/devices/*/config | 언코어 PCI 레지스터 접근 (iMC, UPI) |
/* PCM이 MSR을 읽는 커널 경로 (arch/x86/kernel/msr.c) */
static ssize_t msr_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
u32 __user *tmp = (u32 __user *)buf;
u32 data[2];
u32 reg = *ppos; /* MSR 주소 = file offset */
int cpu = iminor(file->f_path.dentry->d_inode);
int err;
/* 해당 CPU에서 RDMSR 실행 */
err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
if (err)
return -EIO;
if (copy_to_user(tmp, &data, 8))
return -EFAULT;
return 8;
}
/* PCM의 실제 MSR 읽기 (user space → /dev/cpu/N/msr) */
/* pread(fd, &data, sizeof(data), MSR_ADDR) */
/* 예: pread(fd, &val, 8, 0x38F) → IA32_PERF_GLOBAL_CTRL */
# PCM에 필요한 커널 설정
CONFIG_X86_MSR=m # /dev/cpu/*/msr (필수)
CONFIG_PERF_EVENTS=y # perf_event 모드 사용 시
CONFIG_INTEL_UNCORE=m # 언코어 PMU (perf_event 경유 시)
CONFIG_INTEL_RAPL=m # RAPL 전력 측정
CONFIG_INTEL_VSEC=m # TPMI 지원 (SPR+ 서버)
CONFIG_INTEL_PMT_TELEMETRY=m # PMT 텔레메트리
# msr 모듈 자동 로드 설정
echo "msr" | sudo tee /etc/modules-load.d/msr.conf
perf_event 모드 vs MSR 직접 접근: PCM_USE_PERF=1 환경 변수를 설정하면 PCM이 MSR 직접 접근 대신 perf_event_open()을 통해 카운터에 접근합니다. 이 모드는 msr 커널 모듈이 불필요하고, perf_event_paranoid로 권한을 세밀하게 제어할 수 있습니다. 다만 일부 언코어 카운터는 perf_event로 접근이 불가하므로 MSR 모드가 더 완전한 데이터를 제공합니다.
커널 perf 서브시스템과의 통합
PCM과 커널의 perf 서브시스템은 같은 하드웨어 PMU를 공유합니다. 두 도구의 내부 동작을 이해하면 효과적인 조합 전략을 수립할 수 있습니다.
PCM + perf 병행 워크플로
# 실전 예: 데이터베이스 워크로드 병목 분석 전체 과정
# 1단계: PCM으로 시스템 전체 상태 파악 (5초간)
sudo pcm 1 -i=5 -csv=overview.csv
# → IPC=0.8, L3 Hit=45%, FREQ=3.2GHz (Base=2.1) → 메모리 바운드 의심
# 2단계: 메모리 대역폭 확인
sudo pcm-memory 1 -i=5
# → Socket 0: Read=89GB/s, Write=22GB/s (DDR5-4800 6ch 이론 230GB/s)
# → BW 포화는 아님 → 레이턴시 문제? → LLC 미스 확인
# 3단계: toplev로 TMA 분류
sudo python3 toplev.py --core S0-C0 -l2 -v -- sleep 5
# → Backend_Bound.Memory_Bound: 38% → DRAM 레이턴시 문제
# 4단계: perf로 LLC 미스가 많은 함수 식별
sudo perf record -e LLC-load-misses:pp -c 10000 -p $(pgrep mysqld) sleep 10
sudo perf report --sort=dso,symbol
# → handler_read_key()에서 LLC 미스 집중
# 5단계: NUMA 배치 확인 및 최적화
sudo pcm-numa 1 -i=3
# → Socket 0: Remote 15% → numactl 바인딩으로 개선
numactl --cpunodebind=0 --membind=0 mysqld
perf로 언코어 이벤트 직접 사용하기
PCM 없이 perf 도구만으로도 언코어 카운터에 접근할 수 있습니다. PCM이 설치되지 않은 환경에서 유용합니다.
# 사용 가능한 언코어 PMU 이벤트 목록
sudo perf list | grep uncore
# → uncore_imc_0/cas_count_read/
# → uncore_imc_0/cas_count_write/
# → uncore_upi_0/data_bandwidth_tx/
# → uncore_cha_0/llc_lookup.any/
# 메모리 대역폭 측정 (pcm-memory와 동등)
sudo perf stat -e uncore_imc_0/cas_count_read/,\
uncore_imc_0/cas_count_write/,\
uncore_imc_1/cas_count_read/,\
uncore_imc_1/cas_count_write/ \
-a --per-socket sleep 5
# CAS_COUNT × 64바이트 / 측정시간 = 대역폭 (B/s)
# LLC 점유율 모니터링 (RDT/CMT 대안)
sudo perf stat -e uncore_cha_0/llc_lookup.any/ -a sleep 5
# UPI 대역폭 측정 (소켓 간 트래픽)
sudo perf stat -e uncore_upi_0/data_bandwidth_tx/ -a sleep 5
TMA Top-Down Level 1-4
Intel의 TMA(Top-Down Microarchitecture Analysis) 방법론은 CPU 파이프라인 병목을 계층적으로 분류하는 프레임워크입니다. PCM과 pmu-tools의 toplev.py를 결합하면 Level 1(대분류)부터 Level 4(개별 이벤트)까지 파이프라인 비효율의 정확한 원인을 식별할 수 있습니다.
TMA의 핵심 원리는 CPU 파이프라인의 모든 슬롯(μop slot)을 네 가지 대분류로 분할하는 것입니다. 매 사이클마다 파이프라인의 각 슬롯은 Retiring(유용한 작업 완료), Bad Speculation(잘못된 추론 실행으로 폐기), Frontend Bound(명령어 공급 지연), Backend Bound(실행 자원/데이터 대기) 중 하나로 분류됩니다. Level 2~4로 내려가면 각 대분류의 세부 원인을 계층적으로 좁혀갑니다.
Level 1 메트릭 공식
TMA Level 1의 네 가지 대분류는 고정 카운터(Fixed Counter)와 소수의 프로그래머블 카운터만으로 계산됩니다. PCM의 pcm 기본 모드가 보여주는 IPC, L3 Miss 등은 이 Level 1 분류의 입력 데이터입니다.
| 메트릭 | 공식 (간략화) | 의미 | 대표 원인 |
|---|---|---|---|
| Frontend Bound | IDQ_UOPS_NOT_DELIVERED / (4 × CLKS) |
명령어 디코더/캐시가 파이프라인에 μop을 충분히 공급하지 못함 | I-Cache 미스, ITLB 미스, 분기 예측 실패 후 재충전 |
| Bad Speculation | (UOPS_ISSUED.ANY − UOPS_RETIRED.RETIRE_SLOTS + Recovery) / (4 × CLKS) |
잘못된 추론 실행으로 폐기된 슬롯 비율 | 분기 예측 실패, 메모리 순서 위반, 머신 클리어 |
| Backend Bound | 1 − Frontend − Bad Speculation − Retiring |
실행 유닛 또는 메모리 서브시스템 대기로 인한 정체 | 캐시 미스(L1/L2/L3/DRAM), 실행 포트 경합, 분할 로드 |
| Retiring | UOPS_RETIRED.RETIRE_SLOTS / (4 × CLKS) |
실제 유용한 작업을 완료한 슬롯 비율 (높을수록 좋음) | 마이크로코드 시퀀스, 벡터화 부족 시 비효율적 Retiring |
슬롯 너비: 위 공식에서 4는 파이프라인 너비(슬롯 수)입니다. Skylake~Emerald Rapids는 4-wide, Granite Rapids P-core는 6-wide입니다. toplev.py는 CPUID로 마이크로아키텍처를 감지하여 자동으로 올바른 너비를 적용합니다.
pcm + toplev 연동 워크플로
실전에서는 PCM으로 시스템 전체 상태를 파악한 뒤, toplev.py로 특정 프로세스의 파이프라인 병목을 Level 1→4로 드릴다운합니다.
# 1단계: PCM으로 시스템 전체 IPC/캐시 상태 확인
sudo pcm 1 -i=5
# → IPC=0.7, L3 Hit=40% → Backend Bound 의심
# 2단계: toplev Level 1 — 대분류 확인
sudo python3 toplev.py -l1 --no-desc -- taskset -c 0 ./workload
# FE Frontend_Bound: 12.3%
# BAD Bad_Speculation: 5.1%
# BE Backend_Bound: 55.8% <== 주 병목
# RET Retiring: 26.8%
# 3단계: toplev Level 2 — Backend 세부 분류
sudo python3 toplev.py -l2 --no-desc -- taskset -c 0 ./workload
# BE Backend_Bound.Memory_Bound: 42.1% <== 메모리 문제
# BE Backend_Bound.Core_Bound: 13.7%
# 4단계: toplev Level 3 — 메모리 어느 계층?
sudo python3 toplev.py -l3 --no-desc -- taskset -c 0 ./workload
# BE/Mem Backend_Bound.Memory_Bound.DRAM_Bound: 28.5% <== DRAM 레이턴시
# BE/Mem Backend_Bound.Memory_Bound.L3_Bound: 10.2%
# BE/Mem Backend_Bound.Memory_Bound.L1_Bound: 3.4%
# 5단계: toplev Level 4 — 구체적 이벤트
sudo python3 toplev.py -l4 --no-desc -- taskset -c 0 ./workload
# BE/Mem/DRAM MEM_Bandwidth: 18.2% → pcm-memory로 대역폭 확인
# BE/Mem/DRAM MEM_Latency: 10.3% → pcm-latency로 레이턴시 확인
# PCM으로 교차 검증: 대역폭 포화 여부
sudo pcm-memory 0.5 -i=10
# → Socket 0 Total BW: 180 GB/s (이론 max 307 GB/s) → 58% 활용
# → 대역폭 포화보다 레이턴시가 주 원인 → NUMA 배치 검토
toplev 설치: toplev.py는 pmu-tools의 일부입니다. git clone https://github.com/andikleen/pmu-tools && cd pmu-tools && sudo python3 toplev.py -l1 -- sleep 1로 빠르게 시작할 수 있습니다. perf 서브시스템 문서의 TMA 섹션도 참고하세요.
Uncore PMU 상세
Uncore PMU는 CPU 코어 외부에 위치한 공유 자원(LLC, 메모리 컨트롤러, 인터코넥트 등)의 성능 카운터입니다. 코어 PMU가 개별 코어의 파이프라인 이벤트를 측정한다면, 언코어 PMU는 소켓 수준의 공유 인프라 활용도를 측정합니다. PCM의 핵심 가치는 바로 이 언코어 카운터를 사용자 친화적으로 추상화하는 데 있습니다.
Intel 서버 프로세서의 언코어 서브시스템은 여러 독립적인 PMU 유닛으로 구성됩니다. 각 유닛은 고유한 이벤트 세트와 카운터를 가지며, PCI config space 또는 MMIO를 통해 프로그래밍합니다.
언코어 PMU 프로그래밍 방법
언코어 PMU의 각 유닛은 PCI config space 또는 MMIO 레지스터를 통해 프로그래밍합니다. PCM은 이 과정을 추상화하지만, 커스텀 이벤트를 사용하려면 내부 구조를 이해해야 합니다.
| 언코어 유닛 | 접근 방식 | 카운터 수 | PCM 도구 | 대표 이벤트 |
|---|---|---|---|---|
| CHA | PCI config / MMIO | 4 GP | pcm (L3 Hit/Miss) | LLC_LOOKUP.*, TOR_INSERTS.* |
| iMC | PCI config | 4 GP + 1 Fixed | pcm-memory | CAS_COUNT.RD/WR, ACT_COUNT |
| UPI | PCI config | 4 GP | pcm, pcm-numa | DATA_BANDWIDTH_TX, TxL_FLITS.* |
| M2M | PCI config | 4 GP | pcm-raw | DIRECTORY_LOOKUP.*, WB_TO_MEM |
| IIO | PCI config | 4 GP | pcm-pcie, pcm-iio | DATA_REQ_OF_CPU.*, COMP_BUF |
| UBox | MSR | 2 GP + 1 Fixed | pcm-raw | CLOCKTICKS, RAPL_EVENTS |
# 언코어 PMU 유닛 수 확인 (시스템별 상이)
ls /sys/bus/event_source/devices/ | grep uncore
# uncore_cha_0 ~ uncore_cha_35 (36-core SPR → 36 CHA)
# uncore_imc_0 ~ uncore_imc_7 (8채널 DDR5)
# uncore_upi_0 ~ uncore_upi_3 (4 UPI 링크)
# uncore_m2m_0 ~ uncore_m2m_3 (4 M2M 유닛)
# uncore_iio_0 ~ uncore_iio_5 (6 IIO 스택)
# CHA: LLC 조회 이벤트 상세 (전체 CHA 집계)
sudo perf stat -e 'uncore_cha/llc_lookup.data_read/' \
-e 'uncore_cha/llc_lookup.write/' \
-e 'uncore_cha/llc_lookup.any/' \
-a --per-socket sleep 5
# iMC: 메모리 대역폭 세부 (채널별)
# cas_count × 64B / 시간 = 대역폭
sudo perf stat -e uncore_imc_0/cas_count_read/ \
-e uncore_imc_0/cas_count_write/ \
-e uncore_imc_1/cas_count_read/ \
-e uncore_imc_1/cas_count_write/ \
-a sleep 5
# M2M: 디렉터리 조회 및 Write-back 트래픽
sudo perf stat -e uncore_m2m_0/directory_lookup.any/ \
-e uncore_m2m_0/tag_hit.clean_line/ \
-a sleep 5
PCM vs perf 언코어 접근의 차이: PCM은 MSR/PCI config space에 직접 접근하여 카운터를 프로그래밍하고, perf는 커널의 intel_uncore PMU 드라이버를 경유합니다. PCM이 측정 중일 때 perf로 같은 언코어 카운터를 동시에 사용하면 카운터 충돌이 발생합니다. 한 번에 한 도구만 사용하거나, PCM_USE_PERF=1로 PCM이 perf_event 경로를 사용하도록 설정하세요.
CXL 메모리 모니터링 확장
CXL(Compute Express Link) 메모리 확장이 본격화되면서, PCM의 CXL 모니터링 기능이 중요해지고 있습니다. CXL 장치의 유형별 프로토콜 차이를 이해하고, 각 유형에 맞는 계측 전략을 수립해야 합니다. 이 섹션은 기본 CXL 모니터링 섹션을 확장하여 내용을 다룹니다.
CXL 대역폭/레이턴시 측정법
CXL Type 3 메모리 확장 장치의 성능을 평가하려면 대역폭과 레이턴시를 분리하여 측정해야 합니다. DDR5 로컬 메모리 대비 CXL 메모리는 일반적으로 1.5~3배의 추가 레이턴시가 발생합니다.
# CXL 장치 대역폭 측정 (Type 3 메모리 확장기)
sudo pcm-pcie -cxl 1 -i=10
# CXL Port 0: Read BW=12.3 GB/s, Write BW=8.1 GB/s
# CXL Port 1: Read BW=11.8 GB/s, Write BW=7.9 GB/s
# CXL vs DDR5 대역폭 비교
sudo pcm-memory 0.5 -i=10
# Socket 0 DDR5: Read=180 GB/s, Write=45 GB/s
# Socket 0 CXL: Read=24 GB/s, Write=16 GB/s (별도 행 표시)
# CXL 메모리 레이턴시 측정 (pcm-latency + NUMA 노드 분리)
# CXL 메모리는 별도 NUMA 노드로 인식됨
numactl --hardware
# node 0: DDR5 (CPU 0-35)
# node 1: DDR5 (CPU 36-71)
# node 2: CXL (no CPUs) ← CXL 전용 NUMA 노드
# CXL NUMA 노드에 메모리 할당 후 레이턴시 측정
numactl --membind=2 ./mlc --latency_matrix
# Node 0→Node 2 (CXL): ~250ns (DDR5 로컬: ~80ns)
# IIO 카운터로 CXL 포트별 세부 트래픽
sudo perf stat -e uncore_iio_0/data_req_of_cpu.reads.cxl/ \
-e uncore_iio_0/data_req_of_cpu.writes.cxl/ \
-a sleep 5
메모리 티어링과 PCM
Linux 커널의 메모리 티어링(Memory Tiering) 기능은 CXL 메모리를 느린 티어로, DDR5를 빠른 티어로 분류하여 자동으로 핫 페이지(Page)를 승격/강등합니다. PCM은 이 과정의 효율성을 검증하는 데 핵심 도구입니다.
# 메모리 티어링 상태 확인
cat /sys/devices/system/memory/memory_tier/memtier*/nodelist
# memtier0: 0-1 (DDR5, default_dram)
# memtier1: 2 (CXL, slow_tier)
# DAMON 기반 티어링 모니터링과 PCM 결합
# 1) PCM으로 CXL 대역폭 추이 관찰
sudo pcm-pcie -cxl 1 -csv=cxl_bw.csv &
# 2) 핫 페이지 승격/강등 통계
cat /proc/vmstat | grep -E "pgpromote|pgdemote"
# pgpromote_success 1234 ← CXL→DDR5 승격된 페이지
# pgdemote_kswapd 5678 ← DDR5→CXL 강등된 페이지
# 3) pcm-numa로 NUMA 노드 간 트래픽 확인
sudo pcm-numa 1
# Node 2(CXL) 접근 비율이 높으면 티어링 정책 조정 필요
pcm-raw 커스텀 이벤트
pcm-raw는 PCM의 사전 정의 도구가 지원하지 않는 이벤트를 직접 프로그래밍하여 측정하는 범용 카운터 도구입니다. Intel SDM(Software Developer's Manual)이나 언코어 PMU 가이드에 명시된 EventSelect/UnitMask 조합을 JSON 파일로 정의하여 사용합니다.
JSON 이벤트 정의 파일 작성
이벤트 정의 파일은 코어와 언코어 이벤트를 분리하여 기술합니다. 각 이벤트는 event(EventSelect), umask(UnitMask), 선택적으로 cmask, inv, edge, any 등의 한정자를 지정합니다.
{
"core": {
"fixed": [
{ "name": "INST_RETIRED", "idx": 0 },
{ "name": "CPU_CLK_UNHALTED", "idx": 1 },
{ "name": "REF_CLK_UNHALTED", "idx": 2 }
],
"programmable": [
{
"name": "L2_RQSTS.MISS",
"event": "0x24",
"umask": "0x3F",
"cmask": 0,
"inv": 0,
"edge": 0
},
{
"name": "DTLB_LOAD_MISSES.WALK_COMPLETED",
"event": "0x08",
"umask": "0x0E"
},
{
"name": "MEM_LOAD_RETIRED.L3_MISS",
"event": "0xD1",
"umask": "0x20"
},
{
"name": "BR_MISP_RETIRED.ALL_BRANCHES",
"event": "0xC5",
"umask": "0x00"
}
]
},
"uncore": {
"imc": [
{
"name": "CAS_COUNT.RD",
"event": "0x04",
"umask": "0x03"
},
{
"name": "CAS_COUNT.WR",
"event": "0x04",
"umask": "0x0C"
}
],
"cha": [
{
"name": "TOR_INSERTS.IA_MISS",
"event": "0x35",
"umask": "0x21"
}
]
}
}
# pcm-raw 실행: 커스텀 이벤트 파일 사용
sudo pcm-raw -e my_events.json 1 -i=10
# CSV 출력으로 후처리
sudo pcm-raw -e my_events.json 1 -i=30 -csv=raw_counters.csv
# PCM 배포에 포함된 사전 정의 이벤트 파일 확인
ls /usr/share/pcm/PMURegisterDeclarations/
# SPR/ EMR/ GNR/ ICX/ SKX/ ...
# 각 디렉터리: core.json, uncore.json, offcore.json 등
# SPR 코어 이벤트 파일로 전체 코어 카운터 수집
sudo pcm-raw -e /usr/share/pcm/PMURegisterDeclarations/SPR/core.json 1
플랫폼별 이벤트 코드 확인
이벤트 코드는 마이크로아키텍처마다 다를 수 있습니다. Intel SDM Volume 3B 또는 perfmon 이벤트 데이터베이스에서 정확한 코드를 확인해야 합니다.
# perf의 이벤트 데이터베이스 활용 (json 형식)
ls /usr/share/hwdata/pmu-events/arch/x86/
# sapphirerapids/ emeraldrapids/ graniterapids/ ...
# 특정 이벤트의 EventSelect/UnitMask 확인
python3 -c "
import json, glob
for f in glob.glob('/usr/share/hwdata/pmu-events/arch/x86/sapphirerapids/*.json'):
data = json.load(open(f))
for e in data:
if 'MEM_LOAD' in e.get('EventName',''):
print(f'{e[\"EventName\"]}: event={e[\"EventCode\"]}, umask={e[\"UMask\"]}')
"
# MEM_LOAD_RETIRED.L1_MISS: event=0xd1, umask=0x08
# MEM_LOAD_RETIRED.L2_MISS: event=0xd1, umask=0x10
# MEM_LOAD_RETIRED.L3_MISS: event=0xd1, umask=0x20
# ocperf (pmu-tools) 로 이벤트 검색
python3 ocperf.py list | grep -i "mem_load"
커스텀 메트릭 정의: JSON 파일에 "metric" 섹션을 추가하면 카운터 간 비율/연산을 자동 계산할 수 있습니다. 예: "L2_Miss_Rate": "L2_RQSTS.MISS / L2_RQSTS.ALL_REQUESTS". 이 기능은 PCM 2.0+에서 지원됩니다.
멀티소켓 NUMA 분석
멀티소켓 서버에서 성능 최적화의 핵심은 NUMA(Non-Uniform Memory Access) 불균형을 식별하고 해소하는 것입니다. PCM은 소켓 간 QPI/UPI 트래픽, 원격 메모리 접근 비율, NUMA 노드별 대역폭을 정밀하게 측정하여 NUMA 최적화의 기반 데이터를 제공합니다.
pcm-numa 상세 출력 해석
# pcm-numa: 소켓별 로컬/원격 메모리 접근 통계
sudo pcm-numa 1 -i=10
# Socket 0:
# Local Read: 45.2 GB/s Local Write: 12.1 GB/s
# Remote Read: 8.3 GB/s Remote Write: 2.1 GB/s
# Remote Access: 15.4% ← 10% 초과 → NUMA 최적화 필요
#
# Socket 1:
# Local Read: 38.6 GB/s Local Write: 10.3 GB/s
# Remote Read: 3.2 GB/s Remote Write: 0.8 GB/s
# Remote Access: 7.5% ← 양호
# UPI 링크 대역폭 확인 (소켓 간 트래픽 상세)
sudo pcm 1 -i=5
# → UPI0: 18.3 GB/s (TX) / 15.2 GB/s (RX)
# → UPI1: 17.8 GB/s (TX) / 14.9 GB/s (RX)
# → UPI2: 16.5 GB/s (TX) / 13.8 GB/s (RX)
# → 합계: ~52.6 GB/s TX → 이론값 64 GB/s의 82% → 포화 근접!
# QPI/UPI 포화 판단 기준 (3-link SPR 기준)
# UPI 3.0 단일 링크: ~32 GB/s 양방향 → 3링크 합계: ~96 GB/s 단방향
# 활용률 70% 이상: 포화 임박 경고
# 활용률 85% 이상: 즉각 NUMA 격리 필요
NUMA 최적화 전략과 PCM 검증
# 1) 프로세스 NUMA 바인딩 (numactl)
numactl --cpunodebind=0 --membind=0 ./database_server
# → pcm-numa 재측정: Remote Access 15% → 3% 감소 확인
# 2) 커널 NUMA balancing 상태 확인
cat /proc/sys/kernel/numa_balancing
# 1 = 활성 (커널이 자동으로 페이지 마이그레이션)
# NUMA balancing 통계
grep -E "numa_" /proc/vmstat
# numa_hit: 1234567 ← 로컬 할당 성공
# numa_miss: 56789 ← 원격 할당 (폴백)
# numa_foreign: 56789 ← 다른 노드에서 자신의 메모리 접근
# numa_pages_migrated: 12345 ← 자동 마이그레이션 횟수
# 3) PCM + perf c2c 결합: 크로스소켓 캐시라인 경합 식별
sudo perf c2c record -a sleep 10
sudo perf c2c report --stdio
# → HITM(cross-socket) 비율이 높은 캐시라인 → 데이터 구조 분리/패딩
# 4) cgroup NUMA 격리 (Kubernetes)
# cpuset.mems=0 → 노드 0 메모리만 사용
echo 0 > /sys/fs/cgroup/my_workload/cpuset.mems
echo "0-35" > /sys/fs/cgroup/my_workload/cpuset.cpus
NUMA: NUMA 아키텍처 상세, 페이지 마이그레이션, 메모리 정책(Memory Policy)은 NUMA (Non-Uniform Memory Access) 문서를 참고하세요. perf c2c를 활용한 크로스소켓 캐시라인 경합 분석은 perf 서브시스템에서 다룹니다.
컨테이너/VM 모니터링
클라우드 및 컨테이너 환경에서 PCM을 사용하려면 보안 제약, 권한 모델, PMU 공유 문제를 이해해야 합니다. 특히 Kubernetes 환경에서 하드웨어 카운터 기반 모니터링을 운용하는 방법과, KVM 가상화에서 PMU 패스스루를 활용하는 방법을 다룹니다.
Docker/Kubernetes 환경 PCM 운용
컨테이너 환경에서 PCM을 사용하는 주요 패턴은 두 가지입니다: (1) 호스트에서 pcm-sensor-server를 DaemonSet으로 실행하여 전체 노드 메트릭을 수집하거나, (2) perf_event 모드로 cgroup별 코어 PMU 데이터를 수집합니다.
# 방법 1: 호스트 레벨 DaemonSet (전체 시스템 모니터링)
# Kubernetes DaemonSet으로 pcm-sensor-server 배포
# 필요 권한: privileged=true + hostPID=true
# Dockerfile (호스트 모드 PCM)
# FROM ubuntu:22.04
# RUN apt-get update && apt-get install -y pcm
# CMD ["pcm-sensor-server", "-p", "9738"]
# DaemonSet YAML 핵심 부분
# securityContext:
# privileged: true
# hostPID: true
# volumes:
# - name: dev-cpu
# hostPath: { path: /dev/cpu }
# - name: proc
# hostPath: { path: /proc }
# 방법 2: perf_event + cgroup (컨테이너별 코어 PMU)
# perf_event cgroup 컨트롤러 활성화 확인
cat /sys/fs/cgroup/cgroup.controllers
# → perf_event 포함 여부 확인
# 특정 cgroup의 코어 카운터 수집
# Docker 컨테이너의 cgroup 경로 확인
CGPATH=$(docker inspect --format '{{.State.Pid}}' my_container)
sudo perf stat -e instructions,cycles,cache-misses \
--cgroup=docker/$CGPATH -a sleep 10
# PCM_USE_PERF=1로 cgroup 인식 모드
sudo PCM_USE_PERF=1 pcm 1 -i=5
# → perf_event 경로 사용, cgroup 인식 가능
KVM PMU 패스스루
KVM 가상머신에서 PCM을 실행하려면 vPMU(Virtual PMU) 패스스루가 필요합니다. QEMU의 -cpu host,pmu=on 옵션으로 호스트의 코어 PMU를 게스트에 노출할 수 있습니다.
# KVM vPMU 활성화 (QEMU 커맨드라인)
qemu-system-x86_64 \
-cpu host,pmu=on \
-enable-kvm \
-smp 4 -m 8192 \
-drive file=vm.qcow2,format=qcow2 \
...
# libvirt XML에서 vPMU 활성화
# <cpu mode="host-passthrough">
# <feature policy="require" name="pmu"/>
# </cpu>
# 게스트 VM 내부에서 PMU 지원 확인
dmesg | grep -i pmu
# Performance Events: PEBS fmt4+-baseline, ...
# ... Intel PMU driver ...
# 게스트에서 pcm 실행
sudo modprobe msr
sudo pcm 1 -i=3
# → 코어 PMU 카운터 사용 가능 (IPC, 캐시 등)
# → 언코어 카운터는 접근 불가 (호스트 전용)
보안 주의: 컨테이너에 privileged: true 또는 MSR 디바이스 접근 권한을 부여하면 보안 경계가 무력화됩니다. 프로덕션 환경에서는 PCM_USE_PERF=1 + perf_event_paranoid 설정으로 최소 권한 원칙을 준수하세요. MSR 직접 접근은 전용 모니터링 노드에서만 사용하는 것이 권장됩니다.
perf 연동 실전
PCM과 perf를 효과적으로 결합하면 시스템 수준 하드웨어 모니터링(PCM)과 프로세스 수준 프로파일링(perf)의 장점을 모두 활용할 수 있습니다. 이 섹션에서는 실전 크로스 분석 워크플로, 언코어 이벤트 명명 규칙, perf로 PCM과 동등한 데이터를 수집하는 방법을 다룹니다.
pcm + perf stat 크로스 분석 워크플로
실전에서 가장 효과적인 패턴은 PCM으로 시스템 전체 이상을 감지한 뒤, perf로 원인 함수/프로세스를 특정하는 것입니다. 두 도구는 같은 PMU 하드웨어를 공유하므로 동시 실행 시 주의가 필요합니다.
# 워크플로 1: PCM 모니터링 → 이상 감지 → perf 드릴다운
# 터미널 1: PCM으로 시스템 상태 연속 모니터링
sudo pcm 1 -csv=system_monitor.csv
# CSV에서 IPC 급락 시점 확인
awk -F',' 'NR>1 && $3<0.8 {print NR, $1, "IPC="$3}' system_monitor.csv
# 터미널 2: 이상 감지 시 perf record 시작
# (PCM 종료 후 실행 — 카운터 충돌 방지)
sudo perf record -e cycles:pp,instructions:pp,cache-misses:pp \
-a -g --call-graph dwarf sleep 30
sudo perf report --sort=comm,dso,symbol --stdio
# 워크플로 2: perf stat으로 PCM과 동등한 시스템 개요 수집
sudo perf stat -e instructions,cycles,\
ref-cycles,cache-references,cache-misses,\
branches,branch-misses,\
LLC-loads,LLC-load-misses,\
dTLB-loads,dTLB-load-misses \
-a --per-core sleep 10
# → IPC = instructions / cycles
# → L3 Hit = 1 - (LLC-load-misses / LLC-loads)
# → Branch Mispredict = branch-misses / branches
# 워크플로 3: 특정 프로세스의 TMA + 시스템 언코어 동시 수집
# perf로 프로세스 코어 카운터 수집
sudo perf stat -e '{instructions,cycles,topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound}' \
-p $(pgrep -x nginx) sleep 10
# perf 5.12+에서 TopDown Level 1 메트릭 직접 지원
언코어 이벤트 명명 규칙
perf의 언코어 이벤트 이름은 체계적인 규칙을 따릅니다. 이 규칙을 이해하면 perf list 출력에서 원하는 이벤트를 빠르게 찾을 수 있습니다.
| 패턴 | 의미 | 예시 |
|---|---|---|
uncore_{unit}_{N}/ | 언코어 유닛 인스턴스 N번 | uncore_imc_0/ |
uncore_{unit}/ | 모든 인스턴스 집계 | uncore_cha/ |
{event}/ | 사전 정의 이벤트 이름 | cas_count_read/ |
event=0x{XX},umask=0x{YY}/ | raw 이벤트 지정 | event=0x04,umask=0x03/ |
# 전체 언코어 이벤트 검색
sudo perf list | grep "uncore" | head -30
# 특정 유닛의 이벤트만 필터링
sudo perf list | grep "uncore_imc"
# uncore_imc_0/cas_count_read/ [Kernel PMU event]
# uncore_imc_0/cas_count_write/ [Kernel PMU event]
# uncore_imc_0/act_count/ [Kernel PMU event]
# uncore_imc_0/pre_count/ [Kernel PMU event]
# JSON 이벤트 파일 (perf 5.x+)
# /usr/share/hwdata/pmu-events/arch/x86/{platform}/uncore-*.json
ls /usr/share/hwdata/pmu-events/arch/x86/sapphirerapids/
# cache.json core.json floating-point.json frontend.json
# memory.json pipeline.json uncore-cache.json uncore-interconnect.json
# uncore-memory.json uncore-other.json virtual-memory.json
# perf로 PCM-memory 동등 데이터 수집 (전체 iMC 집계)
sudo perf stat -M "memory_bandwidth" -a sleep 5
# perf 5.15+에서 메트릭 그룹 지원 시
# → 읽기/쓰기 대역폭을 자동 계산하여 표시
perf와 PCM 선택 기준: 단일 프로세스 프로파일링에는 perf가 적합하고, 시스템 전체 언코어/메모리/인터코넥트 모니터링에는 PCM이 효율적입니다. 두 도구를 동시에 실행하면 PMU 카운터 충돌이 발생하므로, PCM은 PCM_USE_PERF=1 모드로 perf_event를 경유하거나, 시간을 분리하여 사용하세요. 상세한 perf 사용법은 perf 서브시스템 문서를 참고하세요.
세대별 차이 (SPR/EMR/GNR)
Intel 서버 프로세서의 세대별 PMU 아키텍처 변화는 PCM의 기능과 성능 분석 방법론에 직접적인 영향을 미칩니다. Sapphire Rapids에서 도입된 TPMI가 Emerald Rapids에서 안정화되고, Granite Rapids/Sierra Forest에서 하이브리드 아키텍처가 본격화되면서 모니터링 전략이 진화하고 있습니다.
Granite Rapids / Sierra Forest 하이브리드
Granite Rapids(GNR)와 Sierra Forest(SRF)는 Intel 서버 프로세서에 하이브리드 아키텍처를 도입합니다. GNR은 고성능 P-core, SRF는 고효율 E-core를 사용하며, 동일 플랫폼에서 P-die와 E-die를 혼합할 수 있습니다. PCM 2.0+에서 다이별 분리 모니터링을 지원합니다.
# GNR: P-core / E-core 다이 분리 모니터링
sudo pcm -die 0 1 -i=5
# Die 0 (P-core): IPC=2.1, Freq=3.8GHz, L3 Hit=78%
# Die 0 (P-core): Core PMU v6, GP 카운터 8개
sudo pcm -die 1 1 -i=5
# Die 1 (E-core): IPC=1.5, Freq=2.4GHz, L3 Hit=82%
# Die 1 (E-core): Atom PMU, GP 카운터 4개
# GNR 확장 카운터 활용 (8 GP + 4 Fixed)
# 기존 4개 제한에서 8개 프로그래머블 카운터로 확장
# → 한 번의 실행으로 더 많은 이벤트 동시 수집 가능
sudo pcm-raw -e /usr/share/pcm/PMURegisterDeclarations/GNR/core.json 1
# SRF(Sierra Forest) E-core 전용 TMA
# Atom 아키텍처의 TMA 트리는 P-core와 구조가 다름
sudo python3 toplev.py -l2 --no-desc -- taskset -c 0 ./workload
# (toplev이 CPUID로 E-core 감지 → Atom TMA 트리 자동 적용)
# PCM 버전 호환성 확인
pcm --version
# PCM v2.0 이상: GNR/SRF 지원
# PCM v1.6 이상: EMR 지원
# PCM v1.4 이상: SPR 지원
TPMI 진화와 활용
TPMI(Topology Aware Register and PM Interface)는 SPR에서 도입된 이후 지속적으로 발전하고 있습니다. EMR에서 안정성이 개선되었고, GNR에서는 다이별 세밀한 제어와 새로운 텔레메트리 데이터를 제공합니다.
| TPMI 기능 | SPR | EMR | GNR/SRF |
|---|---|---|---|
| 기본 언코어 카운터 접근 | 지원 | 지원 | 지원 |
| RAPL 통합 | 기본 | 확장 | 다이별 분리 |
| SST (Speed Select) | SST-PP/CP | SST-PP/CP/TF | SST 전체 + 다이별 |
| PMT (Platform Monitoring) | 기본 | 확장 | 전체 텔레메트리 |
| 커널 드라이버 | intel_vsec (6.3+) | intel_vsec (6.5+) | intel_vsec (6.8+) |
| Secure Boot 호환 | 지원 | 지원 | 지원 |
# TPMI 지원 및 버전 확인
dmesg | grep -i tpmi
# intel_vsec: TPMI interface detected (version 2)
# TPMI 기반 PMT(Platform Monitoring Technology) 텔레메트리
ls /sys/class/intel_pmt/
# telem0/ telem1/ ... (텔레메트리 엔드포인트)
# PMT 텔레메트리 데이터 읽기
cat /sys/class/intel_pmt/telem0/guid
# → GUID로 텔레메트리 데이터 형식 식별
hexdump -C /sys/class/intel_pmt/telem0/telem
# → 바이너리 텔레메트리 데이터 (온도, 전력, 주파수 등)
# pcm-tpmi로 TPMI 경로 우선 사용 (MSR 폴백 자동)
sudo pcm-tpmi
# TPMI available: using MMIO-based counter access
# (Secure Boot 환경에서도 정상 동작)
PCM 버전 관리: 새로운 플랫폼 출시 후 PCM이 해당 플랫폼을 완전히 지원하기까지 수 개월이 소요될 수 있습니다. GitHub의 intel/pcm 저장소에서 최신 릴리스 노트를 확인하고, 대상 플랫폼 지원 여부를 사전에 검증하세요. pcm --version과 pcm --help로 현재 버전의 플랫폼 지원 범위를 확인할 수 있습니다.
코어 카운터 메트릭
PCM의 pcm 기본 도구가 표시하는 코어 성능 카운터는 CPU 마이크로아키텍처의 내부 상태를 반영합니다. 각 메트릭의 물리적 의미를 정확히 이해하면, 성능 병목의 근본 원인을 정밀하게 진단할 수 있습니다. 이 섹션에서는 핵심 메트릭의 계산 원리, 해석 방법, 그리고 워크로드 유형별 정상 범위를 상세히 다룹니다.
IPC (Instructions Per Cycle) 심층 분석
IPC는 사이클(Cycle)당 은퇴(Retire)된 명령어 수로, CPU 파이프라인 효율의 가장 중요한 지표입니다. IPC = INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD로 계산되며, 두 값 모두 고정 카운터(Fixed Counter)에서 제공합니다.
캐시 미스율 해석과 계층별 지연
PCM이 표시하는 L2/L3 캐시 히트율은 메모리 서브시스템의 효율을 나타냅니다. 각 캐시 계층의 미스 비용(레이턴시)을 이해하면, 캐시 미스가 전체 성능에 미치는 영향을 정량적으로 평가할 수 있습니다.
# 캐시 계층별 미스율 정밀 측정
sudo perf stat -e L1-dcache-loads,L1-dcache-load-misses,\
LLC-loads,LLC-load-misses,\
l2_rqsts.all_demand_miss,l2_rqsts.all_demand_references \
-a sleep 10
# IPC와 캐시 미스 상관 분석 (pcm 확장 커맨드)
sudo pcm -e core/config=0x24,config1=0x27,name=L2_ALL_MISS/,\
core/config=0xD1,config1=0x20,name=L3_MISS_LOAD/,\
core/config=0xC5,config1=0x00,name=BR_MISP/,\
core/config=0x08,config1=0x0E,name=DTLB_WALK/ 1 -i=10
# 캐시 미스 비용 추정 공식
# 메모리 스톨 사이클 ≈ L3_MISS × DRAM_레이턴시(사이클)
# 예: L3_MISS = 10M/s, DRAM latency = 80ns, freq = 3GHz
# 스톨 = 10M × (80ns × 3GHz) = 10M × 240cy = 2,400M stall cycles/s
# → 전체 사이클의 80%가 메모리 대기 → IPC 급락
분기 예측 실패율 분석
분기 예측 실패(Branch Misprediction)는 파이프라인 플러시를 발생시켜 15~20 사이클의 페널티를 부과합니다. PCM의 pcm 도구는 분기 명령어 대비 예측 실패율을 표시합니다. 워크로드에 따라 1~2%의 실패율만으로도 상당한 성능 저하가 발생할 수 있습니다.
# 분기 예측 정확도 분석
sudo perf stat -e branches,branch-misses,\
br_inst_retired.all_branches,br_misp_retired.all_branches,\
br_misp_retired.cond,br_misp_retired.near_taken \
-a sleep 10
# 분기 예측 실패율 = branch-misses / branches × 100%
# 정상 범위: 0.1~1.0%
# 1% 초과: 분기 패턴 불규칙 (정렬되지 않은 if-else, switch 등)
# 3% 초과: 심각 — 데이터 의존적 분기, 간접 호출 다수
# PCM으로 코어별 분기 예측 실패율 확인
sudo pcm 1 -i=5
# → "Branch Mispr. Ratio" 컬럼 확인
# → 코어 간 편차가 크면 특정 스레드에 분기 집중
# 분기 예측 실패 핫스팟 식별
sudo perf record -e branch-misses:pp -c 1000 -- ./workload
sudo perf report --sort=symbol
# → 분기 미스가 집중된 함수 식별 후 최적화:
# 1. __builtin_expect() / likely()/unlikely() 힌트
# 2. 룩업 테이블로 분기 제거
# 3. CMOV (조건부 이동) 명령어 활용
# 4. 분기 없는 비트 연산으로 변환
pcm-memory: 채널별 메모리 대역폭 분석
pcm-memory는 iMC(Integrated Memory Controller)의 CAS_COUNT 카운터를 읽어 채널별 DRAM Read/Write 대역폭을 실시간으로 측정합니다. 메모리 대역폭 병목은 서버 워크로드에서 가장 흔한 성능 저하 원인 중 하나이며, 채널별 불균형은 DIMM 구성 오류를 나타낼 수 있습니다.
# 채널별 대역폭 상세 측정
sudo pcm-memory 0.5 -i=20 -csv=channel_bw.csv
# CSV 데이터로 채널 불균형 분석
python3 -c "
import csv
with open('channel_bw.csv') as f:
reader = csv.reader(f)
for row in reader:
if 'Channel' in str(row):
vals = [float(x) for x in row if x.replace('.','').isdigit()]
if vals:
avg = sum(vals)/len(vals)
maxv, minv = max(vals), min(vals)
imbalance = (maxv - minv) / avg * 100
print(f'Imbalance: {imbalance:.1f}%')
"
# NUMA 노드별 메모리 대역폭 분리
# 소켓 0의 로컬 DRAM vs 소켓 1의 로컬 DRAM
sudo pcm-memory 1 -s 0 # 소켓 0만
sudo pcm-memory 1 -s 1 # 소켓 1만
# 대역폭 포화 테스트 (STREAM 벤치마크)
# STREAM Triad로 이론 대역폭의 달성 가능 비율 측정
OMP_NUM_THREADS=36 numactl --membind=0 ./stream_c.exe
# → Triad: 250 GB/s (이론 307 GB/s의 81%)
# 동시에 pcm-memory 실행하여 채널별 분포 확인
# MLC (Memory Latency Checker)로 대역폭-레이턴시 커브
sudo mlc --bandwidth_matrix
sudo mlc --loaded_latency
# → 대역폭 증가에 따른 레이턴시 증가 프로파일
# → 50% BW 활용부터 레이턴시 급등 시작 (큐잉 효과)
DIMM 구성 최적화: 최대 대역폭을 달성하려면 모든 채널에 DIMM을 균등하게 장착해야 합니다. 2DPC(DIMM Per Channel) 구성은 최대 주파수를 낮출 수 있으므로, 용량보다 대역폭이 중요한 워크로드에서는 1DPC를 권장합니다. pcm-memory 채널별 불균형이 30% 이상이면 dmidecode -t memory로 DIMM 슬롯 구성을 확인하세요.
pcm-pcie: PCIe 대역폭 분석
pcm-pcie는 IIO(I/O Integration Unit) 언코어 카운터를 통해 각 PCIe Root Port의 인바운드(디바이스→CPU)/아웃바운드(CPU→디바이스) 대역폭을 측정합니다. NVMe SSD, GPU, 네트워크 어댑터, CXL 장치 등의 I/O 성능 병목을 정밀하게 진단할 수 있습니다.
# PCIe 디바이스별 대역폭 상세 모니터링
sudo pcm-pcie 1 -i=10 -csv=pcie_detail.csv
# 이벤트 모드: Part0~Part3 분류 (MRd/MWr/CplD 등)
sudo pcm-pcie -e 1
# Part0: PCIe Read (MRd — Memory Read)
# Part1: PCIe Read CplD (Completion with Data)
# Part2: PCIe Write (MWr — Memory Write)
# Part3: PCIe Non-data (Config, IO, Msg)
# 특정 BDF(Bus:Device.Function) 필터링
lspci -D | grep -i nvidia
# 0000:3a:00.0 3D controller: NVIDIA Corporation ...
sudo pcm-pcie -B 0x3a:0x00.0 1
# PCIe 링크 상태 확인 (실제 협상된 속도/폭)
lspci -vvs 3a:00.0 | grep -i "lnksta\|lnkcap"
# LnkCap: Speed 16GT/s, Width x16 (Gen4 x16 지원)
# LnkSta: Speed 16GT/s, Width x16 (실제 Gen4 x16 동작)
# → Width x8로 제한되었다면 물리적 슬롯/케이블 점검
# DMA 성능 측정 (NVMe SSD)
# fio로 순차 읽기 대역폭 측정 + pcm-pcie 동시 실행
sudo pcm-pcie 1 &
fio --name=seq_read --rw=read --bs=128k --numjobs=4 \
--iodepth=32 --filename=/dev/nvme0n1 --direct=1 \
--ioengine=io_uring --runtime=30
# → fio 출력과 pcm-pcie의 IIO 포트 대역폭 비교
# → 차이가 크면 드라이버/인터럽트 오버헤드 의심
pcm-power: 전력-성능 트레이드오프
pcm-power는 RAPL(Running Average Power Limit) MSR을 통해 CPU 패키지, DRAM, PP0(코어), PP1(GPU/가속기) 도메인별 에너지 소비를 실시간으로 측정합니다. 전력 소비와 성능 간의 트레이드오프를 분석하고, 주파수 스로틀링과 C-State 정책의 효과를 검증하는 데 핵심적인 도구입니다.
# RAPL 도메인별 전력 실시간 모니터링
sudo pcm-power 0.5 -i=30 -csv=power_trace.csv
# 전력 제한(Power Limit) 설정 확인
sudo rdmsr -p 0 0x610
# MSR_PKG_POWER_LIMIT (0x610): PL1/PL2/PL1_TIME 인코딩
# PL1: 장기 전력 제한 (보통 TDP)
# PL2: 단기 전력 제한 (터보 부스트 허용 최대)
# 전력 제한 동적 변경 (Intel RAPL powercap)
cat /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw
# → PL1 (마이크로와트 단위)
cat /sys/class/powercap/intel-rapl:0/constraint_1_power_limit_uw
# → PL2 (마이크로와트 단위)
# PL1 변경 (주의: 과열 위험)
echo 300000000 | sudo tee \
/sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw
# → PL1을 300W로 설정
# 전력-성능 프로파일 변경 (EPB)
sudo cpupower set -b 0 # 최대 성능 (EPB=0)
sudo cpupower set -b 6 # 균형 (EPB=6)
sudo cpupower set -b 15 # 최대 절전 (EPB=15)
# 변경 후 pcm-power로 효과 검증
sudo pcm-power 1 -i=10
# → PKG Watts, C-State 분포, 주파수 변화 확인
실전 워크로드별 PCM 활용 시나리오
실무에서 PCM을 가장 효과적으로 활용하는 방법은 워크로드 유형별로 최적화된 모니터링 전략을 수립하는 것입니다. 웹서버, 데이터베이스, HPC 등 각 워크로드는 서로 다른 하드웨어 자원에 병목이 발생하며, PCM 도구의 조합도 달라집니다.
웹서버 워크로드 (nginx/Apache)
웹서버는 높은 동시 접속, 빈번한 시스템 콜, 네트워크 I/O 중심 워크로드입니다. 코어 수 대비 IPC와 네트워크 카드 PCIe 대역폭이 핵심 지표입니다.
# 웹서버 성능 분석 워크플로
# 1단계: 코어별 IPC 및 캐시 효율 확인
sudo pcm 1 -i=10 -csv=nginx_core.csv
# 확인 포인트:
# - IPC: 1.0~2.0 (정상), <0.8 (메모리 바운드 의심)
# - L3 Hit: >80% (정상), <60% (작업 셋 과대)
# - 코어 간 IPC 편차: 작업 분배 불균형 확인
# 2단계: NIC PCIe 대역폭 확인
sudo pcm-pcie 1 -i=10
# 100GbE NIC: 이론 ~12.5 GB/s, 측정값이 10GB/s 이상이면 NIC 포화
# → TCP offload, RSS(Receive Side Scaling) 조정 검토
# 3단계: NUMA 바인딩 확인 (NIC과 같은 NUMA 노드에 nginx 배치)
# NIC의 NUMA 노드 확인
cat /sys/class/net/eth0/device/numa_node
# → 0 (NUMA 노드 0에 NIC 연결)
# nginx를 NIC과 같은 NUMA 노드에 바인딩
numactl --cpunodebind=0 --membind=0 nginx
# 4단계: PCM으로 바인딩 전후 비교
sudo pcm-numa 1 -i=5
# → Remote Access: 15% → 2% (바인딩 후 개선 확인)
데이터베이스 워크로드 (MySQL/PostgreSQL)
OLTP 데이터베이스는 랜덤 메모리 접근, 높은 LLC 미스율, 잠금 경합이 특징입니다. pcm-memory와 pcm-numa가 핵심 도구입니다.
# OLTP 데이터베이스 성능 분석
# 1단계: IPC + LLC 히트율로 메모리 바운드 판단
sudo pcm 1 -i=10
# OLTP 특성: IPC 0.8~1.5, L3 Hit 40~70%
# → L3 Hit <50% + IPC <1.0 = 버퍼 풀 크기 부족
# 2단계: 메모리 대역폭 + NUMA 불균형
sudo pcm-memory 1 -i=5
# → Read:Write 비율 ≈ 4:1 (인덱스 검색 위주)
# → 소켓 간 대역폭 차이 >30% → NUMA 불균형
sudo pcm-numa 1 -i=5
# → Remote Access >10% → innodb_numa_interleave=ON 또는
# numactl --cpunodebind=0 --membind=0 mysqld
# 3단계: NVMe I/O 대역폭 (WAL/Redo Log)
sudo pcm-pcie 1 -i=5
# → NVMe Write BW가 높으면 fsync 빈도 확인
# → Read BW 높으면 버퍼 풀 미스 (innodb_buffer_pool_size 증가)
# 4단계: 잠금 경합 시 코어별 IPC 편차 확인
sudo pcm 0.5 -i=20 -csv=db_contention.csv
# → 특정 코어 IPC ≈ 0.3 (락 스핀 대기)
# → 다른 코어 IPC ≈ 1.5 (정상 처리)
# → perf record -e cycles:pp -p $(pgrep mysqld)로 핫스팟 확인
HPC 워크로드 (MPI/OpenMP)
# HPC 워크로드 성능 분석
# 1단계: 메모리 대역폭 포화 확인 (HPC의 주요 병목)
sudo pcm-memory 0.5 -i=20 -csv=hpc_bw.csv
# → Total BW가 이론값의 70%+ → 메모리 BW 포화
# → Read:Write ≈ 2:1 (STREAM Triad와 유사)
# 2단계: UPI 대역폭 (MPI 통신 오버헤드)
sudo pcm 1 -i=10
# → UPI TX/RX: 높으면 MPI 랭크 간 통신 집중
# → MPI 토폴로지를 NUMA 토폴로지에 맞게 매핑
# 3단계: AVX-512 전력 스로틀링 확인
sudo pcm-power 0.5 -i=20
# → PKG 전력이 TDP 근접 + 주파수 하락 → AVX offset 문제
# → AVX-512 heavy 코드: 주파수 -200~-600MHz 페널티
# 4단계: NUMA 최적화 (MPI 랭크별 바인딩)
mpirun --map-by socket --bind-to core \
-np 72 ./hpc_app
# → pcm-numa로 원격 접근 비율 검증
sudo pcm-numa 1 -i=5
# → Remote Access <5% 유지 목표
Grafana/Prometheus 대시보드
pcm-sensor-server를 Prometheus/Grafana와 연동하면 실시간 하드웨어 성능 대시보드를 구축할 수 있습니다. 이 섹션에서는 대시보드 설계, PromQL 쿼리, 알림 규칙 설정을 상세히 다룹니다.
핵심 PromQL 쿼리 및 알림 규칙
# Prometheus 알림 규칙 (alerts.yml)
groups:
- name: pcm_hardware_alerts
rules:
# IPC 급락 알림
- alert: LowIPC
expr: avg(pcm_ipc) by (instance) < 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "IPC 급락: {{ $labels.instance }}"
description: "평균 IPC {{ $value | humanize }} - 메모리 바운드 또는 잠금 경합 의심"
# 메모리 대역폭 포화 알림
- alert: MemoryBandwidthSaturation
expr: >
sum(pcm_memory_read_bandwidth + pcm_memory_write_bandwidth)
by (instance, socket) > 200
for: 3m
labels:
severity: critical
annotations:
summary: "메모리 BW 포화: {{ $labels.instance }} Socket {{ $labels.socket }}"
description: "총 대역폭 {{ $value | humanize }} GB/s"
# 온도 경고
- alert: HighTemperature
expr: max(pcm_core_temperature) by (instance) > 90
for: 1m
labels:
severity: critical
annotations:
summary: "CPU 온도 위험: {{ $labels.instance }}"
# NUMA 원격 접근 과다
- alert: NUMAImbalance
expr: >
pcm_numa_remote_access_ratio > 0.15
for: 10m
labels:
severity: warning
annotations:
summary: "NUMA 불균형: {{ $labels.instance }}"
# PCIe 대역폭 이상
- alert: PCIeLowBandwidth
expr: >
pcm_pcie_read_bandwidth{port=~".*gpu.*"} < 10
for: 5m
labels:
severity: warning
annotations:
summary: "GPU PCIe 대역폭 저하: {{ $labels.instance }}"
# Grafana 대시보드 패널별 PromQL 쿼리
# 코어별 IPC 히트맵
# PromQL: pcm_ipc{socket="0"}
# Visualization: Heatmap, Min=0, Max=4
# 소켓별 메모리 BW (Read/Write 스택)
# PromQL Read: pcm_memory_read_bandwidth{socket="0"}
# PromQL Write: pcm_memory_write_bandwidth{socket="0"}
# Visualization: Time Series, Stacked
# 전력 소비 추이 (PKG + DRAM)
# PromQL: rate(pcm_package_consumed_energy_joules[5s])
# Visualization: Time Series, Unit: Watts
# L3 캐시 히트율 게이지
# PromQL: pcm_l3_hit_ratio{socket="0"} * 100
# Visualization: Gauge, Min=0, Max=100, Thresholds: 50(red), 80(yellow)
# 주파수 분포 (코어별)
# PromQL: pcm_freq_mhz{socket="0"}
# Visualization: Time Series, Per-core
# PCIe 포트별 대역폭
# PromQL: pcm_pcie_read_bandwidth{socket="0"}
# Visualization: Bar Gauge
# Grafana 대시보드 JSON 자동 임포트 스크립트
for json in /path/to/pcm/grafana/*.json; do
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $GRAFANA_API_KEY" \
http://localhost:3000/api/dashboards/import \
-d "{\"dashboard\": $(cat $json), \"overwrite\": true}"
echo "Imported: $json"
done
CXL 메모리 모니터링
CXL 메모리 확장이 상용화되면서, PCM의 CXL 모니터링 기능은 메모리 티어링(Memory Tiering) 효율 검증과 대역폭/레이턴시 프로파일링의 핵심 도구가 되었습니다. 이 섹션에서는 CXL 메모리 성능 프로파일링, 티어링 효과 분석, NUMA 토폴로지와의 통합 모니터링을 다룹니다.
# CXL 메모리 티어링 효과 종합 분석
# 1. CXL 장치 토폴로지 확인
numactl --hardware
# node distances:
# node 0 1 2
# 0: 10 21 40 ← CXL(node 2) distance=40 (DDR distance=21)
# 1: 21 10 40
# 2: 40 40 10
# 2. 동시 대역폭 측정 (DDR5 + CXL)
sudo pcm-memory 0.5 -i=20 &
sudo pcm-pcie -cxl 0.5 -i=20 &
# → DDR5: Read 180 GB/s, Write 45 GB/s
# → CXL: Read 24 GB/s, Write 16 GB/s
# → 총 가용 대역폭: DDR5 225 + CXL 40 = 265 GB/s
# 3. 티어링 상태 모니터링
watch -n 1 "grep -E 'pgpromote|pgdemote' /proc/vmstat"
# pgpromote_success 1234 ← CXL→DDR 승격 (핫 페이지)
# pgdemote_kswapd 5678 ← DDR→CXL 강등 (콜드 페이지)
# 4. DAMON 기반 자동 티어링 활성화
echo 1 > /sys/kernel/mm/damon/admin/kdamonds/0/state
# → 핫/콜드 페이지 자동 분류 → 승격/강등 자동화
# 5. 애플리케이션별 CXL 메모리 사용 제어
# 레이턴시 민감: DDR만 사용
numactl --membind=0,1 ./latency_sensitive_app
# 레이턴시 허용: CXL 포함 전체 메모리 사용
numactl --interleave=all ./batch_processing_app
# CXL 전용: 대용량 콜드 데이터
numactl --membind=2 ./cold_data_cache
경쟁 도구 상세 비교
Intel PCM과 유사한 기능을 제공하는 도구들의 강점, 제한사항, 적용 시나리오를 상세히 비교합니다. 각 도구는 고유한 강점이 있으며, 실무에서는 여러 도구를 상호 보완적으로 사용하는 것이 효과적입니다.
# 도구별 동일 데이터 수집 비교
# === 코어별 IPC 측정 ===
# PCM:
sudo pcm 1 -i=5
# perf:
sudo perf stat -e instructions,cycles -a --per-core sleep 5
# turbostat (IPC 직접 제공 안 함, 주파수/전력만):
sudo turbostat --interval 1 --num_iterations 5
# LIKWID:
sudo likwid-perfctr -g FLOPS_DP -C 0-35 -- ./benchmark
# === 메모리 대역폭 측정 ===
# PCM:
sudo pcm-memory 1 -i=5
# perf (수동 계산 필요):
sudo perf stat -e uncore_imc_0/cas_count_read/,\
uncore_imc_0/cas_count_write/ -a sleep 5
# → CAS_COUNT × 64B / 시간 = 대역폭
# LIKWID:
sudo likwid-perfctr -g MEM -C 0 -- sleep 5
# === TMA Top-Down 분석 ===
# toplev:
sudo python3 toplev.py -l2 --no-desc -- taskset -c 0 ./workload
# perf (5.12+, Level 1만):
sudo perf stat -e '{topdown-retiring,topdown-bad-spec,topdown-fe-bound,topdown-be-bound}' \
-a sleep 5
# VTune (GUI):
vtune -collect uarch-exploration -- ./workload
도구 선택 가이드: 처음 접하는 성능 문제에는 pcm + pcm-memory로 시스템 전체 상태를 파악하고, 문제 영역이 좁혀지면 toplev으로 TMA 분류 후 perf record로 핫스팟을 식별하세요. 코드 수준 최적화가 필요하면 VTune(GUI 환경) 또는 LIKWID(서버 CLI 환경)를 사용합니다. 상시 모니터링에는 pcm-sensor-server + Grafana가 가장 적합합니다.
PCM 내부 아키텍처 상세
PCM은 사용자 공간(User Space)에서 하드웨어 PMU에 직접 접근하는 독특한 구조를 가지고 있습니다. 이 섹션에서는 PCM의 내부 소프트웨어 아키텍처, 카운터 소유권 관리, 멀티플렉싱 전략, 그리고 플랫폼 자동 감지 메커니즘을 상세히 다룹니다.
PCM의 플랫폼 자동 감지 메커니즘
PCM은 시작 시 CPUID 명령어를 실행하여 CPU의 마이크로아키텍처를 자동 감지합니다. Family/Model/Stepping 조합으로 정확한 플랫폼을 식별하고, 해당 플랫폼에 맞는 이벤트 코드와 카운터 구성을 적용합니다.
/* PCM의 CPU 감지 로직 (간략화) */
/* src/cpucounters.cpp — PCM::detectModel() */
void PCM::detectModel()
{
uint32_t eax, ebx, ecx, edx;
/* CPUID Leaf 1: Family, Model, Stepping */
cpuid(1, &eax, &ebx, &ecx, &edx);
cpu_family = ((eax >> 8) & 0xF) +
((eax >> 20) & 0xFF); /* Extended Family */
cpu_model = ((eax >> 4) & 0xF) |
((eax >> 12) & 0xF0); /* Extended Model */
cpu_stepping = eax & 0xF;
/* CPUID Leaf 0xA: PMU 아키텍처 버전 */
cpuid(0xA, &eax, &ebx, &ecx, &edx);
perfmon_version = eax & 0xFF; /* PMU 버전 */
num_gp_counters = (eax >> 8) & 0xFF; /* GP 카운터 수 */
gp_counter_width = (eax >> 16) & 0xFF; /* 카운터 비트 폭 */
num_fixed_counters = edx & 0x1F; /* Fixed 카운터 수 */
fixed_counter_width = (edx >> 5) & 0xFF; /* Fixed 비트 폭 */
/* 플랫폼별 이벤트 코드 설정 */
switch (cpu_model) {
case 0x8F: /* Sapphire Rapids */
cpu_model_str = "SPR";
L2_hit_event = {0x24, 0xD8};
L3_miss_event = {0x2E, 0x41};
break;
case 0xCF: /* Emerald Rapids */
cpu_model_str = "EMR";
/* SPR과 동일한 이벤트 코드 (호환) */
break;
case 0xAD: /* Granite Rapids */
case 0xAE:
cpu_model_str = "GNR";
num_gp_counters = 8; /* 확장된 카운터 */
break;
}
}
/* PCM 카운터 프로그래밍 순서:
* 1. GLOBAL_CTRL = 0 (모든 카운터 정지)
* 2. PERFEVTSELx = event|umask (이벤트 설정)
* 3. PMCx = 0 (카운터 초기화)
* 4. FIXED_CTR_CTRL = mode (Fixed 카운터 모드 설정)
* 5. GLOBAL_CTRL = 활성 비트 (카운터 시작)
* 6. sleep(interval) (측정 구간 대기)
* 7. PMCx/FIXED_CTRx 읽기 (카운터 값 수집)
* 8. delta = after - before (이전 값과 차이 계산) */
카운터 소유권 관리와 충돌 방지
PCM이 MSR을 직접 프로그래밍하면 커널의 perf 서브시스템과 카운터 소유권 충돌이 발생할 수 있습니다. PCM은 이 문제를 여러 단계로 관리합니다.
# PCM의 카운터 충돌 감지 및 해결 과정
# 1. PCM 시작 시 기존 카운터 소유자 확인
sudo pcm 1
# 출력: "Trying to use MSR directly..."
# 출력: "Checking if other PMU tools are running..."
# 충돌 시 출력:
# "Warning: Performance counter programming conflict detected"
# "Another tool (e.g., perf, VTune) is using the PMU counters"
# 2. 강제 리셋으로 카운터 점유 해제
sudo pcm -r
# → IA32_PERF_GLOBAL_CTRL = 0 (전역 비활성화)
# → 모든 PERFEVTSELx = 0 (이벤트 해제)
# → 모든 PMCx = 0 (카운터 초기화)
# 주의: perf 세션도 동시에 중단됨
# 3. perf_event 모드로 충돌 회피
export PCM_USE_PERF=1
sudo pcm 1
# → 커널의 perf_event 서브시스템이 카운터 소유권 관리
# → perf와 동시 실행 가능 (커널이 멀티플렉싱)
# 4. MSR 접근 경로별 우선순위 확인
# PCM은 다음 순서로 접근 경로를 시도:
# a) TPMI (MMIO) — SPR+ 환경에서 최우선
# b) perf_event — PCM_USE_PERF=1 설정 시
# c) MSR direct — 기본 (최하위 안전성)
# 5. 카운터 사용 상태 디버깅
# perf 카운터 사용 현황
sudo perf stat -e cycles true 2>&1
# "not counted" 또는 "not supported" → 카운터 점유 중
# MSR 직접 읽기로 카운터 상태 확인
sudo rdmsr -p 0 0x38F # IA32_PERF_GLOBAL_CTRL
# → 0이면 모든 카운터 비활성 (정상 대기 상태)
# → 0x700000007이면 Fixed 3개 + GP 4개 활성 (누군가 사용 중)
카운터 델타 계산과 오버플로 처리
PCM은 두 시점 간 카운터 값의 차이(델타)를 계산하여 메트릭을 도출합니다. 48비트 카운터의 오버플로, 카운터 리셋, 코어 마이그레이션 등 예외 상황을 처리하는 로직이 중요합니다.
/* PCM의 델타 계산 로직 (간략화) */
uint64_t getIPC(const CounterState &before,
const CounterState &after)
{
uint64_t instr = after.instRetired - before.instRetired;
uint64_t cycles = after.cycles - before.cycles;
/* 48비트 오버플로 처리 */
if (after.instRetired < before.instRetired) {
/* 오버플로 발생: 2^48 보정 */
instr = (1ULL << 48) - before.instRetired
+ after.instRetired;
}
if (cycles == 0) return 0;
return (double)instr / (double)cycles;
}
/* 메모리 대역폭 계산 */
double getMemoryBW(const CounterState &before,
const CounterState &after,
double elapsed_seconds)
{
/* CAS_COUNT.RD × 64 바이트 = 읽기 바이트 수 */
uint64_t cas_rd = after.imc_rd - before.imc_rd;
uint64_t bytes_rd = cas_rd * 64;
/* GB/s 변환 */
return (double)bytes_rd / elapsed_seconds / 1e9;
}
/* 전력 계산 (RAPL) */
double getPackagePower(const CounterState &before,
const CounterState &after,
double elapsed_seconds)
{
/* RAPL 에너지 단위: MSR_RAPL_POWER_UNIT (0x606) */
/* 에너지 단위 = 2^(-ESU) 줄 (ESU: Energy Status Unit) */
uint64_t energy_delta = after.packageEnergy
- before.packageEnergy;
double joules = energy_delta * rapl_energy_unit;
/* 와트 = 줄 / 초 */
return joules / elapsed_seconds;
}
고급 진단 기법
기본 진단 시나리오를 넘어, PCM을 활용한 고급 진단 기법을 소개합니다. False Sharing 탐지, 메모리 대역폭-레이턴시 곡선 분석, 마이크로아키텍처 이벤트 상관관계 분석 등 내용입니다.
False Sharing 탐지
False Sharing은 서로 다른 코어가 같은 캐시 라인의 다른 변수에 접근할 때 발생하는 불필요한 캐시 일관성 트래픽(Coherence Traffic)입니다. PCM의 L3 미스 카운터와 perf c2c를 결합하여 정밀 탐지할 수 있습니다.
# False Sharing 탐지 실전 절차
# 1. PCM으로 HITM(Hit in Modified) 비율 확인
sudo pcm -e core/config=0xD2,config1=0x02,name=MEM_LOAD_L3_HIT_RETIRED.XSNP_HIT/ 1
# → 값이 높으면 크로스코어 스누프 히트 (공유 라인 경합)
# 2. perf c2c로 상세 분석
sudo perf c2c record -a sleep 10
sudo perf c2c report --stdio
# ==============================================
# Shared Data Cache Line Table
# ==============================================
# Cacheline | Total | Remote | LLC | ... | Symbol
# 0x7f8a3c001000 | 8543 | 6234 | 1523 | ... | stats+0x0
# → Remote HITM 비율 73% → 심각한 False Sharing
# 3. 정확한 오프셋 확인
sudo perf c2c report --sort=cacheline,iaddr --stdio | head -30
# → 어떤 명령어(IP)가 해당 캐시 라인에 접근하는지 확인
# 4. 해결 후 검증
# __cacheline_aligned_in_smp 적용 후 재빌드
sudo pcm 1 -i=5
# → IPC 개선, HITM 카운터 감소 확인
메모리 대역폭-레이턴시 곡선 분석
메모리 대역폭이 증가함에 따라 레이턴시가 비선형적으로 증가하는 큐잉 효과(Queueing Effect)는 서버 성능 예측의 핵심입니다. PCM과 MLC(Memory Latency Checker)를 결합하여 시스템의 대역폭-레이턴시 프로파일을 작성할 수 있습니다.
# 대역폭-레이턴시 곡선 측정 (Intel MLC 활용)
# MLC로 loaded latency 측정 (대역폭 증가에 따른 레이턴시 변화)
sudo mlc --loaded_latency
# Inject Latency Bandwidth
# Delay (ns) (MB/sec)
# 0 82.5 245000 ← 0% 부하
# 100 83.2 232000 ← 5% 부하
# 250 85.1 198000 ← 20% 부하
# 500 91.3 165000 ← 35% 부하
# 1000 102.5 130000 ← 50% 부하 → 레이턴시 급등 시작!
# 2000 125.8 98000 ← 60% 부하
# 5000 178.3 62000 ← 75% 부하
# 0(max) 245.1 280000 ← 100% 부하 (최대 BW 시 레이턴시 3x)
# PCM으로 실제 워크로드의 BW 활용률 확인
sudo pcm-memory 0.5 -i=10
# → Total BW: 165 GB/s → 이론 307 GB/s의 54%
# → MLC 곡선에서 54% 지점의 레이턴시: ~100ns
# → BW 여유가 있어도 레이턴시 민감 앱은 성능 저하 가능
# 권장: BW 활용률 50% 미만 유지 (레이턴시 급등 방지)
# 50% 초과 시: NUMA 격리, 메모리 접근 패턴 최적화 필요
# NUMA 노드별 대역폭-레이턴시 분리 측정
sudo mlc --bandwidth_matrix
# Numa node
# Numa 0 1 2(CXL)
# 0 245000 120000 35000 (MB/s)
# 1 120000 245000 35000
# 2 35000 35000 38000
sudo mlc --latency_matrix
# Numa node
# Numa 0 1 2(CXL)
# 0 82 135 250 (ns)
# 1 135 82 250
# 2 250 250 85
열 스로틀링 정밀 분석
서버의 간헐적 성능 저하는 열 스로틀링(Thermal Throttling)이 원인인 경우가 많습니다. PCM의 온도/주파수 카운터와 RAPL 전력 데이터를 교차 분석하면 정확한 스로틀링 원인과 시점을 파악할 수 있습니다.
# 열 스로틀링 정밀 진단
# 1. pcm-power로 실시간 온도/전력/주파수 추적
sudo pcm-power 0.5 -i=60 -csv=thermal_trace.csv
# 2. CSV에서 스로틀링 시점 탐지
python3 -c "
import csv
with open('thermal_trace.csv') as f:
reader = csv.DictReader(f)
for i, row in enumerate(reader):
temp = float(row.get('TEMP', 0))
freq = float(row.get('FREQ', 0))
pkg_w = float(row.get('PKG_Watts', 0))
if temp > 85 or freq < 2000:
print(f'Row {i}: TEMP={temp}C, FREQ={freq}MHz, PKG={pkg_w}W')
"
# 3. MSR로 스로틀링 원인 직접 확인
# IA32_PACKAGE_THERM_STATUS (0x1B1)
sudo rdmsr -p 0 0x1B1
# bit 0: Thermal Status (1=스로틀링 활성)
# bit 1: Thermal Status Log (1=스로틀링 발생 이력)
# bits 22:16: Digital Readout (TjMax - 현재 온도)
# IA32_PERF_STATUS (0x198)
sudo rdmsr -p 0 0x198
# bits 15:8: Current P-State ratio (현재 주파수 비율)
# ratio × BCLK(100MHz) = 현재 주파수
# 4. 스로틀링 원인 분류
# a) 열 스로틀링: TEMP = TjMax, FREQ 하강, PKG_W 유지/하강
# b) 전력 스로틀링: TEMP < TjMax, FREQ 하강, PKG_W = TDP
# c) AVX 오프셋: AVX-512 실행 시 FREQ 자동 하강
# d) EER 제한: 효율 에너지 비율 초과 시 P-State 강제 하향
# 5. turbostat 병행으로 교차 검증
sudo turbostat --interval 1 --quiet \
--show Core,CPU,Avg_MHz,Busy%,Bzy_MHz,TSC_MHz,\
PkgWatt,CoreTmp,PkgTmp \
--num_iterations 30
이벤트 상관관계 분석
PCM의 여러 메트릭 간 상관관계를 분석하면 성능 문제의 근본 원인을 빠르게 좁힐 수 있습니다. 핵심 상관관계 패턴을 아래에 정리합니다.
| 관찰된 현상 | 상관 메트릭 | 가능한 원인 | PCM 검증 도구 | 해결 방향 |
|---|---|---|---|---|
| IPC < 0.5 + L3 Hit > 90% | HITM 높음, 분기 미스 높음 | False Sharing 또는 분기 예측 실패 | pcm + perf c2c | 캐시 라인 패딩, 분기 힌트 |
| IPC < 0.5 + L3 Hit < 40% | Memory BW 높음 | 워킹셋 > LLC 크기, DRAM 바운드 | pcm + pcm-memory | 데이터 타일링, 프리페치, HBM 활용 |
| IPC 편차 > 3x (코어 간) | 특정 코어 L3 Miss 집중 | NUMA 불균형, 잠금 경합 | pcm + pcm-numa | numactl 바인딩, 잠금 분산 |
| FREQ < Base Clock | PKG Watts = TDP, TEMP 높음 | 열/전력 스로틀링 | pcm-power + turbostat | 냉각 개선, PL1/PL2 조정, AVX 제한 |
| 높은 BW + 낮은 IPC | BW > 70% 이론값 | 메모리 대역폭 포화 | pcm-memory | 채널 증설, DDR 속도 업그레이드, CXL 추가 |
| UPI TX > 70% 이론값 | Remote Access > 20% | 크로스소켓 트래픽 과다 | pcm-numa + pcm | NUMA-aware 코드, 소켓 바인딩 |
| PCIe BW < 50% 이론값 | CPU IPC 정상 | 디바이스 드라이버/인터럽트 문제 | pcm-pcie + pcm-iio | MPS/MRRS 조정, 인터럽트 코얼레싱 |
| C6 잔류 > 50% + 레이턴시 지터 | FREQ 급변, AFREQ 불안정 | 깊은 C-State에서 wake-up 지연 | pcm-power | max_cstate 제한, idle-set -D 1 |
체계적 진단 순서: 성능 문제에 직면하면 다음 순서로 PCM 도구를 실행하세요: (1) pcm 1 -i=5 — IPC, 캐시, 주파수 개요 (2) pcm-memory 1 -i=5 — 메모리 BW 포화 확인 (3) pcm-numa 1 -i=5 — NUMA 불균형 확인 (4) pcm-power 1 -i=5 — 전력/열 제한 확인 (5) pcm-pcie 1 -i=5 — I/O 병목 확인. 이 5단계로 대부분의 하드웨어 병목을 3분 이내에 식별할 수 있습니다.
프로덕션 환경 모범 사례
프로덕션 서버에서 PCM을 안전하고 효과적으로 운용하기 위한 모범 사례를 정리합니다. 성능 오버헤드 관리, 보안 정책 준수, 데이터 수집 전략, 그리고 장기 트렌드 분석 방법을 다룹니다.
성능 오버헤드 관리
PCM의 카운팅 모드는 매우 낮은 오버헤드(일반적으로 CPU 사용률 0.1% 미만)를 가지지만, 프로덕션 환경에서는 이마저도 관리해야 합니다.
# PCM 오버헤드 측정
# pcm-sensor-server의 CPU 사용률 확인
top -p $(pgrep pcm-sensor-server) -b -n 5
# 일반적으로 0.1~0.5% CPU 사용 (5초 간격 폴링 기준)
# 최소 오버헤드 설정 가이드
# 1. 수집 간격 조정 (기본 1초 → 5초로 완화)
sudo pcm-sensor-server -p 9738 --interval 5000
# 2. Prometheus scrape 간격 조정
# prometheus.yml:
# scrape_interval: 10s (5s → 10s로 완화)
# 3. 필요 없는 카운터 비활성화
# pcm-sensor-server의 커스텀 카운터 세트 지정
sudo pcm-sensor-server --core-events -e \
/usr/share/pcm/PMURegisterDeclarations/SPR/minimal.json
# 4. 코어 바인딩으로 모니터링 영향 최소화
# pcm-sensor-server를 특정 코어에 고정
sudo taskset -c 71 pcm-sensor-server -p 9738
# → 마지막 코어에 바인딩하여 워크로드 코어에 영향 없음
장기 데이터 수집 및 트렌드 분석
PCM 데이터를 Prometheus에 장기 저장하면 하드웨어 성능 추세를 분석하고, 용량 계획(Capacity Planning)에 활용할 수 있습니다.
# Prometheus 장기 저장 설정
# prometheus.yml:
# global:
# scrape_interval: 15s # 프로덕션 권장 (5s → 15s)
# storage:
# tsdb:
# retention.time: 90d # 90일 보관
# retention.size: 50GB # 최대 50GB
# PromQL: 주간 IPC 트렌드 (7일 이동 평균)
# avg_over_time(pcm_ipc{socket="0"}[7d])
# PromQL: 메모리 BW 피크 트렌드 (일별 최대값)
# max_over_time(
# sum(pcm_memory_read_bandwidth + pcm_memory_write_bandwidth)
# by (instance, socket)[1d]
# )
# PromQL: 전력 소비 주간 비교
# rate(pcm_package_consumed_energy_joules[1h])
# 용량 계획 활용 예시
# 1. 메모리 BW 활용률이 월별 5%씩 증가 → 6개월 후 포화 예측
# 2. L3 Hit Ratio가 점진적 하락 → 워킹셋 증가, LLC 업그레이드 검토
# 3. PCIe BW가 특정 시간대에 포화 → 네트워크 분산 또는 NIC 업그레이드
# CSV 직접 수집 (Prometheus 없이 간단 모니터링)
# cron으로 주기적 수집
# crontab -e:
# */5 * * * * /usr/sbin/pcm 1 -i=1 -csv=/var/log/pcm/core_$(date +\%Y\%m\%d_\%H\%M).csv
# */5 * * * * /usr/sbin/pcm-memory 1 -i=1 -csv=/var/log/pcm/mem_$(date +\%Y\%m\%d_\%H\%M).csv
멀티 노드 클러스터 모니터링
대규모 서버 클러스터에서 PCM을 운용하는 전략입니다. 각 노드에 pcm-sensor-server를 DaemonSet으로 배포하고, 중앙 Prometheus가 전체 클러스터의 하드웨어 메트릭을 수집합니다.
# Prometheus 서비스 디스커버리 — PCM 엔드포인트 자동 탐지
# prometheus.yml (Kubernetes 환경)
scrape_configs:
- job_name: 'intel-pcm-cluster'
kubernetes_sd_configs:
- role: pod
namespaces:
names: [monitoring]
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
regex: pcm-sensor
action: keep
- source_labels: [__meta_kubernetes_pod_ip]
target_label: __address__
replacement: '${1}:9738'
- source_labels: [__meta_kubernetes_node_name]
target_label: node
metrics_path: '/prometheus'
scrape_interval: 15s
scrape_timeout: 10s
# 멀티 노드 비교 분석 PromQL 쿼리
# 노드별 IPC 비교 (이상치 탐지)
# avg(pcm_ipc) by (node)
# 노드별 메모리 BW 히트맵
# sum(pcm_memory_read_bandwidth) by (node, socket)
# 클러스터 전체 전력 소비
# sum(rate(pcm_package_consumed_energy_joules[5m])) by (node)
# 이상치 노드 자동 탐지 (IPC가 클러스터 평균의 50% 미만)
# avg(pcm_ipc) by (node) < avg(pcm_ipc) * 0.5
# 특정 노드의 NUMA 불균형 알림
# pcm_numa_remote_access_ratio{node=~".*"} > 0.15
# 멀티 노드 PCM 상태 일괄 확인 스크립트
for node in node{01..20}; do
status=$(curl -s -o /dev/null -w "%{http_code}" \
http://${node}:9738/prometheus 2>/dev/null)
if [[ "$status" == "200" ]]; then
# IPC 추출
ipc=$(curl -s http://${node}:9738/prometheus | \
grep 'pcm_ipc{socket="0"' | awk '{print $2}' | head -1)
echo "${node}: OK (IPC=${ipc})"
else
echo "${node}: UNREACHABLE"
fi
done
프로덕션 PCM 배포 체크리스트
| 항목 | 확인 사항 | 명령어 | 권장 설정 |
|---|---|---|---|
| msr 모듈 | 자동 로드 설정 | echo "msr" | tee /etc/modules-load.d/msr.conf |
부팅 시 자동 로드 |
| NMI watchdog | 비활성화 | sysctl kernel.nmi_watchdog=0 |
sysctl.d에 영구 설정 |
| perf_event_paranoid | PCM_USE_PERF 모드 시 | sysctl kernel.perf_event_paranoid=0 |
0 또는 -1 (용도에 따라) |
| 수집 간격 | 프로덕션 최적화 | --interval 5000 |
5~15초 (1초는 개발환경) |
| 보안 | MSR 접근 제한 | PCM_USE_PERF=1 |
perf_event 경로 권장 |
| 코어 바인딩 | 모니터링 오버헤드 격리 | taskset -c N pcm-sensor-server |
유휴 코어에 고정 |
| 로그 로테이션 | CSV 파일 관리 | logrotate /etc/logrotate.d/pcm |
7일 보관, gzip 압축 |
| PCM 버전 | 플랫폼 호환성 | pcm --version |
CPU 모델 지원 확인 |
| 방화벽 | 9738 포트 제한 | ufw allow from prometheus_ip to any port 9738 |
Prometheus 서버만 허용 |
| HTTPS | 전송 암호화 | --https 443 --key --cert |
외부 네트워크 시 필수 |
프로덕션 배포 주의사항: (1) MSR 직접 접근은 보안 위험이 있으므로 PCM_USE_PERF=1 모드를 기본으로 사용하세요. (2) pcm-sensor-server의 9738 포트는 인증이 없으므로 방화벽으로 접근을 제한하세요. (3) PCM 업데이트 시 카운터 리셋이 발생할 수 있으므로 유지보수 윈도우에 수행하세요. (4) 클라우드 VM에서는 언코어 카운터가 작동하지 않으므로, 코어 PMU 기반 메트릭만 수집 가능합니다.
참고자료
Intel PCM 공식 자료
- Intel PCM GitHub 저장소 — PCM 소스 코드, 빌드 방법, 릴리스 노트를 포함합니다
- PCM Linux HOWTO — 리눅스 환경에서 PCM 빌드·설치·실행 방법을 안내합니다
- pcm-sensor-server 문서 — REST API 기반 원격 모니터링 서버 설정 방법을 설명합니다
Intel 개발자 문서
- Intel Performance Monitoring — Intel CPU 성능 모니터링 유닛(PMU) 기술 문서입니다
- Intel PCM 소개 페이지 — PCM 도구의 기능과 활용 시나리오를 소개합니다
- Intel VTune Profiler — PCM과 동일한 PMU 하드웨어를 활용하는 상용 프로파일러입니다
- Intel 64 and IA-32 Architectures SDM Vol. 3B — Chapter 19 Performance Monitoring에서 PMU 아키텍처, MSR, 이벤트 코딩을 정의합니다
- Intel Perfmon Events — CPU 마이크로아키텍처별 성능 모니터링 이벤트 목록을 제공합니다
Top-Down Microarchitecture Analysis (TMA)
- TMA Method (Intel) — Top-Down 분석 방법론의 공식 설명입니다
- pmu-tools (toplev.py) — Andi Kleen의 pmu-tools로 perf 기반 TMA 분석을 수행합니다
- A Top-Down Method for Performance Analysis and Counters Architecture (IEEE) — Ahmad Yasin의 TMA 원본 논문입니다 (ISPASS 2014)
LWN.net 기사
- Performance counters on Linux — 리눅스 커널의 perf_events 서브시스템과 하드웨어 PMU 통합 구조를 설명합니다 (2011)
- Performance events and tool security — PMU 카운터 접근 보안 정책(perf_event_paranoid)을 다룹니다 (2014)
- Uncore performance monitoring — 언코어 PMU를 리눅스 perf에서 지원하는 방법을 설명합니다 (2016)
관련 도구
- perf Wiki — 리눅스 perf 도구의 공식 위키로, PMU 이벤트 수집·분석 방법을 안내합니다
- LIKWID — 하드웨어 성능 카운터 측정 도구로, PCM과 유사하게 MSR 기반 카운터를 지원합니다
- PAPI (Performance Application Programming Interface) — 하드웨어 성능 카운터에 대한 이식 가능한 C API를 제공합니다
- perf-tools (Brendan Gregg) — perf 기반 성능 분석 스크립트 모음으로, PMU 활용 예시를 포함합니다
커널 소스 코드
- arch/x86/events/intel/core.c — Intel 코어 PMU 드라이버 구현입니다
- arch/x86/events/intel/uncore.c — Intel 언코어 PMU 드라이버 구현입니다
- include/linux/perf_event.h — perf_event 서브시스템 핵심 헤더로, PMU 구조체를 정의합니다
- arch/x86/events/perf_event.h — x86 PMU 아키텍처 공통 헤더입니다
관련 문서
Intel PCM과 관련된 다른 주제를 더 깊이 이해하고 싶다면 다음 문서를 참고하세요.