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 드라이버 기반

단계별 이해

  1. 설치: GitHub 소스 빌드 또는 패키지 설치, msr 모듈 로드, NMI watchdog 비활성화
  2. 기본 모니터링: sudo pcm으로 코어별 IPC/캐시(Cache) 히트율/주파수/온도 확인
  3. 메모리 BW: sudo pcm-memory로 소켓별 읽기/쓰기 대역폭 → 이론값 대비 포화율 계산
  4. PCIe/CXL: sudo pcm-pcie(표준) / sudo pcm-pcie -cxl(CXL 장치)로 인바운드/아웃바운드 BW
  5. TPMI 활용: sudo pcm-tpmi로 Sapphire Rapids+ 언코어 카운터 접근 (MSR 불필요)
  6. Grafana 연동: sudo pcm-sensor-server → Prometheus scrape → Grafana 대시보드 임포트
  7. TMA 분석: toplev.py -l1~l3으로 파이프라인(Pipeline) 병목 대분류 → PCM으로 하드웨어 수치 확인
  8. 진단 시나리오: IPC 저하 → 메모리 BW 포화, 주파수 스로틀링, NUMA 불균형, LLC 쓰레싱 순으로 확인
문서 역할: 이 문서는 Intel 플랫폼의 언코어·메모리·PCIe·전력 계측을 다룹니다. 코어 중심 프로파일링은 perf 서브시스템, 전체 튜닝 절차는 성능 최적화, 실시간 지연(Latency) 분석은 RTLA / timerlat / osnoise 문서를 참고하세요.

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은 세 가지 경로로 하드웨어 카운터에 접근합니다:

User Space pcm (Core 카운터) pcm-memory (메모리 BW) pcm-pcie (PCIe BW) pcm-power (전력/온도) pcm-latency (메모리 레이턴시) pcm-sensor-server (REST API/Grafana) Kernel Space /dev/cpu/*/msr (MSR) perf_event_open() (PMU) sysfs / MMIO (TPMI) Hardware (CPU / Uncore) Core PMU PMC, Fixed CTR Uncore PMU CBox, iMC, UPI 메모리 컨트롤러 iMC 카운터 RAPL PKG/DRAM 에너지 PCIe / CXL IIO 카운터
접근 경로대상 카운터커널 요구사항용도
MSR 드라이버Core PMU, Fixed CTR, RAPLmsr 커널 모듈코어별 성능 카운터, 전력 측정
perf_eventCore/Uncore PMUCONFIG_PERF_EVENTSperf 서브시스템 경유 (권한 제어 용이)
sysfs/MMIOTPMI, PCI config spaceTPMI 드라이버 (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 출력의 주요 지표:

지표설명정상 범위이상 징후
IPCInstructions Per Cycle1.0~4.0< 0.5이면 심각한 메모리 스톨
L2 Hit RatioL2 캐시 히트율> 95%< 80%이면 작업 셋 > L2
L3 Hit RatioL3 (LLC) 캐시 히트율> 80%< 50%이면 메모리 대역폭 확인 필요
FREQ실제 동작 주파수 (GHz)부스트 근처기본 클럭 이하이면 전력/열 제한
TEMP코어 온도 (°C)< TjMax-10TjMax 도달 시 스로틀링
INST은퇴된 명령어 수워크로드 의존코어 간 불균형 → 부하 분산(Load Balancing) 문제
AFREQActive Frequency (활성 시 주파수)≈ Max Turbo기본 클럭 근처이면 전력 제한
L3MISSL3 캐시 미스 횟수워크로드 의존높으면 메모리 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만

출력 예시:

SocketRead (GB/s)Write (GB/s)PMM ReadPMM WriteTotal (GB/s)
045.212.8N/AN/A58.0
143.811.5N/AN/A55.3
System89.024.3N/AN/A113.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에서 도입된 새로운 하드웨어 인터페이스로, 다음과 같은 특징을 갖습니다:

# 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 RapidsSPR (Xeon 4th Gen)2023HBM 모니터링, CXL 1.1, TPMI 최초 도입, AMX 카운터✅ 지원
Emerald RapidsEMR (Xeon 5th Gen)2024DDR5 6400MT/s 대역폭, 개선된 언코어 PMU, UPI 3.0✅ 지원
Granite RapidsGNR (Xeon 6th Gen)2024다수 다이 통합 (P-die + E-die), CXL 2.0, 확장 IIO✅ 지원
Ice Lake-SPICX (Xeon 3rd Gen)2021UPI 2.0, PCIe Gen4, DDR4 채널 × 8
Skylake-SPSKX/CLX2017~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 지원

Host CPU (SPR / EMR / GNR) CXL Root Port (IIO) CXL Switch (CXL 2.0+, 선택사항) CXL Type 1 가속기 (캐시 공유) 예: SmartNIC, FPGA 캐시는 있음, 로컬 메모리 없음 CXL Type 2 GPU/가속기 (캐시+메모리) 예: CXL-attached GPU 캐시 + 로컬 메모리 모두 CXL Type 3 메모리 확장 장치 예: DRAM/PMEM 모듈 메모리 전용, 캐시 없음 PCM CXL 모니터링 pcm-pcie -cxl: IIO 포트별 CXL 대역폭 (Read/Write GB/s) pcm-latency: CXL 메모리 접근 레이턴시 (ns 단위) pcm-numa: CXL 노드 로컬/원격 접근 비율 → NUMA topology 반영
CXL 유형특징Linux NUMA 노드PCM 도구대역폭 기준
Type 1가속기, 캐시 공유, 로컬 메모리 없음별도 노드 없음pcm-pcie -cxlPCIe Gen5 ×16 ≈ 128 GB/s
Type 2가속기 + 캐시 + 로컬 메모리별도 NUMA 노드pcm-pcie -cxl, pcm-numa장치 의존적
Type 3메모리 확장 전용 (DRAM/PMEM)별도 NUMA 노드pcm-memory, pcm-latencyCXL 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 /prometheusPrometheus 형식 메트릭text/plain
GET /package/{n}패키지 n의 상세 메트릭JSON
GET /core/{n}코어 n의 상세 메트릭JSON
GET /memory메모리 대역폭 메트릭JSON
GET /pciePCIe 대역폭 메트릭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 레지스터 구조 (Sapphire Rapids 기준) Fixed Counters (IA32_FIXED_CTR0~2) CTR0 (0x309) INST_RETIRED.ANY — 은퇴 명령어 수 CTR1 (0x30A) CPU_CLK_UNHALTED.THREAD — 활성 사이클 CTR2 (0x30B) CPU_CLK_UNHALTED.REF_TSC — 참조 사이클 General-Purpose Counters (IA32_PMC0~7) PMC0 (0xC1) 프로그래밍 가능 — Event + Umask PMC1 (0xC2) 프로그래밍 가능 — Event + Umask PMC2~7 SPR: 최대 8개, 이전: 4개 (모델별 상이) 제어 MSR IA32_PERFEVTSELx (0x186~0x18D) Event(7:0) | Umask(15:8) | USR | OS | EN IA32_PERF_GLOBAL_CTRL (0x38F) Fixed/GP 카운터 전역 활성화 비트맵 IA32_FIXED_CTR_CTRL (0x38D) Fixed 카운터 모드 (User/OS/AnyThread) PCM 프로그래밍 순서 1. GLOBAL_CTRL = 0 (정지) → 2. PERFEVTSELx 설정 → 3. PMCx = 0 (초기화) → 4. GLOBAL_CTRL = 활성화 비트맵 → 5. 주기적 읽기
/* 커널의 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_eventperf_event_paranoid 설정 의존중간 (커널 매개)일부 언코어 카운터 미지원
TPMI/MMIOintel_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 drivermsr 커널 모듈 미로드sudo modprobe msr
Access to Intel different from different different performance monitoring unit다른 프로파일링 도구가 카운터 점유perf, VTune, likwid 등 종료 후 재시도
NMI watchdog is enabled. Consider disablingNMI watchdog가 고정 카운터 점유sudo sysctl kernel.nmi_watchdog=0
Error: PMU counter programmingSecure Boot/lockdown에 의한 MSR 쓰기 차단export PCM_USE_PERF=1 또는 TPMI 모드
Unsupported processor modelPCM 버전이 CPU 모델 미지원PCM 최신 버전으로 업데이트
perf_event_open failedperf_event_paranoid 값이 높음sudo sysctl kernel.perf_event_paranoid=-1
No uncore PMUs detectedVM 환경이거나 언코어 드라이버 미로드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을 결합하면 체계적인 병목 분석이 가능합니다.

Pipeline Slots (100%) Frontend Bound Bad Speculation Backend Bound Retiring Fetch Latency Fetch BW Branch Mispr. Machine Clears Memory Bound Core Bound Base Micro Seq. L1/L2/L3 Bound DRAM Bound Store Bound pcm → IPC/L3 히트율 | pcm-memory → DRAM BW | toplev → TMA Level 1~6 자동 분류
# 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 PCMIntel (오픈소스)MSR, perf_event, MMIO언코어 카운터 (iMC, UPI, IIO) 통합, REST API, CXL 지원Intel CPU 전용
perf커널 내장perf_event범용 프로파일링, 프로세스/함수 수준 분석언코어 카운터 설정 복잡
turbostat커널 소스 포함MSR주파수/전력/C-State 특화, 커널과 함께 배포성능 카운터 제한적
pmu-tools (toplev)Andi Kleenperf 위에 구축Top-Down 마이크로아키텍처 분석 (TMA) 자동화설정 복잡, Intel 전용
likwidRRZE (독일)MSR, perf_eventIntel + AMD 지원, 그룹 기반 측정언코어 카운터 PCM보다 제한적
AMD uProfAMDMSR, perf_eventAMD 전용 언코어 카운터, Infinity Fabric 모니터링AMD CPU 전용

커널 드라이버 및 관련 소스

PCM이 내부적으로 사용하는 커널 인프라:

커널 드라이버/인터페이스경로역할
msr 모듈arch/x86/kernel/msr.c/dev/cpu/N/msr 문자 장치(Character Device) 제공
intel_uncore PMUarch/x86/events/intel/uncore*.cperf 서브시스템에 언코어 PMU 등록
intel_rapldrivers/powercap/intel_rapl_*.cRAPL 전력 측정 (powercap 프레임워크)
intel_vsec/tpmidrivers/platform/x86/intel/tpmi.cTPMI 레지스터 MMIO 접근 (6.3+)
intel-cstate PMUarch/x86/events/intel/cstate.cC-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 병행 워크플로

시스템 성능 분석 워크플로: PCM → perf → 최적화 1단계: 시스템 개요 pcm: IPC, 캐시, 주파수 pcm-memory: BW 포화? pcm-power: 스로틀링? 2단계: 병목 분류 toplev -l1~l3: TMA 분류 Frontend / Backend Memory / Core Bound 3단계: 핫스팟 분석 perf record: 함수별 프로파일 perf annotate: 명령어 수준 perf c2c: 캐시 라인 경합 4단계: 최적화 NUMA 바인딩 캐시 라인 정렬 코드/데이터 구조 개선 단계별 도구 선택 가이드 IPC < 1.0? → 메모리 바운드 의심 → pcm-memory → perf stat -e LLC-load-misses L3 Hit < 50%? → LLC 쓰레싱 의심 → perf c2c → RDT(CAT) LLC 파티셔닝 FREQ < Base Clock? → 열/전력 스로틀링 → pcm-power → turbostat → C-State 조정 Remote Access > 10%? → NUMA 불균형 → pcm-numa → numactl --membind / cpuset PCIe BW < 50% 이론값? → I/O 병목 → pcm-pcie → pcm-iio → lspci 구성 확인
# 실전 예: 데이터베이스 워크로드 병목 분석 전체 과정

# 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로 내려가면 각 대분류의 세부 원인을 계층적으로 좁혀갑니다.

TMA Top-Down Microarchitecture Analysis (Level 1-4) Pipeline Slots (100%) Frontend Bound Bad Speculation Backend Bound Retiring Fetch Latency Fetch Bandwidth Memory Bound Core Bound L1 Bound L2/L3 Bound DRAM Bound ICache Miss ITLB Miss 세대별 TMA 지원 수준 ICX (Ice Lake-SP) TMA 4.0 — Level 1-3 완전, Level 4 부분 지원 SPR (Sapphire Rapids) TMA 4.5 — Level 1-4 완전, AMX/TMUL 메트릭 추가, PEBS-via-PT EMR (Emerald Rapids) TMA 4.6 — SPR 호환 + 메모리 메트릭 세분화, Retire Latency GNR (Granite Rapids) TMA 5.0 — P-core/E-core 분리 메트릭, CXL Bound 신규, 확장 Level 4 SRF (Sierra Forest) TMA 5.0 (E-core) — Atom 전용 TMA 트리, Frontend/Backend 구조 상이 ※ toplev.py는 CPUID를 자동 감지하여 해당 마이크로아키텍처의 TMA 트리를 적용합니다.

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.pypmu-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를 통해 프로그래밍합니다.

Intel Uncore PMU 유닛 구조 (서버 프로세서) Socket 0 CHA (Caching Home Agent) LLC 슬라이스별 PMU × N개 llc_lookup, requests, snoop → perf: uncore_cha_N/ iMC (Memory Controller) 채널별 PMU × M개 cas_count_read/write, act_count → perf: uncore_imc_N/ UPI (Ultra Path Interconnect) 링크별 PMU × K개 data_bandwidth_tx/rx, retry → perf: uncore_upi_N/ M2M (Mesh to Memory) iMC↔메시 브릿지 PMU directory_lookup, wb_to_mem → perf: uncore_m2m_N/ IIO (I/O 유닛) PCIe 스택별 PMU data_req_of_cpu, compls_of_cpu → perf: uncore_iio_N/ UBox (System Agent) 클럭 생성, 인터럽트 라우팅 clock, rapl_events → perf: uncore_ubox/ Mesh Interconnect (Snoop Filter + Ring/Mesh Stop) Core Tile 0..N (Core PMU) LLC Slice 0..N (CHA PMU) DDR5 CH 0..M (iMC PMU) UPI Link 0..K (UPI PMU)

언코어 PMU 프로그래밍 방법

언코어 PMU의 각 유닛은 PCI config space 또는 MMIO 레지스터를 통해 프로그래밍합니다. PCM은 이 과정을 추상화하지만, 커스텀 이벤트를 사용하려면 내부 구조를 이해해야 합니다.

언코어 유닛접근 방식카운터 수PCM 도구대표 이벤트
CHAPCI config / MMIO4 GPpcm (L3 Hit/Miss)LLC_LOOKUP.*, TOR_INSERTS.*
iMCPCI config4 GP + 1 Fixedpcm-memoryCAS_COUNT.RD/WR, ACT_COUNT
UPIPCI config4 GPpcm, pcm-numaDATA_BANDWIDTH_TX, TxL_FLITS.*
M2MPCI config4 GPpcm-rawDIRECTORY_LOOKUP.*, WB_TO_MEM
IIOPCI config4 GPpcm-pcie, pcm-iioDATA_REQ_OF_CPU.*, COMP_BUF
UBoxMSR2 GP + 1 Fixedpcm-rawCLOCKTICKS, 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 디바이스 유형별 프로토콜 및 모니터링 포인트 Host CPU (CXL Root Port) IIO PMU — pcm-pcie / pcm-iio CXL.cache CXL.mem CXL.io (PCIe) Type 1: Accelerator CXL.io + CXL.cache SmartNIC, FPGA 장치가 호스트 메모리 캐시 PCM: IIO + CHA snoop Type 2: Accel + Memory CXL.io + CXL.cache + CXL.mem GPU, AI 가속기 양방향 캐시 일관성 PCM: IIO + CHA + iMC Type 3: Memory Expander CXL.io + CXL.mem Samsung CMM, Micron CZ120 호스트가 장치 메모리에 접근 PCM: pcm-pcie -cxl CXL 모니터링 포인트 요약 IIO 카운터 CXL.io 트랜잭션 대역폭 (pcm-pcie, pcm-iio) CHA 카운터 CXL.cache 스누프/일관성 트래픽 (TOR_INSERTS.CXL) iMC 카운터 CXL.mem 메모리 접근 대역폭 (CAS_COUNT + CXL 채널 분리) DVSEC 레지스터 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) 접근 비율이 높으면 티어링 정책 조정 필요
💡

CXL: CXL 프로토콜 상세, 커널 드라이버 구조, 메모리 티어링 정책 설정은 CXL 메모리 문서를 참고하세요. DAMON 기반 핫/콜드 페이지 분류는 DAMON 문서에서 다룹니다.

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 최적화의 기반 데이터를 제공합니다.

멀티소켓 NUMA 분석: UPI 포화 및 원격 접근 모니터링 Socket 0 (NUMA Node 0) Core 0-35 (P-core) LLC (54 MB) DDR5 × 8ch 로컬 BW: 307 GB/s CXL (Node 2) CXL BW: 32 GB/s Socket 1 (NUMA Node 1) Core 36-71 (P-core) LLC (54 MB) DDR5 × 8ch 로컬 BW: 307 GB/s CXL (Node 3) CXL BW: 32 GB/s UPI ×3 ~192 GB/s 양방향 pcm-numa 출력 해석 가이드 Local Read/Write 같은 소켓의 DDR5에서 처리된 메모리 접근 (최적) Remote Read/Write UPI를 경유하여 다른 소켓의 DDR5에 접근 (레이턴시 2~3배) Remote Access % 전체 메모리 접근 중 원격 접근 비율 — 10% 이상이면 NUMA 최적화 필요 UPI Utilization UPI 링크 대역폭 활용도 — 70% 이상이면 포화 임박, 소켓 분리 검토 UPI L0p/L1 UPI 절전 상태 비율 — 유휴 시 전력 절감 확인

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 패스스루를 활용하는 방법을 다룹니다.

컨테이너/VM 환경 PCM 모니터링 아키텍처 Host (Bare Metal) pcm-sensor-server 전체 시스템 모니터링 (root) → Prometheus / Grafana Kubernetes / Docker Pod A (cgroup) perf_event + cgroup 코어 PMU 격리 가능 PCM_USE_PERF=1 Pod B (cgroup) perf_event + cgroup 코어 PMU 격리 가능 PCM_USE_PERF=1 제한: 언코어 PMU는 cgroup 격리 불가 pcm-memory, pcm-pcie 등은 호스트 레벨에서만 실행 KVM / QEMU VM 1 (vPMU) PMU 패스스루 모드 코어 PMU 직접 접근 pcm 실행 가능 VM 2 (에뮬레이션) vPMU 미지원 시 perf만 제한적 사용 PCM 불가 KVM: -cpu host,pmu=on 으로 vPMU 활성화 코어 PMU만 패스스루, 언코어는 호스트에서만 접근 Hardware PMU (Core PMU + Uncore PMU) MSR / PCI Config / MMIO (TPMI) — root 또는 CAP_SYS_RAWIO 필요

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에서 하이브리드 아키텍처가 본격화되면서 모니터링 전략이 진화하고 있습니다.

Intel 서버 플랫폼 세대별 PMU 진화 시간 2021 ICX Xeon 3세대 Core PMU v5 DDR4 × 8ch UPI 2.0 × 2 TPMI: 미지원 2023 SPR Xeon 4세대 Core PMU v5+ DDR5 × 8ch, HBM UPI 2.0 × 4, CXL 1.1 TPMI: 도입 2024 EMR Xeon 5세대 Core PMU v5+ DDR5-6400 × 8ch UPI 3.0 × 4 TPMI: 안정화 2024 GNR / SRF Xeon 6세대 Core PMU v6 DDR5-6800 × 12ch UPI 3.0 × 6, CXL 2.0 TPMI: 확장 세대별 PCM 기능 차이 항목 ICX SPR EMR GNR/SRF GP 카운터 수 4 + 3 Fixed 4 + 3 Fixed 4 + 3 Fixed 8 + 4 Fixed CHA 수 최대 40 최대 60 최대 60 최대 128 iMC 채널 8 (DDR4) 8 (DDR5)+HBM 8 (DDR5-6400) 12 (DDR5-6800) CXL 지원 미지원 CXL 1.1 CXL 1.1+ CXL 2.0 TMA 버전 4.0 4.5 4.6 5.0 pcm 접근 경로 MSR only MSR + TPMI MSR + TPMI MSR + TPMI PCM 최소 버전 PCM 1.0 PCM 1.4 PCM 1.6 PCM 2.0 하이브리드 P-core only P-core only P-core only P+E (GNR+SRF)

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 기능SPREMRGNR/SRF
기본 언코어 카운터 접근지원지원지원
RAPL 통합기본확장다이별 분리
SST (Speed Select)SST-PP/CPSST-PP/CP/TFSST 전체 + 다이별
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 --versionpcm --help로 현재 버전의 플랫폼 지원 범위를 확인할 수 있습니다.

코어 카운터 메트릭

PCM의 pcm 기본 도구가 표시하는 코어 성능 카운터는 CPU 마이크로아키텍처의 내부 상태를 반영합니다. 각 메트릭의 물리적 의미를 정확히 이해하면, 성능 병목의 근본 원인을 정밀하게 진단할 수 있습니다. 이 섹션에서는 핵심 메트릭의 계산 원리, 해석 방법, 그리고 워크로드 유형별 정상 범위를 상세히 다룹니다.

IPC (Instructions Per Cycle) 심층 분석

IPC는 사이클(Cycle)당 은퇴(Retire)된 명령어 수로, CPU 파이프라인 효율의 가장 중요한 지표입니다. IPC = INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD로 계산되며, 두 값 모두 고정 카운터(Fixed Counter)에서 제공합니다.

IPC 결정 요인 분석 및 워크로드별 기대 범위 IPC = INST_RETIRED.ANY / CPU_CLK_UNHALTED.THREAD IPC 저하 원인 (왼쪽) / IPC 향상 요인 (오른쪽) IPC 저하 원인 캐시 미스 (L2/L3/DRAM) IPC 0.3~0.8 유발 분기 예측 실패 파이프라인 플러시 15-20cy TLB 미스 + 페이지 워크 4-level: ~50cy, 5-level: ~80cy 데이터 의존성 체인 직렬화된 명령어 체인 실행 포트 경합 동일 포트 명령어 집중 메모리 BW 포화 LLC 미스 대기 증가 IPC 향상 요인 높은 캐시 히트율 L1 hit: 4cy, L2 hit: 12cy SIMD/벡터 연산 AVX-512: 다수 연산/명령어 명령어 수준 병렬성 독립 연산 다중 디스패치 하드웨어 프리페치 LLC prefetcher 효과 분기 예측 정확도 TAGE + uBTB 히트 μop 캐시 히트 (DSB) 디코더 바이패스 워크로드 유형별 IPC 기대 범위 (4-wide 파이프라인) HPC (LINPACK) IPC 2.5~4.0 (AVX-512 벡터화) 컴파일러 빌드 IPC 1.5~2.5 (분기 많음, I-Cache 압박) 웹서버 (nginx) IPC 1.0~2.0 (시스템콜 많음, 컨텍스트 전환) 데이터베이스 (OLTP) IPC 0.8~1.5 (랜덤 메모리 접근, 락 경합) 그래프 처리 IPC 0.3~0.8 (포인터 체이싱, LLC 미스 극심) In-memory DB IPC 0.5~1.0 (대규모 워킹셋, DRAM 바운드)

캐시 미스율 해석과 계층별 지연

PCM이 표시하는 L2/L3 캐시 히트율은 메모리 서브시스템의 효율을 나타냅니다. 각 캐시 계층의 미스 비용(레이턴시)을 이해하면, 캐시 미스가 전체 성능에 미치는 영향을 정량적으로 평가할 수 있습니다.

CPU 캐시 계층별 접근 레이턴시 및 PCM 측정 이벤트 L1 Data Cache (48KB/core) 4~5 cycles | ~2 TB/s (코어당) PCM: L1-dcache-load-misses 미스 시 +8cy L2 Unified Cache (2MB/core) 12~14 cycles | ~1 TB/s (코어당) PCM: L2 Hit Ratio, L2_RQSTS.MISS 미스 시 +30cy L3 / LLC (1.875~3.375 MB/core, 공유) 40~50 cycles | ~600 GB/s (소켓) PCM: L3 Hit Ratio, L3MISS, LLC-load-misses 미스 시 +30~50cy 로컬 DRAM (DDR5) 70~100 cycles (~80ns) pcm-memory: Read/Write BW 원격 DRAM (UPI 경유) 120~180 cycles (~130ns) pcm-numa: Remote Access % CXL 메모리 (Type 3) 200~350 cycles (~250ns) pcm-pcie -cxl: CXL BW
# 캐시 계층별 미스율 정밀 측정
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 구성 오류를 나타낼 수 있습니다.

pcm-memory: iMC 채널별 대역폭 측정 구조 CPU Socket 0 — Sapphire Rapids (8채널 DDR5-4800) 이론 최대: 8 × 4800MT/s × 8B = 307.2 GB/s iMC 0 (채널 0~3) iMC 1 (채널 4~7) CH 0 R:36 W:9 CH 1 R:35 W:8 CH 2 R:34 W:9 CH 3 R:12 W:3 CH 4 CH 5 CH 6 CH 7 CH 3 대역폭 이상 저하 — DIMM 장애 의심 채널 간 편차 >30%면 DIMM 구성 점검 필요 메모리 대역폭 병목 판단 기준 Read BW (GB/s) Write BW (GB/s) BW 포화 판단: Total BW / 이론 최대 BW × 100% 0~50%: 정상 (여유 있음) 50~70%: 주의 (고부하 시 병목 가능) 70~85%: 경고 (BW 병목 시작) 85%+: 심각 (즉각 최적화 필요) 채널 불균형: (max_ch - min_ch) / avg_ch × 100% > 30% → DIMM 장애 또는 비대칭 구성 Read/Write 비율: OLTP ~4:1, OLAP ~8:1, Streaming ~1:1, AI Training ~3:1
# 채널별 대역폭 상세 측정
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 성능 병목을 정밀하게 진단할 수 있습니다.

pcm-pcie: IIO 스택별 PCIe 디바이스 대역폭 모니터링 CPU Socket 0 — Mesh Interconnect IIO PMU: uncore_iio_0 ~ uncore_iio_5 IIO Stack 0 PCIe Gen5 x16 IIO Stack 1 PCIe Gen5 x16 IIO Stack 2 PCIe Gen4 x8 + x8 IIO Stack 3 PCIe Gen5 x8 GPU (A100) Gen4 x16 In: 25 GB/s Out: 22 GB/s CXL Mem CXL Type 3 In: 12 GB/s Out: 8 GB/s NIC 200G RDMA In: 24 GB/s Out: 23 GB/s NVMe 0 Gen4 x4 In:6.5 Out:5.2 NVMe 1 Gen4 x4 In:6.8 Out:5.5 DPU Gen5 x8 In: 15 GB/s Out: 14 GB/s PCIe 세대별 이론 대역폭 (단방향, 인코딩 후) 세대 x1 (GB/s) x4 (GB/s) x8 (GB/s) x16 (GB/s) pcm-pcie 측정 대상 Gen3 ~1.0 ~3.9 ~7.9 ~15.8 SKX/CLX 환경 Gen4 ~2.0 ~7.9 ~15.8 ~31.5 ICX, SPR 메인 Gen5 ~3.9 ~15.8 ~31.5 ~63.0 SPR/EMR/GNR 지원 CXL 1.1 - - ~15.8 ~31.5 pcm-pcie -cxl 판단 기준: 측정값이 이론값의 50% 미만이면 I/O 병목 — lspci 링크 속도, MPS/MRRS, 인터럽트 모드 확인
# 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 도메인별 전력 모니터링 구조 및 pcm-power 출력 RAPL Platform Power (MSR 0x64E) 전체 소켓 전력 — TDP: 350W (SPR-HCC) PKG Domain (MSR 0x611) 패키지 전체 전력: 280W PP0 (Cores) MSR 0x639 코어 소비: 180W AVX-512 시 급증 PP1 (Graphics) MSR 0x641 내장 GPU/가속기 서버: 주로 0W DRAM Domain (MSR 0x619) DRAM 전력: 45W (8ch DDR5) DDR5 채널 0~3 iMC 0: 22W 활성 대기: ~0.5W/DIMM Self-Refresh: 극소 DDR5 채널 4~7 iMC 1: 23W BW 비례 증가 고부하 시 ~60W+ 전력-성능 트레이드오프 시나리오 시나리오 PKG 전력 주파수 IPC 처리량 진단 포인트 정상 운영 200W (57%) 3.6 GHz 2.1 100% 기준선 AVX-512 집중 340W (97%) 2.4 GHz 3.5 85% 전력 스로틀링 열 스로틀링 350W (TDP) 1.8 GHz 2.0 60% TEMP = TjMax 절전 모드 80W (23%) 1.2 GHz 1.8 35% C6 잔류 50%+ pcm-power로 PKG 전력과 주파수를 동시 관찰 → 전력 제한(PL1/PL2) 도달 여부 판단
# 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 도구의 조합도 달라집니다.

워크로드별 PCM 도구 활용 전략 매트릭스 워크로드 pcm (코어) pcm-memory (메모리) pcm-pcie (PCIe) pcm-numa (NUMA) pcm-power (전력) 주요 병목 요인 웹서버 (nginx) ●●● ●○○ ●●○ ●○○ ●○○ IPC, 분기, I-Cache, NIC BW DB (OLTP) ●●● ●●● ●●○ ●●● ●○○ LLC 미스, NUMA, NVMe IO DB (OLAP) ●●○ ●●● ●●● ●●○ ●○○ 메모리 BW, 스캔 IO, SIMD HPC (MPI) ●●○ ●●● ●●○ ●●● ●●● UPI BW, DRAM BW, AVX 전력 AI 훈련 (GPU) ●○○ ●●○ ●●● ●●○ ●●○ PCIe BW (GPU), 데이터 로딩 Redis/Memcached ●●● ●●● ●●○ ●●● ●○○ LLC 미스, NUMA, 네트워크 중요도 범례 및 워크로드별 PCM 활용 가이드 ●●● 핵심: 이 워크로드에서 반드시 모니터링해야 할 지표 ●●○ 권장: 병목 발생 가능성이 있어 주기적 확인 권장 ●○○ 참고: 특수 상황에서만 확인 (일상 모니터링 불필요) 전략: pcm으로 전체 개요 → 워크로드 특성에 맞는 도구로 드릴다운 → perf record로 코드 레벨 핫스팟 식별

웹서버 워크로드 (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 쿼리, 알림 규칙 설정을 상세히 다룹니다.

PCM + Prometheus + Grafana 모니터링 아키텍처 서버 노드 1 pcm-sensor-server :9738 Core PMU Uncore PMU RAPL PCIe/CXL 서버 노드 2 pcm-sensor-server :9738 서버 노드 N ... scrape /prometheus Prometheus TSDB 저장소 scrape_interval: 5s retention: 30d PromQL Grafana IPC/캐시 패널 메모리 BW 패널 전력/온도 패널 PCIe BW 패널 Alertmanager Slack / PagerDuty / Email IPC <0.5 / BW >80% / Temp >90 주요 PromQL 쿼리 예시 IPC: pcm_ipc{socket="0"} | BW: sum(pcm_memory_read_bandwidth) by (socket) Temp: pcm_core_temperature{core="0"} | Power: pcm_package_consumed_energy_joules

핵심 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 메모리 티어링 모니터링 워크플로 Linux 메모리 티어링 (kernel 6.1+) Fast Tier: DDR5 (Node 0,1) ~80ns | 307 GB/s/socket Slow Tier: CXL (Node 2,3) ~250ns | 32 GB/s/device Cold Tier: PMEM (선택) ~350ns | 8 GB/s 승격 강등 PCM 기반 CXL 티어링 효과 분석 워크플로 1. 대역폭 프로파일 pcm-memory (DDR5) pcm-pcie -cxl (CXL) DDR:CXL BW 비율 측정 2. 레이턴시 측정 pcm-latency (NUMA별) MLC loaded_latency DDR vs CXL 레이턴시 비 3. 티어링 효과 검증 pcm-numa (접근 비율) /proc/vmstat 승격/강등 핫 페이지 DDR 비율 4. 정책 조정 DAMON 프로모션율 numa_balancing 튜닝 numactl --membind CXL 디바이스 성능 특성과 PCM 측정 포인트 CXL 디바이스 레이턴시 대역폭 용량 PCM 도구 적합 워크로드 Samsung CMM-D ~200ns ~36 GB/s 256 GB pcm-pcie -cxl In-memory DB 확장 Micron CZ120 ~250ns ~32 GB/s 512 GB pcm-pcie -cxl 대규모 캐시, AI 추론 ASIC 가속기 (Type 2) ~150ns ~64 GB/s HBM 탑재 pcm-pcie -cxl + pcm GPU/AI 가속기 Pooled Memory (Switch) ~350ns ~16 GB/s 수 TB pcm-pcie -cxl + pcm-numa VM 메모리 풀링 팁: CXL 레이턴시 > 3x DDR이면 해당 노드에 레이턴시 민감 데이터를 배치하지 않도록 numactl --membind 사용
# 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과 유사한 기능을 제공하는 도구들의 강점, 제한사항, 적용 시나리오를 상세히 비교합니다. 각 도구는 고유한 강점이 있으며, 실무에서는 여러 도구를 상호 보완적으로 사용하는 것이 효과적입니다.

성능 분석 도구 비교: 기능 범위 및 적용 시나리오 시스템 전체 모니터링 ←→ 프로세스/함수 수준 프로파일링 Intel PCM 오픈소스 | Intel 전용 + 언코어 카운터 완전 지원 + REST API / Grafana 연동 + CXL / TPMI 지원 - 프로세스 수준 분석 불가 - AMD CPU 미지원 perf 커널 내장 | 범용 + 프로세스/함수 프로파일링 + Intel + AMD 모두 지원 + Flame Graph, 콜 그래프 - 언코어 설정 복잡 - REST API/대시보드 없음 Intel VTune 상용(무료 제공) | Intel + GUI, 소스 코드 연동 + TMA 자동 분석 + GPU/FPGA 프로파일링 - 서버 CLI 환경 제약 - 실시간 모니터링 제한 pmu-tools (toplev) 오픈소스 | Intel 전용 + TMA Level 1-6 자동 분류 + perf 위에 구축 (호환성) - 설정 복잡, 학습 곡선 - 시스템 전체 모니터링 제한 LIKWID 오픈소스 | Intel + AMD + 그룹 기반 측정 (간편) + 마커 API (코드 구간) - 언코어 PCM보다 제한적 - CXL/TPMI 미지원 turbostat 커널 소스 포함 | Intel + 주파수/전력/C-State 특화 + 커널과 함께 배포 (설치 불필요) - 성능 카운터 미지원 - 메모리/PCIe BW 측정 불가 시나리오별 최적 도구 조합 시스템 전체 상태 모니터링: PCM (언코어/BW) + turbostat (주파수/전력) + Grafana (시각화) 특정 프로세스 병목 분석: toplev (TMA 분류) → perf record (핫스팟) → perf annotate (명령어 수준) 메모리 서브시스템 진단: pcm-memory (BW) + pcm-numa (NUMA 비율) + perf c2c (캐시 라인 경합) + MLC (레이턴시) 개발자 코드 최적화: VTune (GUI, 소스 매핑) 또는 LIKWID (마커 API) + Flame Graph
# 도구별 동일 데이터 수집 비교

# === 코어별 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 Application Layer pcm Core 카운터 IPC/캐시/주파수 pcm-memory iMC 카운터 채널별 BW pcm-pcie IIO 카운터 포트별 BW pcm-power RAPL MSR 전력/온도 pcm-raw JSON 이벤트 커스텀 카운터 pcm-sensor-server REST API (JSON) Prometheus 메트릭 PCM Core Library (libpcm) PCM::getInstance() CPUID 감지 플랫폼 자동 선택 CounterState 코어/언코어 카운터 값 델타 계산 (before-after) ServerUncoreMemory iMC 카운터 추상화 BW 계산 (CAS × 64B) PciHandleType / MsrHandle PCI config read/write MSR pread/pwrite Hardware Access Layer (3가지 경로) MSR Direct Access pread(/dev/cpu/N/msr, reg) perf_event_open() PCM_USE_PERF=1 모드 MMIO (TPMI) intel_vsec sysfs (SPR+) Kernel Space msr.ko (/dev/cpu/*/msr) perf_event subsystem intel_vsec / intel_tpmi Hardware PMU Core PMU (MSR) CHA/LLC PMU iMC PMU (PCI) UPI PMU (PCI) IIO PMU (PCI/MMIO)

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 탐지: PCM + perf c2c 결합 워크플로 캐시 라인 (64 Bytes) Core 0: 변수 A (8B) pad Core 1: 변수 B (8B) 미사용 영역 (48B) — 같은 캐시 라인! 1. PCM으로 감지 pcm: IPC 저하 + L3 Hit Ratio 높음 + HITM 이벤트 다수 2. perf c2c 확인 perf c2c record HITM 분포 확인 크로스소켓 HITM 많음 3. 해결 __cacheline_aligned 구조체 패딩 추가 변수 분리 → 별도 라인 4. 검증 pcm 재측정 IPC 회복 HITM 감소 코드 수준 해결 예시 Before (False Sharing 발생): struct stats { uint64_t core0_count; uint64_t core1_count; }; → core0_count와 core1_count가 같은 캐시 라인에 위치 → 코어 간 무효화 폭풍 After (패딩으로 분리): struct stats { uint64_t core0_count; char pad[56]; uint64_t core1_count; }; → 56B 패딩으로 별도 캐시 라인 보장 → __cacheline_aligned 어트리뷰트 사용 권장
# 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 개발자 문서

Top-Down Microarchitecture Analysis (TMA)

LWN.net 기사

관련 도구

커널 소스 코드

Intel PCM과 관련된 다른 주제를 더 깊이 이해하고 싶다면 다음 문서를 참고하세요.