성능 최적화 (Performance Optimization)
Linux 커널 성능 최적화: perf, ftrace, io_uring, 프로파일링, 튜닝.
성능 최적화 개요
커널 성능 최적화는 병목 지점을 정확히 파악하는 것에서 시작합니다. Linux는 perf, ftrace, BPF 등 강력한 프로파일링/추적 도구를 기본 제공합니다.
성능 모니터링 원리 (PMU)
커널 성능 분석의 기반은 CPU에 내장된 PMU(Performance Monitoring Unit)입니다. PMU는 하드웨어 수준에서 CPU 이벤트를 카운팅하는 전용 회로로, 소프트웨어 오버헤드 없이 정밀한 성능 데이터를 수집합니다.
PMU 동작 메커니즘
| 구성 요소 | 역할 | 예시 |
|---|---|---|
| 성능 카운터 레지스터 | 특정 이벤트 발생 횟수를 카운팅 | x86: PMC0~PMCn (일반적으로 4~8개) |
| 이벤트 선택 레지스터 | 카운팅할 이벤트 종류를 지정 | cycles, instructions, cache-misses, branch-misses |
| 오버플로 인터럽트 | 카운터가 지정값에 도달하면 인터럽트 발생 | PMI(Performance Monitoring Interrupt) |
샘플링 vs 카운팅
perf는 두 가지 방식으로 PMU를 활용합니다:
- 카운팅 모드 (
perf stat): 이벤트 발생 횟수를 정확히 세어 총계를 보여줍니다. 오버헤드가 거의 없으나, 어디서 발생했는지는 알 수 없습니다. - 샘플링 모드 (
perf record): 카운터가 N번 이벤트마다 인터럽트를 발생시키고, 그 시점의 IP(Instruction Pointer)와 콜스택을 기록합니다. 이 샘플들의 통계적 분포로 핫 코드 경로를 식별합니다. 샘플링 주파수(예: -F 99 = 초당 99회)가 높을수록 정밀하지만 오버헤드도 증가합니다.
이벤트 멀티플렉싱: 하드웨어 PMC 수(보통 4~8개)보다 많은 이벤트를 동시에 모니터링하면, 커널이 시분할로 PMC를 전환합니다. 이 경우 결과에 추정값(<not counted> 또는 스케일링 계수)이 포함될 수 있습니다.
프로파일링 방법론
체계적인 성능 분석 워크플로는 다음 순서를 따릅니다:
- 전체 지표 수집 (
perf stat): IPC(Instructions Per Cycle), 캐시 미스율, 분기 예측 실패율 등 시스템 전체의 성능 특성을 파악합니다. IPC < 1이면 메모리/I/O 바운드, IPC > 2이면 컴퓨트 바운드 가능성이 높습니다. - 핫스팟 식별 (
perf record+ Flame Graph): CPU 시간 소모가 집중되는 함수와 콜 체인을 식별합니다. - 정밀 분석 (
perf annotate,ftrace): 핫스팟 함수의 명령어별 사이클 분포, 함수 호출 흐름, 지연 원인을 파악합니다. - 가설 검증 및 최적화: 원인에 맞는 최적화를 적용하고 다시 측정하여 효과를 검증합니다.
Brendan Gregg의 USE 방법론: 모든 리소스(CPU, 메모리, 디스크, 네트워크)에 대해 Utilization(사용률), Saturation(포화도), Errors(에러)를 체계적으로 점검합니다. 이 프레임워크를 따르면 병목을 빠르게 좁힐 수 있습니다.
perf 종합 가이드
perf는 Linux 커널에 내장된 성능 분석 프레임워크로, perf_event_open(2) 시스템 콜을 통해 PMU 하드웨어 카운터, 소프트웨어 이벤트, tracepoint, kprobe/uprobe 등을 통합적으로 활용합니다. 위의 PMU 원리 섹션에서 설명한 카운팅/샘플링 모드를 실전에서 사용하는 도구입니다.
설정 및 권한
perf를 사용하려면 커널 설정과 시스템 권한이 필요합니다:
# 필수 커널 설정
CONFIG_PERF_EVENTS=y # perf_event 서브시스템
CONFIG_HW_PERF_EVENTS=y # 하드웨어 PMU 지원
CONFIG_DEBUG_INFO=y # 심볼/소스 매핑 (annotate, probe)
CONFIG_DEBUG_INFO_BTF=y # BPF 타입 정보 (선택)
CONFIG_KALLSYMS_ALL=y # 모든 커널 심볼 (권장)
# 설치 (배포판별)
sudo apt install linux-tools-$(uname -r) # Debian/Ubuntu
sudo dnf install perf # Fedora/RHEL
perf_event_paranoid 값 | 허용 범위 | 설명 |
|---|---|---|
-1 | 모든 이벤트, 모든 사용자 | 제한 없음 (개발/테스트 환경) |
0 | 커널+사용자 공간 | CPU 이벤트 허용, raw tracepoint 제한 |
1 (기본) | 사용자 공간만 | 커널 프로파일링에 root 또는 CAP_PERFMON 필요 |
2 | 사용자 공간 (CPU 제한) | 시스템 전체 모니터링 불가 |
3 | 거부 | perf_event_open 완전 차단 |
# 현재 설정 확인 및 변경
cat /proc/sys/kernel/perf_event_paranoid
sudo sysctl kernel.perf_event_paranoid=-1 # 임시 해제
# Linux 5.8+: CAP_PERFMON capability (root 대신 사용)
sudo setcap cap_perfmon+ep /usr/bin/perf
perf list: 이벤트 탐색
perf가 지원하는 이벤트를 확인합니다. 이벤트는 카테고리별로 분류됩니다:
| 카테고리 | 예시 | 소스 |
|---|---|---|
| Hardware | cycles, instructions, cache-misses, branch-misses | PMU 카운터 |
| Software | context-switches, page-faults, cpu-migrations | 커널 소프트웨어 카운터 |
| Cache | L1-dcache-load-misses, LLC-load-misses | PMU 캐시 이벤트 |
| Tracepoint | sched:sched_switch, block:block_rq_issue | 커널 tracepoint |
| PMU | cpu/event=0xc0,umask=0x01/ | 플랫폼 특정 PMU |
| Raw | rNNN (예: r003c = unhalted cycles) | 하드웨어 인코딩 직접 지정 |
# 전체 이벤트 목록
perf list
# 카테고리별 필터
perf list hw # 하드웨어 이벤트만
perf list sw # 소프트웨어 이벤트만
perf list cache # 캐시 이벤트
perf list tracepoint # tracepoint 이벤트
perf list pmu # PMU 특정 이벤트
# 키워드 검색
perf list | grep -i 'branch'
# Raw 이벤트: Intel SDM/AMD APM에서 인코딩 확인
# rNNN 형식: r + EventSelect(8bit) + UnitMask(8bit)
perf stat -e r003c ./program # CPU_CLK_UNHALTED.CORE
perf stat: 이벤트 카운팅 심화
perf stat은 카운팅 모드로 이벤트 총계를 수집합니다. 기본 사용법은 디버깅 페이지를 참조하고, 여기서는 분석적 해석에 집중합니다.
# 상세 카운터 (-d: L1, -dd: L1+LLC, -ddd: L1+LLC+TLB+분기)
perf stat -ddd ./program
# 반복 측정으로 통계적 신뢰도 확보
perf stat -r 5 -e cycles,instructions ./program
# 출력: 평균 ± 표준편차 (stddev)
# 인터벌 모드: 1초 간격으로 카운터 출력 (추세 분석)
perf stat -I 1000 -e cycles,instructions -a
# 이벤트 그룹: 동일 PMC 타임슬라이스에서 측정 (비율 정확도 향상)
perf stat -e '{cycles,instructions}' ./program
# CPU별 통계
perf stat -e cycles -A -a -- sleep 5
IPC 해석 가이드:
- IPC < 1.0: 메모리/I/O 바운드 가능성 — 캐시 미스, TLB 미스, 메모리 대역폭 포화 확인
- IPC 1.0~2.0: 혼합 워크로드 — 분기 예측 실패, 파이프라인 스톨 확인
- IPC > 2.0: 컴퓨트 바운드 — 알고리즘/SIMD 최적화가 효과적
cache-misses / cache-references 비율이 5% 이상이면 캐시 최적화가 필요합니다.
perf record / report: 샘플링 프로파일링
perf record는 샘플링 모드로 프로파일 데이터를 perf.data 파일에 기록하고, perf report로 분석합니다.
# 샘플링 주파수 vs 주기
perf record -F 99 ./program # -F: 초당 99 샘플 (주파수)
perf record -c 100000 ./program # -c: 100000 이벤트마다 1 샘플 (주기)
# -F 99: 커널이 주파수를 유지하도록 주기를 자동 조절 (권장)
# -c: 정확한 이벤트 수 기준 (이벤트 빈도가 변할 때 유용)
# 콜 그래프 포함 기록 (다음 섹션에서 방법 비교)
perf record -g -F 99 -p $(pidof myapp) -- sleep 30
# 시스템 전체 + 커널 심볼
perf record -ag -F 99 -- sleep 10
# report 주요 옵션
perf report # TUI 모드 (대화식)
perf report --stdio # 텍스트 출력 (스크립트/로그용)
perf report --hierarchy # 콜 체인 계층 구조
perf report --sort=dso,sym # 라이브러리/심볼별 정렬
perf report --percent-limit=1 # 1% 미만 항목 필터링
콜 그래프 수집 방법 비교
perf record -g로 콜 그래프(콜 스택)를 수집할 때 세 가지 방법을 선택할 수 있으며, 각각 트레이드오프가 다릅니다:
| 방법 | 옵션 | 오버헤드 | 정확도 | 스택 깊이 | 요구사항 |
|---|---|---|---|---|---|
| Frame Pointer (fp) | --call-graph fp | 최소 | 중간 | 무제한 | -fno-omit-frame-pointer 컴파일 |
| DWARF | --call-graph dwarf | 높음 | 높음 | 무제한 | CONFIG_DEBUG_INFO, 디버그 심볼 |
| LBR | --call-graph lbr | 최소 | 높음 | 8~32단계 | Intel CPU (Haswell+), CONFIG_PERF_EVENTS_INTEL_LBR |
# Frame Pointer: 빠르지만 -fno-omit-frame-pointer로 빌드된 코드 필요
perf record --call-graph fp -F 99 ./program
# DWARF: 가장 정확하지만 perf.data 크기 큼 (스택 덤프 저장)
perf record --call-graph dwarf,32768 -F 99 ./program
# 32768 = 스택 덤프 크기 (기본 8192, 깊은 스택이면 증가)
# LBR: Intel CPU에서 하드웨어 지원, 낮은 오버헤드 + 높은 정확도
perf record --call-graph lbr -F 99 ./program
콜 그래프 방법 선택 가이드: 커널 프로파일링은 fp가 기본(커널은 frame pointer 사용). 사용자 공간은 dwarf가 가장 정확하며, Intel 환경에서 오버헤드가 문제면 lbr을 선택하세요. -g만 쓰면 기본값은 fp입니다.
perf annotate: 명령어 수준 분석
perf annotate는 핫스팟 함수의 어셈블리/소스 코드에 샘플 분포를 매핑하여, 어떤 명령어가 가장 많은 사이클을 소모하는지 보여줍니다.
# 기본 사용법 (perf record 후)
perf record -g -F 99 ./program
perf annotate # TUI: 심볼 선택 → 명령어별 비율
perf annotate --symbol=hot_function # 특정 함수 직접 지정
# 소스 코드 인터리빙 (CONFIG_DEBUG_INFO 필요)
perf annotate --source # 소스 + 어셈블리 동시 표시
perf annotate --no-source # 어셈블리만 표시
# stdio 출력 (스크립트/분석용)
perf annotate --stdio --symbol=copy_page
annotate 출력 예시 — 각 어셈블리 명령어 앞에 해당 명령어의 샘플 비율(%)이 표시됩니다:
│ copy_page():
0.50 │ mov (%rsi),%rax
45.20 │ mov %rax,(%rdi) ← 캐시 미스로 스톨 (핫 명령어)
0.30 │ mov 0x8(%rsi),%rax
2.10 │ mov %rax,0x8(%rdi)
│ ...
핫 명령어 해석: mov 명령어에 높은 비율이 나타나면 대개 캐시 미스(메모리 스톨)가 원인입니다. 이때 perf stat -e L1-dcache-load-misses와 함께 확인하세요. div/idiv에 높은 비율이면 정수 나눗셈 비용, 분기 명령에 높으면 분기 예측 실패를 의심합니다.
perf top: 실시간 모니터링
perf top은 top 명령어처럼 실시간으로 CPU를 가장 많이 소모하는 함수를 보여줍니다.
# 시스템 전체 실시간 프로파일링
perf top # 기본: cycles 이벤트
perf top -g # 콜 그래프 포함
# 특정 프로세스 / 이벤트 필터링
perf top -p $(pidof myapp) # PID 기반
perf top -e cache-misses # 캐시 미스 기준 정렬
# TUI에서 심볼 선택 후 Enter → annotate 뷰 (명령어별 분석)
# 's' 키: 심볼 필터, 'K': 커널 심볼 토글
perf trace: 시스템 콜 추적
perf trace는 strace와 유사하지만, 커널 tracepoint 기반으로 동작하여 오버헤드가 훨씬 낮습니다.
| 특성 | strace | perf trace |
|---|---|---|
| 메커니즘 | ptrace (프로세스 중단) | perf_event tracepoint |
| 오버헤드 | 높음 (2~10x 느려짐) | 낮음 (<5%) |
| 시스템 전체 | PID별만 가능 | -a로 시스템 전체 |
| 통계 모드 | -c | -s (더 상세) |
| 이벤트 확장 | 시스콜만 | 시스콜 + page-fault + 기타 이벤트 |
# 기본 사용법
perf trace ./program # 새 프로세스 추적
perf trace -p $(pidof myapp) # 실행 중인 프로세스
# 필터링
perf trace -e open,read,write ./program # 특정 시스콜만
perf trace --duration 10 -p 1234 # 10ms 이상 소요된 콜만
# 요약 모드: 시스콜별 횟수/시간 통계
perf trace -s ./program
# 출력: syscall calls errors total(ms) min(ms) avg(ms) max(ms)
# 시스템 전체 + page fault 포함
perf trace -a -e 'major-faults,minor-faults' -- sleep 5
perf c2c: False Sharing 탐지
perf c2c(cache-to-cache)는 HITM(Hit in Modified) 이벤트를 분석하여, 여러 CPU 코어가 동일 캐시라인을 경쟁적으로 수정하는 false sharing을 탐지합니다.
# 1단계: 메모리 접근 샘플 기록
perf c2c record -a -- sleep 10
# 또는 특정 프로세스
perf c2c record -p $(pidof myapp) -- sleep 10
# 2단계: HITM 분석 리포트
perf c2c report --stdio
# Shared Data Cache Line Table에서:
# - Rmt HITM: 원격 소켓에서 수정된 라인 접근 (가장 비쌈)
# - Lcl HITM: 같은 소켓 내 다른 코어에서 수정된 라인 접근
# 3단계: 핫 캐시라인의 오프셋 + 데이터 소스 확인
# → struct 멤버 분리 또는 ____cacheline_aligned 적용
캐시 코히런시 프로토콜(MESI/MOESI)과 false sharing의 원리, ____cacheline_aligned 해결 기법 등 상세 내용은 CPU 캐시 — False Sharing 페이지를 참고하세요.
perf diff: 프로파일 비교
perf diff는 두 개의 perf.data 파일을 비교하여 최적화 전후의 성능 변화를 정량적으로 분석합니다.
# A/B 테스트 워크플로
# 1. 최적화 전 프로파일 기록
perf record -g -F 99 -o baseline.data -- ./program_v1
# 2. 최적화 후 프로파일 기록
perf record -g -F 99 -o optimized.data -- ./program_v2
# 3. 비교 분석
perf diff baseline.data optimized.data
# 출력 컬럼:
# Baseline Delta Symbol
# -------- ----- ------
# 15.30% -8.20% hot_function ← 8.2% 감소 (개선)
# 3.10% +2.50% new_function ← 2.5% 증가 (회귀)
# delta 기준 정렬
perf diff --sort=delta baseline.data optimized.data
perf bench: 내장 벤치마크
perf bench는 커널/하드웨어 서브시스템의 기본 성능을 측정하는 마이크로벤치마크 모음입니다. 시스템 설정 변경이나 커널 업그레이드 전후 비교에 유용합니다.
| 카테고리 | 벤치마크 | 측정 대상 |
|---|---|---|
sched | messaging, pipe | 스케줄러 컨텍스트 스위치, IPC 성능 |
mem | memcpy, memset | 메모리 대역폭 |
numa | mem | NUMA 노드 간 메모리 접근 지연 |
futex | hash, wake, requeue, lock-pi | futex 서브시스템 성능 |
epoll | wait, ctl | epoll 이벤트 처리 성능 |
# 스케줄러: 메시지 패싱 성능 (프로세스/스레드 간)
perf bench sched messaging -g 20 -t -l 1000
# -g 20: 20개 그룹, -t: 스레드 사용, -l 1000: 1000회 반복
# 메모리: memcpy 대역폭
perf bench mem memcpy -s 4GB -l 5
# futex: 잠금 성능 (nthread별)
perf bench futex lock-pi -t 8
# NUMA: 노드 간 메모리 접근
perf bench numa mem -p 4 -t 4 -P 1024 -T 0
# 전체 벤치마크 실행
perf bench all
Intel/AMD 플랫폼별 PMU
범용 이벤트(cycles, instructions) 외에, 플랫폼별 PMU 확장 기능을 활용하면 더 정밀한 분석이 가능합니다.
Intel PEBS (Precise Event-Based Sampling)
PEBS는 이벤트 발생 시점의 정확한 IP(Instruction Pointer)를 하드웨어가 기록합니다. 일반 샘플링의 "skid"(인터럽트 지연으로 인한 IP 부정확) 문제를 해결합니다.
# PEBS 이벤트: 이벤트명 뒤에 :p 또는 :pp 수정자
# :p = precise level 1, :pp = precise level 2 (최대 정밀도)
perf record -e cycles:pp -F 99 ./program
perf record -e mem-loads:pp -F 97 ./program # 메모리 로드 정밀 샘플링
# PEBS + annotate로 정확한 명령어별 분석
perf annotate --symbol=hot_function
AMD IBS (Instruction-Based Sampling)
IBS는 명령어 파이프라인에서 직접 샘플링하여 PEBS와 유사한 정밀도를 제공합니다. Fetch와 Op 두 가지 모드가 있습니다.
# AMD IBS Fetch 샘플링
perf record -e ibs_fetch// -c 100000 ./program
# AMD IBS Op 샘플링 (실행된 마이크로-op 기반)
perf record -e ibs_op// -c 100000 ./program
# IBS + 메모리 접근 분석
perf mem record -- ./program # AMD에서 자동으로 IBS 사용
플랫폼별 유용 이벤트
| 이벤트 | 플랫폼 | 용도 |
|---|---|---|
mem-loads:pp, mem-stores:pp | Intel (PEBS) | 메모리 접근 지연/소스 분석 |
ibs_op//, ibs_fetch// | AMD (IBS) | 명령어/페치 수준 정밀 분석 |
topdown-* | Intel (Skylake+) | Top-Down 마이크로아키텍처 분석 |
offcore_response | Intel | L3 미스 후 메모리 응답 소스 분석 |
cpu/event=0x...,umask=0x.../ | 공통 | 벤더 문서의 raw 이벤트 직접 지정 |
MSR 레지스터를 통한 PMU 제어, HWP/RAPL 등 하드웨어 성능 모니터링의 저수준 세부사항은 MSR 레지스터 페이지를 참고하세요.
Flame Graph 분석
Flame Graph는 CPU 프로파일 데이터를 스택 깊이별로 시각화하여 핫 코드 경로를 직관적으로 식별합니다:
# On-CPU Flame Graph
perf record -F 99 -ag -- sleep 30
perf script > out.perf
stackcollapse-perf.pl out.perf > out.folded
flamegraph.pl out.folded > cpu_flame.svg
# Off-CPU Flame Graph (블로킹 시간 분석)
# BPF 기반 (bcc tools)
offcputime-bpfcc -df -p $(pidof myapp) 30 > offcpu.folded
flamegraph.pl --color=io offcpu.folded > offcpu_flame.svg
# Memory allocation Flame Graph
perf record -e kmem:kmalloc -ag -- sleep 10
perf script | stackcollapse-perf.pl | flamegraph.pl > mem_flame.svg
Differential Flame Graph
perf diff의 결과를 시각화하여 최적화 전후 변화를 색상으로 표현합니다:
# 최적화 전/후 프로파일 수집
perf record -F 99 -ag -o before.data -- ./workload_v1
perf record -F 99 -ag -o after.data -- ./workload_v2
# Differential Flame Graph 생성
perf script -i before.data | stackcollapse-perf.pl > before.folded
perf script -i after.data | stackcollapse-perf.pl > after.folded
difffolded.pl before.folded after.folded | flamegraph.pl > diff_flame.svg
# 빨간색: 증가 (회귀), 파란색: 감소 (개선)
Intel® PCM (Performance Counter Monitor)
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 아키텍처 개요
PCM은 세 가지 경로로 하드웨어 카운터에 접근합니다:
| 접근 경로 | 대상 카운터 | 커널 요구사항 | 용도 |
|---|---|---|---|
| MSR 드라이버 | Core PMU, Fixed CTR, RAPL | msr 커널 모듈 | 코어별 성능 카운터, 전력 측정 |
| perf_event | Core/Uncore PMU | CONFIG_PERF_EVENTS | perf 서브시스템 경유 (권한 제어 용이) |
| sysfs/MMIO | TPMI, PCI config space | TPMI 드라이버 (6.3+) | 언코어 카운터, PCIe/CXL 모니터링 |
설치 및 빌드
# 소스에서 빌드 (GitHub)
git clone --recursive https://github.com/intel/pcm.git
cd pcm
mkdir build && cd build
cmake ..
cmake --build . --parallel
# 패키지 매니저로 설치 (배포판별)
sudo apt install pcm # Ubuntu 22.04+ / Debian
sudo dnf install pcm # Fedora / RHEL 9+
# Docker로 실행 (권한 필요)
docker run --privileged -d \
--name pcm --ipc=host --pid=host \
-v /sys:/sys:rw \
ghcr.io/intel/pcm
커널 모듈 및 접근 권한 설정
PCM은 MSR 레지스터에 직접 접근하므로 msr 커널 모듈과 root 권한(또는 CAP_SYS_RAWIO)이 필요합니다:
# msr 커널 모듈 로드
sudo modprobe msr
# NMI watchdog 비활성화 (PMU 카운터 점유 방지)
# NMI watchdog가 고정 카운터를 사용하면 PCM과 충돌
sudo sysctl kernel.nmi_watchdog=0
# Secure Boot 환경에서 MSR 접근 허용
# /dev/cpu/*/msr 접근이 차단될 경우:
sudo modprobe msr allow_writes=on
# perf_event 기반 접근 사용 시 (MSR 직접 접근 대신)
# PCM은 perf_event 모드도 지원 (-e 옵션 또는 환경변수)
export PCM_USE_PERF=1
sudo sysctl kernel.perf_event_paranoid=-1
NMI watchdog 충돌: NMI watchdog는 고정 카운터(INST_RETIRED.ANY)를 점유합니다. PCM 실행 전 nmi_watchdog=0으로 비활성화하지 않으면 카운터 프로그래밍이 실패하거나 부정확한 결과가 나올 수 있습니다. PCM은 시작 시 이 충돌을 자동 감지하고 경고합니다.
핵심 도구 모음
PCM은 목적별로 분리된 여러 도구를 제공합니다. 각 도구는 Intel CPU의 특정 하드웨어 카운터에 최적화되어 있습니다.
pcm: 코어 성능 카운터
기본 도구로, 코어별 IPC(Instructions Per Cycle), L2/L3 캐시 히트율, 분기 예측률 등 핵심 지표를 실시간 표시합니다.
# 기본 실행: 1초 간격으로 코어별 성능 카운터 표시
sudo pcm
# 측정 간격 및 반복 횟수 지정
sudo pcm 0.5 -i=20 # 0.5초 간격, 20회 측정
# CSV 출력 (후처리/시각화용)
sudo pcm 1 -csv=result.csv
# 특정 프로그램 실행 동안 측정
sudo pcm -- ./benchmark
# 코어 이벤트 커스텀 지정 (최대 4개 범용 카운터)
sudo pcm -e core/config=0x2e,config1=0x41,name=LLC_MISSES/
pcm 출력의 주요 지표:
| 지표 | 설명 | 정상 범위 | 이상 징후 |
|---|---|---|---|
| IPC | Instructions Per Cycle | 1.0~4.0 | < 0.5이면 심각한 메모리 스톨 |
| L2 Hit Ratio | L2 캐시 히트율 | > 95% | < 80%이면 작업 셋 > L2 |
| L3 Hit Ratio | L3 (LLC) 캐시 히트율 | > 80% | < 50%이면 메모리 대역폭 확인 필요 |
| FREQ | 실제 동작 주파수 (GHz) | 부스트 근처 | 기본 클럭 이하이면 전력/열 제한 |
| TEMP | 코어 온도 (°C) | < TjMax-10 | TjMax 도달 시 스로틀링 |
| INST | 은퇴된 명령어 수 | 워크로드 의존 | 코어 간 불균형 → 부하 분산 문제 |
| AFREQ | Active Frequency (활성 시 주파수) | ≈ Max Turbo | 기본 클럭 근처이면 전력 제한 |
| L3MISS | L3 캐시 미스 횟수 | 워크로드 의존 | 높으면 메모리 BW 병목 |
pcm-memory: 메모리 대역폭 모니터링
소켓/채널별 메모리 대역폭(Read/Write/Total)을 iMC(Integrated Memory Controller) 카운터로 실시간 측정합니다. NUMA 환경에서 메모리 병목 진단에 필수적입니다.
# 소켓/채널별 메모리 대역폭 측정
sudo pcm-memory
# 0.5초 간격, 파일 출력
sudo pcm-memory 0.5 -csv=mem_bw.csv
# 특정 소켓만 모니터링
sudo pcm-memory -s 0 # 소켓 0만
# 출력 예시:
# Skt | Read(GB/s) | Write(GB/s) | PMM Read | PMM Write | Total(GB/s)
# ---+------------+-------------+----------+-----------+------------
# 0 | 45.2 | 12.8 | N/A | N/A | 58.0
# 1 | 43.8 | 11.5 | N/A | N/A | 55.3
# ---+------------+-------------+----------+-----------+------------
# System| 89.0 | 24.3 | N/A | N/A | 113.3
메모리 대역폭 포화 판단: 이론적 최대 대역폭은 채널 수 × DDR 전송률 × 8바이트로 계산됩니다. 예: 6채널 DDR5-4800 = 6 × 4800MT/s × 8B ≈ 230 GB/s. 측정값이 이론값의 70% 이상이면 메모리 BW 포화 상태입니다. perf stat -e LLC-load-misses와 함께 확인하세요.
pcm-pcie: PCIe 대역폭 모니터링
IIO(I/O 유닛) 언코어 카운터를 통해 PCIe 포트별 인바운드/아웃바운드 대역폭을 측정합니다. NVMe SSD, GPU, 네트워크 카드 등의 I/O 병목 진단에 사용합니다.
# PCIe 포트별 대역폭 (GB/s)
sudo pcm-pcie
# 이벤트 모드: Part0~Part3 상세 분류
sudo pcm-pcie -e
# 특정 BDF (Bus:Device.Function) 필터링
sudo pcm-pcie -B 0x3a:0x00.0
# CSV 출력
sudo pcm-pcie 1 -csv=pcie_bw.csv
# CXL 메모리 대역폭 모니터링 (지원 플랫폼)
sudo pcm-pcie -cxl
pcm-power: 전력 및 열 모니터링
RAPL(Running Average Power Limit) MSR과 온도 센서를 통해 패키지/DRAM/PP0/PP1별 전력 소비와 코어 온도, C-State 상주 비율을 실시간으로 표시합니다.
# 전력/온도/C-State 모니터링
sudo pcm-power
# 출력 예시:
# Package 0: Consumed energy (Joules): 85.2 | Thermal headroom: 23°C
# Package 0: C2 residency: 45.2% | C6 residency: 32.1%
# DRAM energy: 12.8 J
# 전력 변화 추세 관찰 (CSV)
sudo pcm-power 1 -csv=power.csv
pcm-latency: 메모리 레이턴시 측정
메모리 접근 레이턴시를 측정합니다. NUMA 환경에서 로컬/원격 메모리 접근 지연 차이를 정량적으로 파악할 수 있습니다.
# 메모리 레이턴시 측정
sudo pcm-latency
# 특정 소켓 대상
sudo pcm-latency -s 0
pcm-numa: NUMA 트래픽 분석
NUMA 환경에서 로컬/원격 메모리 접근 비율을 측정하여 메모리 배치 최적화 기회를 식별합니다.
# NUMA 로컬/원격 메모리 접근 비율 측정
sudo pcm-numa
# 출력 예시:
# Socket 0: Local Memory Accesses: 95.2% | Remote: 4.8%
# Socket 1: Local Memory Accesses: 87.3% | Remote: 12.7% ← 최적화 필요
# NUMA 최적화 확인: 원격 접근이 10% 이상이면
# numactl --membind 또는 cpuset으로 바인딩 조정 필요
pcm-iio: I/O 유닛 통계
IIO(I/O 유닛) 스택별 인바운드/아웃바운드 트래픽을 상세 분석합니다. PCIe 디바이스와 CPU 소켓 간 데이터 흐름을 파악합니다.
# I/O 유닛(IIO) 스택별 트래픽
sudo pcm-iio
# CSV 출력
sudo pcm-iio 1 -csv=iio.csv
pcm-raw: Raw 카운터 프로그래밍
사전 정의 도구로 측정할 수 없는 커스텀 이벤트를 JSON 기반 이벤트 정의 파일로 프로그래밍합니다. Intel SDM의 이벤트 코드를 직접 지정할 수 있습니다.
# JSON 이벤트 정의 파일 사용
sudo pcm-raw -e events.json
# 이벤트 정의 예시 (events.json):
# {
# "core": {
# "programmable": [
# { "name": "L2_MISS", "event": "0x2e", "umask": "0x41" },
# { "name": "DTLB_MISS", "event": "0x08", "umask": "0x20" }
# ]
# }
# }
# PCM 배포에 포함된 사전 정의 이벤트
ls /usr/share/pcm/PMURegisterDeclarations/
# → SPR/ ICX/ SKX/ ... (마이크로아키텍처별 이벤트 파일)
pcm-sensor-server: 원격 모니터링 (REST API / Grafana)
pcm-sensor-server는 PCM 데이터를 HTTP/HTTPS REST API로 노출하여, Grafana, Prometheus, Telegraf 등 외부 모니터링 시스템과 통합합니다.
# 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
# Prometheus 형식 메트릭 노출 → Grafana 대시보드 연동
# Grafana 대시보드 활용
# PCM 소스의 grafana/ 디렉터리에 사전 정의 대시보드 JSON 포함
# → Grafana에서 Import하면 코어/메모리/PCIe/전력 대시보드 즉시 사용
pcm-tpmi: Topology Aware Register & PM Interface (6.3+)
Sapphire Rapids 이후 서버 플랫폼에서 TPMI(Topology Aware Register and PM Interface)를 통해 언코어 카운터에 접근합니다. MSR 대신 MMIO 기반으로 동작하여 Secure Boot 환경에서도 사용 가능합니다.
# TPMI 기반 언코어 카운터 접근
sudo pcm-tpmi
# TPMI 지원 확인
ls /sys/bus/auxiliary/devices/ | grep intel_vsec
# intel_vsec 드라이버가 로드되어 있으면 TPMI 지원
실전 활용 시나리오
시나리오 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이면 전력/열 제한
PCM과 대안 도구 비교
| 도구 | 제공자 | 카운터 접근 | 강점 | 제한 |
|---|---|---|---|---|
| Intel PCM | Intel (오픈소스) | MSR, perf_event, MMIO | 언코어 카운터 (iMC, UPI, IIO) 통합, REST API | Intel CPU 전용 |
| perf | 커널 내장 | perf_event | 범용 프로파일링, 프로세스/함수 수준 분석 | 언코어 카운터 설정 복잡 |
| turbostat | 커널 소스 포함 | MSR | 주파수/전력/C-State 특화, 커널과 함께 배포 | 성능 카운터 제한적 |
| pmu-tools (toplev) | Andi Kleen | perf 위에 구축 | Top-Down 마이크로아키텍처 분석 (TMA) 자동화 | 설정 복잡, Intel 전용 |
| likwid | RRZE (독일) | MSR, perf_event | Intel + AMD 지원, 그룹 기반 측정 | 언코어 카운터 PCM보다 제한적 |
Top-Down 마이크로아키텍처 분석 (TMA) 연계
Intel의 Top-Down Microarchitecture Analysis (TMA) 방법론은 CPU 파이프라인의 병목을 4개 대분류(Frontend Bound, Backend Bound, Bad Speculation, Retiring)로 분류합니다. PCM과 pmu-tools/toplev을 결합하면 체계적인 병목 분석이 가능합니다.
# pmu-tools 설치
git clone https://github.com/andikleen/pmu-tools.git
cd pmu-tools
# toplev: TMA Level 1 (대분류) 분석
sudo python3 toplev.py --core S0-C0 -l1 -v -- ./benchmark
# 출력: FE(Frontend) 30%, BE(Backend) 45%, BadSpec 5%, Retiring 20%
# → Backend Bound가 지배적 → 메모리/코어 바운드 분석 필요
# Level 2: Backend Bound 상세 분해
sudo python3 toplev.py --core S0-C0 -l2 -v -- ./benchmark
# → Memory Bound 35%, Core Bound 10%
# Level 3+: Memory Bound 세부 원인
sudo python3 toplev.py --core S0-C0 -l3 --nodes '!+Memory*' -v -- ./benchmark
# → L3 Bound 8%, DRAM Bound 22%, Store Bound 5%
# → pcm-memory로 DRAM BW 포화 확인
# PCM + toplev 병행 워크플로
# 1. pcm: 전체 시스템 IPC/캐시/주파수 개요 → 이상 징후 파악
# 2. toplev -l1~l3: 병목 카테고리 좁히기
# 3. pcm-memory/pcm-pcie: 구체적 하드웨어 병목 수치 확인
# 4. perf record + annotate: 함수/명령어 수준 최적화
커널 드라이버 및 관련 소스
PCM이 내부적으로 사용하는 커널 인프라:
| 커널 드라이버/인터페이스 | 경로 | 역할 |
|---|---|---|
msr 모듈 | arch/x86/kernel/msr.c | /dev/cpu/N/msr 문자 장치 제공 |
intel_uncore PMU | arch/x86/events/intel/uncore*.c | perf 서브시스템에 언코어 PMU 등록 |
intel_rapl | drivers/powercap/intel_rapl_*.c | RAPL 전력 측정 (powercap 프레임워크) |
intel_vsec/tpmi | drivers/platform/x86/intel/tpmi.c | TPMI 레지스터 MMIO 접근 (6.3+) |
intel-cstate PMU | arch/x86/events/intel/cstate.c | C-State 상주 시간 카운터 |
| PCI config space | /sys/bus/pci/devices/*/config | 언코어 PCI 레지스터 접근 (iMC, UPI) |
/* PCM이 MSR을 읽는 커널 경로 (arch/x86/kernel/msr.c) */
static ssize_t msr_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
u32 __user *tmp = (u32 __user *)buf;
u32 data[2];
u32 reg = *ppos; /* MSR 주소 = file offset */
int cpu = iminor(file->f_path.dentry->d_inode);
int err;
/* 해당 CPU에서 RDMSR 실행 */
err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
if (err)
return -EIO;
if (copy_to_user(tmp, &data, 8))
return -EFAULT;
return 8;
}
/* PCM의 실제 MSR 읽기 (user space → /dev/cpu/N/msr) */
/* pread(fd, &data, sizeof(data), MSR_ADDR) */
/* 예: pread(fd, &val, 8, 0x38F) → IA32_PERF_GLOBAL_CTRL */
# PCM에 필요한 커널 설정
CONFIG_X86_MSR=m # /dev/cpu/*/msr (필수)
CONFIG_PERF_EVENTS=y # perf_event 모드 사용 시
CONFIG_INTEL_UNCORE=m # 언코어 PMU (perf_event 경유 시)
CONFIG_INTEL_RAPL=m # RAPL 전력 측정
CONFIG_INTEL_VSEC=m # TPMI 지원 (SPR+ 서버)
CONFIG_INTEL_PMT_TELEMETRY=m # PMT 텔레메트리
# msr 모듈 자동 로드 설정
echo "msr" | sudo tee /etc/modules-load.d/msr.conf
perf_event 모드 vs MSR 직접 접근: PCM_USE_PERF=1 환경 변수를 설정하면 PCM이 MSR 직접 접근 대신 perf_event_open()을 통해 카운터에 접근합니다. 이 모드는 msr 커널 모듈이 불필요하고, perf_event_paranoid로 권한을 세밀하게 제어할 수 있습니다. 다만 일부 언코어 카운터는 perf_event로 접근이 불가하므로 MSR 모드가 더 완전한 데이터를 제공합니다.
ftrace
ftrace는 커널 내장 추적 프레임워크입니다. 함수 호출, 이벤트, 지연 시간 등을 추적합니다. ftrace의 핵심 원리는 동적 계측(dynamic instrumentation)입니다 — 커널 컴파일 시 모든 함수 진입점에 nop 명령어를 삽입하고, 추적 활성화 시 이를 trampoline 호출로 교체하여 함수 진입/종료를 기록합니다. 비활성 상태에서는 nop이므로 오버헤드가 거의 없습니다.
# ftrace 디렉터리
cd /sys/kernel/tracing # 또는 /sys/kernel/debug/tracing
# 함수 추적
echo function > current_tracer
echo do_sys_openat2 > set_ftrace_filter
echo 1 > tracing_on
cat trace
echo 0 > tracing_on
# 함수 호출 그래프
echo function_graph > current_tracer
echo vfs_read > set_graph_function
echo 1 > tracing_on
# 이벤트 추적
echo 1 > events/sched/sched_switch/enable
echo 1 > tracing_on
cat trace_pipe
io_uring
io_uring은 Linux 5.1에서 도입된 비동기 I/O 인터페이스로, 공유 링 버퍼를 통해 시스템 콜 오버헤드를 최소화합니다. SQPOLL+IOPOLL 모드에서는 시스템 콜과 인터럽트 없이 I/O를 처리할 수 있습니다.
io_uring의 상세 아키텍처, 커널 내부 구현, liburing 예제, 보안 고려사항 등은 io_uring 전용 페이지를 참고하세요.
커널 튜닝 파라미터
| 파라미터 | 경로 | 설명 |
|---|---|---|
| swappiness | /proc/sys/vm/swappiness | 스왑 적극성 (0-200) |
| dirty_ratio | /proc/sys/vm/dirty_ratio | dirty 페이지 비율 임계값 |
| tcp_rmem | /proc/sys/net/ipv4/tcp_rmem | TCP 수신 버퍼 크기 |
| tcp_wmem | /proc/sys/net/ipv4/tcp_wmem | TCP 송신 버퍼 크기 |
| nr_hugepages | /proc/sys/vm/nr_hugepages | Huge page 수 |
| sched_latency_ns | /proc/sys/kernel/sched_latency_ns | CFS 스케줄링 주기 |
컴파일러 최적화 힌트
/* Branch prediction hints */
if (likely(condition)) /* 대부분 true */
fast_path();
if (unlikely(error)) /* 대부분 false */
handle_error();
/* Cache prefetch */
prefetch(ptr); /* L1 캐시로 미리 로드 */
prefetchw(ptr); /* 쓰기 의도로 미리 로드 */
/* Hot/Cold function sections */
void __hot fast_func(void); /* .text.hot 섹션 */
void __cold error_func(void); /* .text.unlikely 섹션 */
/* Cache-line alignment */
struct my_data {
atomic_t counter;
char padding[60]; /* 캐시라인 경계 정렬 */
} ____cacheline_aligned;
perf stat -d로 L1/LLC 캐시 미스율을 확인하세요. 캐시 미스가 많으면 자료구조의 캐시라인 정렬과 메모리 접근 패턴 최적화가 필요합니다.
BPF 기반 프로파일링
| 도구 (bcc/bpftrace) | 용도 |
|---|---|
funclatency | 커널 함수 실행 시간 히스토그램 |
biolatency | 블록 I/O 지연 시간 분포 |
runqlat | 런큐 지연 시간 (스케줄링 대기) |
cachestat | 페이지 캐시 히트/미스율 |
tcpretrans | TCP 재전송 추적 |
hardirqs/softirqs | 인터럽트 처리 시간 |
# bpftrace: 함수별 실행 시간 히스토그램
bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/ {
@us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}'
# 블록 I/O 지연 시간 분석
biolatency-bpfcc -mD 10 # 밀리초 단위, 디스크별, 10초
잠금 경쟁 분석 (lockstat)
# lockstat 활성화 (CONFIG_LOCK_STAT 필요)
echo 1 > /proc/sys/kernel/lock_stat
# 워크로드 실행
cat /proc/lock_stat | head -40
# perf lock으로 분석
perf lock record -- sleep 10
perf lock report
# contention 시간이 긴 잠금을 우선 최적화
# lock contention 추적 (BPF)
bpftrace -e 'tracepoint:lock:contention_begin {
@[kstack] = count();
}'
메모리 프로파일링
# Slab 사용량 분석
slabtop -o -s c # 캐시 크기순 정렬
# 페이지 할당 추적
echo 1 > /sys/kernel/tracing/events/kmem/mm_page_alloc/enable
cat /sys/kernel/tracing/trace_pipe
# NUMA 메모리 배치 확인
numastat -p $(pidof myapp)
numactl --hardware
# 주요 메모리 튜닝 파라미터
# vm.min_free_kbytes - 비상 메모리 예약 (OOM 방지)
# vm.zone_reclaim_mode - NUMA 존 회수 정책
# vm.vfs_cache_pressure - dentry/inode 캐시 회수 압력
스케줄러 튜닝
| 파라미터 | 기본값 | 설명 |
|---|---|---|
sched_latency_ns | 6ms (6000000) | CFS 스케줄링 주기 |
sched_min_granularity_ns | 0.75ms | 태스크 최소 실행 시간 |
sched_wakeup_granularity_ns | 1ms | 선점 결정 임계값 |
sched_migration_cost_ns | 0.5ms | CPU 마이그레이션 비용 추정 |
sched_nr_migrate | 32 | 로드밸런싱 시 이동할 최대 태스크 |
# 실시간 워크로드 최적화
chrt -f 80 ./realtime_app # SCHED_FIFO, 우선순위 80
# CPU 고정 (CPU affinity)
taskset -c 2,3 ./app # CPU 2,3에 고정
# cgroup v2로 CPU 대역폭 제한
echo "100000 1000000" > /sys/fs/cgroup/mygroup/cpu.max # 10%
Linux 6.6+에서는 EEVDF (Earliest Eligible Virtual Deadline First) 스케줄러가 CFS를 대체합니다. sched_latency_ns 등의 기존 파라미터 대신 deadline 기반 공정성을 제공합니다.