수정 이력(1건, 최종 수정 2026년 09월 03일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- 한국어 전면 재작성에 맞춰 본문 표현을 바로잡았습니다. 기술적인 주장은 일본어판과 같습니다.
- 최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22176575)
아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.
Go Komura (2026). 「WPR/WPA 실무 ── 「PC 전체가 느리다」를 시스템 전체에서 조사하는 성능 조사 입문」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/wpr-wpa-system-performance-analysis/
- DOI(등록된 아카이브)
- 10.5281/zenodo.22176575
- DOI(마지막 등록 버전)
- 10.5281/zenodo.22176576
「새 앱을 넣었더니 PC 전체 동작이 무거워졌다고 한다. 그런데 작업 관리자를 보면 CPU에도 메모리에도 여유가 있다」「부팅에 3분이 걸리는 PC가 한 대 있다. 무엇이 잘못됐는지 전혀 모르겠다」── 성능 관련 상담에는 이 형태가 정말 많습니다. 공통점은 특정 프로세스를 들여다봐도 답이 나오지 않는다는 것입니다.
프로세스 단위 도구는 갖춰져 있습니다. 파일이나 레지스트리 접근은 Process Monitor로 볼 수 있고, .NET 앱의 CPU와 GC는 PerfView로 따라갈 수 있습니다. 그러나 「PC 전체가 느리다」「CPU는 한가한데도 느리다」는 증상은, 원인이 어느 프로세스인지도 모르는 지점에서 시작합니다. 앱 A가 느린 이유가 바이러스 백신의 스캔일 수도 있고, 다른 서비스의 대량 디스크 쓰기일 수도 있고, 여러 프로세스에 걸친 락의 연쇄일 수도 있습니다. 필요한 것은 프로세스 안이 아니라, OS 전체를 하나의 시간축으로 기록한 데이터입니다.
그것을 모아 읽는 도구가 Windows Performance Recorder(WPR)와 Windows Performance Analyzer(WPA)입니다. WPR은 ETW(Event Tracing for Windows) 기반으로 OS 전체 움직임을 기록하고, WPA는 그 기록을 그래프와 테이블로 분석합니다. 누가 어느 스택에서 CPU를 썼는지, 스레드가 누구를 기다렸는지, 어느 프로세스가 어느 파일에 디스크 I/O를 냈는지── 작업 관리자보다 한두 단계 아래의 사실이, 시각과 함께 전부 남습니다.
이 글에서는 중소기업 정보시스템 담당자와 Windows 앱 개발자를 대상으로, WPR 수집 실무와 WPA 읽는 법── 특히 「CPU가 높을 때」와 「CPU가 낮은데도 느릴 때」의 조사 차이──를 2026년 8월 시점의 1차 정보를 바탕으로 정리합니다.
1. 먼저 결론
- 「PC 전체가 느리다」류 조사의 본래 선택은, OS 전체 ETW 트레이스를 모아 읽는 WPR/WPA입니다. 프로세스 단위 도구(작업 관리자·Procmon·PerfView)로 특정하지 못하는 문제도, 모든 프로세스와 커널을 하나의 시간축에서 보면 따라갈 수 있습니다.12
- 수집 도구 wpr.exe는 Windows 8.1 이후 OS에 기본 포함됩니다. 추가 설치 없이 쓸 수 있습니다. GUI 버전(WPRUI)과 분석 도구 WPA는 Windows ADK에 들어 있습니다.12
- 기본 절차는 세 줄입니다. 관리자 권한으로
wpr -start GeneralProfile -filemode→ 현상을 재현 →wpr -stop C:\temp\trace.etl. 이것만 기억하면 수집을 시작할 수 있습니다.3 - 현장의 기본은 「고객 환경에서는 wpr.exe로 모으기만 하고, 읽기는 자기 PC의 WPA」라는 분담입니다. 소프트웨어를 넣을 수 없는 서버에서도 수집할 수 있습니다. 패킷 캡처의 「모으는 것은 표준 도구, 읽는 것은 Wireshark」와 같은 발상입니다.1
- WPA 읽기의 시작은 「CPU인가, 대기인가, I/O인가」분류입니다. CPU가 뜨거우면 CPU Usage (Sampled), CPU가 한가한데도 느리면 CPU Usage (Precise)의 대기 분석, 디스크가 의심되면 Disk Usage로, 처음부터 길이 갈립니다.45
- CPU Usage (Sampled)는 약 1밀리초마다의 샘플링으로 「어느 함수가 CPU를 썼는지」를 보여 줍니다. 작업 관리자의 「50%」내역을 프로세스 → 스레드 → 스택 → 함수까지 내려갈 수 있습니다.6
- CPU Usage (Precise)는 컨텍스트 스위치의 완전한 기록이며, 「스레드가 누구를 기다렸는지」를 알 수 있습니다. Waits(대기 시간)·ReadyingProcess(깨운 상대)·ReadyThreadStack(깨운 쪽의 스택)을 따라가는 것이, 이 글이 가장 전하고 싶은 기술입니다.47
- 스택을 읽으려면 심볼 설정이 필요합니다. WPA는 기본적으로 Microsoft 공개 심볼 서버를 참조합니다. 자사 앱의 함수 이름까지 보려면 자사 PDB 경로를 추가합니다.8
- ETL 파일에는 프로세스 이름·파일 경로 등 시스템 내부 정보가 들어갑니다. 수집은 필요 최소로 두고, 사외로 넘길 때의 취급을 정한 뒤에 모으십시오.
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 16건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle
2. 도구의 위치 ── 모으는 쪽이 WPR, 읽는 쪽이 WPA
Windows Performance Toolkit(WPT)은 Windows ADK(Windows Assessment and Deployment Kit)에 포함된 성능 조사 도구 모음이며, 중심은 WPR과 WPA 둘입니다.2 역할은 분명히 나뉩니다.
- WPR(Windows Performance Recorder) = 수집. ETW 프로바이더 묶음을 「프로필」이라는 단위로 모아 기록을 시작·중지하고 ETL 파일을 만듭니다. 명령줄 버전 wpr.exe는 Windows 8.1 이후 OS에 기본 포함되어 추가 설치가 필요 없습니다. GUI 버전(WPRUI.exe)은 ADK에 들어 있습니다.1
- WPA(Windows Performance Analyzer) = 분석. ETL 파일을 열어 그래프와 테이블로 분석합니다. ADK 설치가 필요합니다.2
즉 고객 환경에 둘 것은 아무것도 없습니다. OS 기본 wpr.exe로 모으고, ETL 파일을 가져와 자기 PC의 WPA로 읽습니다── 패킷 캡처에서 「pktmon으로 모으고 Wireshark로 읽는다」와 같은 분담이 성립합니다.
flowchart LR
accTitle: WPR로 모으고 WPA로 읽는 분담
accDescr: 고객 환경에서는 OS 기본 wpr.exe로 기록해 ETL 파일을 만들고, 가져와 자기 PC에 ADK로 넣은 WPA로 분석한다
subgraph customer["고객 환경(추가 설치 불필요)"]
wpr["wpr -start → 현상을 재현 → wpr -stop"] --> etl["ETL 파일"]
end
subgraph office["자기 PC(ADK로 WPA 도입됨)"]
wpa["WPA로 그래프·테이블 분석"]
end
etl -->|"가져온다"| wpa
비슷한 도구와의 쓰임도 먼저 정리해 둡니다.
| Process Monitor | PerfView | WPR + WPA | |
|---|---|---|---|
| 답해 주는 질문 | 어느 프로세스가, 어느 경로에, 무엇을 했고, 어떻게 되었는가 | .NET 앱의 CPU·GC·할당은 어떻게 되어 있는가 | OS 전체에서, 어디에서 시간이 사라졌는가 |
| 범위 | 파일·레지스트리·프로세스 시작의 조작 로그 | 매니지드 코드 중심 | CPU·대기·디스크·파일 I/O·전원 등 시스템 전체 |
| 맞는 증상 | 설정이 읽히지 않음, ACCESS DENIED | 자사 .NET 앱만의 느림·메모리 | PC 전체가 느림, CPU가 한가한데도 느림, 원인 프로세스 불명 |
| 글 | Procmon 실전 가이드 | PerfView 실무 입문 | 이 글 |
Procmon이 「무엇을 했는가」의 조작 로그, PerfView가 「.NET 안에서 무슨 일이 일어났는가」라면, WPA는 「어디에서 시간이 사라졌는가」를 모든 프로세스에 걸쳐 회계 감사하는 도구입니다. 참고로 ETW 자체의 구조와 자사 앱을 ETW에 계측하는 방법은 「Windows 이벤트 로그·ETW 입문」에서 다룹니다. 자사 앱이 ETW 이벤트를 내고 있으면, 트레이스에 자사 앱의 구간도 함께 기록되어 대조가 한결 쉬워집니다. 다만 WPR은 선택한 기록 프로필로 켠 프로바이더의 이벤트만 기록합니다. GeneralProfile에는 자사 프로바이더가 들어 있지 않으므로, 섞으려면 자사 프로바이더를 켜는 커스텀 기록 프로필(.wprp)을 준비하고 wpr -start GeneralProfile -start MyApp.wprp!MyAppProfile처럼 .wprp 파일 안의 프로필 이름을 !로 지정해 함께 씁니다3.
3. 수집 실무(WPR) ── start, 재현, stop
관리자 권한 터미널에서의 기본 절차입니다.
:: 사용할 수 있는 내장 프로필 목록
wpr -profiles
:: 1. 수집 시작(범용 프로필, 파일 모드)
wpr -start GeneralProfile -filemode
:: 2. 현상을 재현한다(수집 중 상태 확인은 wpr -status)
:: 3. 중지하고 저장한다(문제 설명을 붙일 수 있다).
:: 저장 폴더는 미리 만든다(없으면 -stop이 저장에 실패한다)
mkdir C:\temp 2>nul
wpr -stop C:\temp\slow-pc.etl "앱 X 시작 중에 PC 전체가 느려지는 현상을 재현"
:: 도중에 그만둘 때는 저장하지 않고 폐기
wpr -cancel
-start에 지정하는 것이 프로필이며, 그 조사에 필요한 ETW 프로바이더의 묶음입니다.3 자주 쓰는 것만 기억하면 충분합니다.9
| 프로필 | 기록하는 내용 | 쓸 때 |
|---|---|---|
GeneralProfile |
CPU 샘플·컨텍스트 스위치·디스크 I/O 등 범용 세트 | 일단 이것. 무엇이 문제인지 모를 단계의 첫 수 |
CPU |
CPU 사용의 상세 | CPU가 뜨거운 것이 이미 분명할 때 |
DiskIO |
디스크 I/O 활동 | 디스크가 의심될 때 |
FileIO |
파일 I/O 활동 | 어느 파일 접근인지까지 따라갈 때 |
프로필은 -start를 나란히 써서 여러 개를 동시에 지정할 수 있습니다(예: wpr -start GeneralProfile -start FileIO -filemode).3
flowchart TB
accTitle: WPR 수집 흐름과 모드 고르기
accDescr: 자기 자리에서 재현할 수 있는 현상은 파일 모드로 짧게·확실하게 모으고, 언제 발생할지 모르는 현상은 기본 메모리 모드의 링 버퍼로 기다린다. 부팅이나 로그온 중의 현상은 부트 트레이스를 쓴다. 어느 쪽이든 시작·재현·중지 절차는 같다
q{"현상은 언제 일어나는가"}
q -->|"자기 자리에서 재현할 수 있다"| file["-filemode로 짧게·확실하게 수집"]
q -->|"언제 발생할지 모른다"| mem["메모리 모드(기본·링 버퍼)로 대기(3.1절)"]
q -->|"부팅·로그온 중"| boot["부트 트레이스(8장)"]
file --> s1["wpr -start → 현상 재현·발생 → wpr -stop"]
mem --> s1
3.1. Memory 모드와 File 모드 ── 재현할 수 있는가, 기다릴 것인가
WPR의 기록처에는 모드가 둘 있고, 기본은 Memory 모드(메모리상의 순환 버퍼)입니다. 오래된 이벤트부터 덮어쓰는 링 버퍼이므로, 언제 발생할지 모르는 현상을 계속 켠 채로 기다리다가, 일어나면 멈추는 쓰임에 맞습니다. -filemode를 붙이면 File 모드가 되어, 연속 파일에 모두 기록됩니다. 이쪽은 덮어쓰여 사라지지 않는 대신, 상한은 디스크 여유뿐이고 파일은 한없이 커집니다.10
flowchart LR
accTitle: Memory 모드와 File 모드의 기록 방식
accDescr: Memory 모드는 메모리상의 순환 버퍼에 기록하고, 오래된 이벤트부터 덮어써 최근만 남으므로 대기에 맞다. File 모드는 파일에 모두 남지만 상한은 디스크 여유뿐이며, 짧은 확정 재현에 맞다
ev["ETW 이벤트의 흐름"] --> ring["Memory 모드: 순환 버퍼(오래된 것부터 덮어씀 → 최근만 남음)"]
ev --> filem["File 모드: 파일에 모두 남음(상한은 디스크 여유)"]
ring -.-> use1["언제 발생할지 모르는 현상의 대기에 맞음"]
filem -.-> use2["짧은 시간에 확실히 재현할 수 있는 현상에 맞음"]
쓰임의 기준은 다음과 같습니다.
- 그 자리에서 재현할 수 있다 → File 모드. 재현 직전에 시작, 직후에 중지하고, 수집은 몇 분 이내로 둡니다
- 언제 발생할지 모른다 → Memory 모드(기본)로 대기. 발생하면 바로
wpr -stop - 몇 분의 GeneralProfile만으로도 ETL은 수백 MB~GB급이 될 수 있습니다. 너무 큰 파일은 WPA에서 분석하지 못하는 경우가 있으므로, 「오래 모을수록 좋다」는 역효과입니다1011
GUI로 모을 때는 WPRUI를 시작해 프로필과 Logging mode를 고르고 Start/Save하면 됩니다. 절차의 상세는 공식 How-to에 정리되어 있습니다.11 고객 측 담당자에게 수집을 부탁할 때도, 위의 세 명령을 그대로 절차서에 넣을 수 있습니다.
4. WPA 읽기의 기본 ── 그래프, 테이블의 황금률, 시간 좁히기
모은 ETL을 WPA에서 열면, 왼쪽 Graph Explorer에 System Activity·Computation·Storage·Memory 등의 범주로 그래프 썸네일이 늘어섭니다.12 보고 싶은 그래프를 오른쪽 Analysis 탭으로 끌면, 위에 그래프, 아래에 테이블이 표시됩니다. 먼저 잡을 것은 세 가지뿐입니다.
- 테이블의 황금률 ── 열 순서가 그룹화를 정한다. WPA 테이블에는 금색과 파란색 세로 막대가 둘 있고, 금색 막대보다 왼쪽 열의 순서로 데이터가 계층화(그룹화)되며, 파란색 막대보다 오른쪽 열이 집계값이 됩니다.13 「Process → Stack」순으로 두면 프로세스별 스택 집계, 「Stack → Process」순이면 같은 스택을 쓰는 모든 프로세스의 집계가 됩니다. 열을 끌어 순서를 바꾸는 것 자체가 분석 조작입니다. 이 한 점을 이해하면 WPA의 모든 테이블이 같은 읽기가 됩니다.
flowchart LR
accTitle: 테이블의 황금률 ── 두 막대와 열의 역할
accDescr: 금색 막대보다 왼쪽 열의 순서로 데이터가 계층화되고, 금색과 파란색 막대 사이가 표시 열, 파란색 막대보다 오른쪽이 집계값이 된다. 열을 끌어 순서를 바꾸는 것 자체가 분석 조작이 된다
left["금색 막대보다 왼쪽: 그룹화 열(순서 = 계층)"] --> gold["금색 막대"]
gold --> mid["막대 사이: 표시 열"]
mid --> blue["파란색 막대"]
blue --> right["파란색 막대보다 오른쪽: 집계값(Sum·% 등)"]
left -.-> op["열 드래그 = 분석 조작(Process→Stack이면 프로세스별 스택 집계)"]
- 시간 범위를 좁힌다. 그래프 위에서 끌어 범위를 고르고, 오른쪽 클릭의 「Zoom」으로 그 구간만의 집계로 바뀝니다. 성능 조사는 항상 「현상이 일어나고 있던 구간」만 보는 것이 원칙입니다(9장).
- 심볼을 설정한다. 스택을 함수 이름으로 읽으려면 메뉴의 Trace > Load Symbols를 실행합니다.14 기본적으로 Microsoft 공개 심볼 서버(msdl.microsoft.com)를 참조하므로, Windows 본체의 스택은 인터넷에 연결되어 있으면 해석할 수 있습니다. 자사 앱의 함수 이름까지 보려면 Trace > Configure Symbol Paths에서 자사 앱 PDB 폴더를 추가합니다.8 PDB가 무엇이고, 왜 릴리스 빌드에서도 반드시 보관해야 하는지는 「PDB(프로그램 데이터베이스)란 무엇인가」에 정리했습니다. 참고로 .NET Framework의 NGen 네이티브 이미지에 대해서는, WPR이 수집 시 NGen용 PDB(.ngenpdb)를 만들어 트레이스 옆 폴더에 두고 WPA가 자동으로 참조합니다.8 이것은 NGen 이미지 전용 메커니즘이며, JIT로 동작하는 일반 .NET 앱의 자체 코드는 대상이 아닙니다. JIT 코드의 주소와 함수 이름 대응은 CLR이 내는 JIT 이벤트에서 해석되므로, .NET 앱을 조사할 때는 CLR 프로바이더(Microsoft-Windows-DotNETRuntime과 그 Rundown)를 켜는 기록 프로필(.wprp)을 준비하고, 3장의 자사 프로바이더와 같은 요령으로
wpr -start GeneralProfile -start MyDotNet.wprp!프로필명형태로 함께 써서 CLR 이벤트를 트레이스에 넣어 둡니다(자기 PC의 WPR이 쓸 수 있는 내장 프로필은wpr -profiles로 확인할 수 있습니다). 그 위에, 소스 줄과의 대응을 위해 빌드에서 나온 PDB를 보관하고 위의 심볼 경로에 추가하십시오.
flowchart TB
accTitle: 스택을 함수 이름으로 읽기 위한 심볼 해석
accDescr: Trace Load Symbols를 실행하면, Windows 본체는 Microsoft 공개 심볼 서버에서, 자사 앱은 심볼 경로에 추가한 빌드 PDB에서 해석된다. NGen 이미지는 WPR이 만드는 NGen용 PDB, JIT .NET 코드는 트레이스 안의 CLR JIT 이벤트와 빌드 PDB가 해석의 근원이 된다
load["Trace > Load Symbols"] --> ms["Windows 본체: 공개 심볼 서버(msdl)"]
load --> own["자사 앱: Configure Symbol Paths에 추가한 빌드 PDB"]
load --> ngen[".NET Framework의 NGen 이미지: WPR이 만든 .ngenpdb"]
load --> jit["JIT .NET 코드: 트레이스 안의 CLR JIT 이벤트 + 빌드 PDB"]
준비가 되면 다음 분기에서 들어갑니다. 그 구간, CPU는 높았는가, 낮았는가. 높으면 5장(Sampled), 낮은데도 느리면 6장(Precise)으로 갑니다.
flowchart TB
accTitle: 증상에서 WPA 그래프를 고르는 분기
accDescr: 현상 구간으로 줌하고, CPU가 높으면 CPU Usage Sampled로, 낮은데도 느리면 코어 고정을 확인한 뒤 CPU Usage Precise의 대기 분석으로, 디스크가 의심되면 Disk Usage와 File IO로 진행한다
zoom["현상 구간으로 줌"] --> cpu{"그 구간의 CPU는?"}
cpu -->|"높다"| sampled["5장: CPU Usage (Sampled)로 「누가 어느 함수에서 태우고 있는가」"]
cpu -->|"낮은데도 느리다"| core{"1코어·1스레드 고정은?"}
core -->|"있다"| sampled
core -->|"없다"| precise["6장: CPU Usage (Precise)로 「무엇을 기다렸는가」"]
cpu -->|"디스크가 의심된다"| disk["7장: Disk Usage / File I/O로 원인을 특정"]
5. CPU가 높을 때 ── CPU Usage (Sampled)로 「누가 어느 함수에서 태우고 있는가」
CPU가 붙어 있으면 보는 것은 CPU Usage (Sampled)입니다. 이것은 약 1밀리초마다 모든 CPU에서 「지금 어느 프로세스의 어느 스택이 실행 중인가」를 기록한 샘플링 데이터이며, 샘플 수 비율이 곧 CPU 시간의 내역이 됩니다.6
flowchart LR
accTitle: CPU Usage Sampled의 구조
accDescr: 약 1밀리초마다 모든 CPU에서 실행 중인 스택을 기록하고, 샘플을 집계한 비율이 CPU 시간의 내역이 된다. 프로세스에서 스레드, 스택, 함수로 내려가 읽는다. 샘플 사이에 끝나는 짧은 활동은 나타나지 않는다
tick["약 1ms마다의 인터럽트"] --> snap["모든 CPU에서 「지금 실행 중인 스택」을 기록"]
snap --> agg["샘플을 집계(비율 = CPU 시간의 내역)"]
agg --> drill["Process → Thread → Stack → 함수로 내려간다"]
snap -.-> miss["샘플 사이에 끝나는 짧은 활동은 나타나지 않는다"]
- Graph Explorer의 Computation에서 CPU Usage (Sampled)를 Analysis 탭에 두고, 프리셋 Utilization by Process, Stack을 고릅니다.5
- Weight(또는 Count)가 큰 순으로 프로세스를 봅니다. 작업 관리자에서 「50%」였던 것의 정체가, 먼저 프로세스 단위로 드러납니다.
- 원인 프로세스의 Stack 열을 펼쳐 갑니다. 스택은 트리로 집계되어 있으며, 분기에서 숫자가 크게 줄지 않는 길을 내려가면 CPU를 태우고 있는 함수에 도착합니다. 심볼이 해석되어 있으면 자사 코드의 어느 함수인지까지 일직선입니다.
- 트리 펼치기가 번거로우면 그래프 표시를 Flame(플레임 그래프)으로 바꿉니다. 가로 폭 = CPU 시간 비율로 그려지므로, 어느 호출 경로가 지배적인지 한눈에 보입니다. CPU Usage (Sampled)에는 Flame by Process, Stack 프리셋도 준비되어 있습니다.13
주의가 하나 있습니다. 샘플링인 이상, 샘플 사이에 끝나는 짧은 활동은 나타나지 않습니다.6 「합쳐서 어디에서 CPU가 쓰였는가」를 보는 도구이지, 한 번마다의 정확한 실행 시간을 재는 도구가 아니라고 기억해 두십시오.
6. CPU가 낮은데도 느릴 때 ── CPU Usage (Precise)와 대기 분석
이 글의 핵심은 여기입니다. 다만 대기 분석으로 가기 전에 확인할 것이 하나 있습니다. 「전체 CPU 사용률이 낮다」는 「CPU가 병목이 아니다」를 뜻하지 않습니다. 16코어 PC에서는, 1코어에 붙은 직렬 처리(UI 스레드 하나가 전력을 다해 도는 상태)도 전체로는 약 6%밖에 보이지 않기 때문입니다. 먼저 5장의 Sampled(또는 CPU Usage (Precise)의 Utilization by CPU)로 특정 코어·스레드 고정이 없는지 확인하고, 그것도 없으면 이 장으로 옵니다 ── 처리는 움직이지 못하는 것이 아니라 기다리고 있는 것입니다. 무엇을 기다리는지 알려 주는 것이 CPU Usage (Precise)입니다.
Sampled가 샘플링인 데 비해, Precise는 컨텍스트 스위치(스레드 전환)의 완전한 기록입니다. 스레드가 대기에 들어가고, 누군가에게 깨어나고(Ready), CPU에 올라가는── 이 왕복이 한 행씩 남아 있으며, 다음 열을 읽을 수 있습니다.74
| 열 | 의미 |
|---|---|
| NewThreadStack | 그 스레드가 어느 스택에서 대기에 들어갔는지(= 무엇을 하다가 멈췄는지) |
| Waits (us) | 기다리고 있던 시간 |
| Ready (us) | 깨어난 뒤 CPU에 올라갈 때까지 기다리게 된 시간(CPU 경합) |
| ReadyingProcess / ReadyingThreadId | 그 스레드를 깨운(대기를 푼) 프로세스와 스레드 |
| ReadyThreadStack | 깨운 쪽이 어느 스택에서 깨웠는지 |
flowchart LR
accTitle: 대기 한 왕복과 각 열의 대응
accDescr: 스레드는 NewThreadStack에 남는 스택에서 대기에 들어가, Waits 시간만큼 기다린다. 누군가가 깨우면 ReadyingProcess와 ReadyThreadStack에 그 상대가 남고, Ready 시간만큼 CPU 경합을 기다린 뒤 다시 실행된다
run1["실행 중"] -->|"대기에 들어간다(NewThreadStack에 남는다)"| waitst["대기(Waits (us))"]
waitst -->|"누군가가 깨운다(ReadyingProcess / ReadyThreadStack)"| ready["Ready(CPU 경합 대기)"]
ready -->|"CPU에 올라간다"| run2["다시 실행"]
읽는 패턴은 이렇습니다.4
- 프리셋 Utilization by Process, Thread를 적용하고, 열에 NewThreadStack·ReadyThreadStack을 추가합니다.
- 먼저 지연된 조작을 실행하고 있던 스레드(UI 스레드, 해당 요청의 처리 스레드)를 특정합니다. Waits 합계가 큰 순으로만 보면, 메시지 펌프나 타이머처럼 「의도적으로 계속 기다리고 있을」 뿐인 스레드가 상위를 차지해 헷갈리기 때문입니다. 대상 스레드를 찾으면, 그 CPU Usage (ms)가 크면 5장의 CPU 문제, Waits가 지배적이면 대기 문제입니다.
- NewThreadStack을 펼쳐 무엇을 하다가 멈췄는지를 봅니다.
WaitForSingleObject나EnterCriticalSection이면 락 대기,ReadFile등 동기 I/O 안이면 I/O 대기, 소켓 수신 안이면 상대의 응답 대기입니다. - 다음으로 누가 대기를 풀었는지를 봅니다. ReadyThreadStack을 펼치고 ReadyingProcess / ReadyingThreadId를 확인합니다. 커널의
KiTimerExpiration에서 깨어났으면 타이머(= 타임아웃까지 잠들어 있던 것), I/O 완료 처리에서 깨어났으면 I/O 대기였음이 뒷받침됩니다.4 - 깨운 상대가 다른 스레드나 다른 프로세스이면, 이번에는 그 스레드를 같은 절차로 조사합니다. 「A는 B의 락 해제를 기다리고, B는 C의 RPC 응답을 기다리고, C는 디스크 I/O를 기다리고 있었다」── 이 사슬을 뿌리까지 따라간 것이 지연의 크리티컬 패스입니다.7
flowchart LR
accTitle: 대기 분석에서 따라가는 크리티컬 패스의 사슬
accDescr: 지연된 스레드 A의 NewThreadStack에서 무엇을 하다가 멈췄는지를 보고, ReadyThreadStack과 ReadyingProcess로 깨운 상대 B를 특정한 뒤, B도 같은 절차로 조사해 뿌리의 디스크 I/O까지 따라간다
a["스레드 A(지연된 조작)"] -->|"NewThreadStack: 락 대기로 정지"| b["스레드 B(락 보유 중)"]
b -->|"NewThreadStack: RPC 응답 대기"| c["프로세스 C"]
c -->|"NewThreadStack: 동기 I/O 대기"| d["디스크 I/O(뿌리)"]
d -.->|"완료가 C를 깨운다"| c
c -.->|"응답이 B를 깨운다"| b
b -.->|"락 해제가 A를 깨운다(ReadyThreadStack에 나타남)"| a
예를 들어 「멀티스레드화했는데 빨라지지 않는다」는 건에서는, 이 절차로 워커 전부가 락 하나에 줄 서 있는 모습이 그대로 보입니다. 락 경합을 설계로 피하는 이야기는 「멀티스레드 실무 베스트 프랙티스 .NET 편」에, 동기 I/O로 기다리는 대신 완료 알림으로 도는 Windows 메커니즘은 「I/O 완료 포트(IOCP)와 .NET 스레드 풀」에 썼습니다. WPA에서 「누구를 기다렸는지」를 집어내고, 이 설계론으로 고치는 것이 한 줄기의 흐름입니다.
7. 디스크와 파일 I/O ── 「누군가가 디스크를 훑고 있다」를 특정하기
「PC 전체가 느리다」의 단골 원인은 CPU가 아니라 디스크입니다. Storage 범주의 Disk Usage와 File I/O로 조사합니다.15
Disk Usage는 디스크 I/O의 기록이며, 중요한 열이 둘 있습니다. Disk Service Time은 디스크 장치가 그 I/O 처리에 실제로 걸린 시간, IO Time은 I/O가 OS 큐에 들어간 뒤 완료될 때까지의 시간입니다. IO Time은 대기열만큼 반드시 Service Time 이상이 되므로, IO Time이 Service Time보다 훨씬 길면 그 I/O는 「대기열에서 기다리고 있던」 것입니다.6 다만 이것만으로는, 줄을 만든 원인이 다른 프로세스인지, 느린 장치에 자기 자신의 대량 I/O가 늘어선 것인지는 정해지지 않습니다. 결론은 여기서 내지 않고, Service Time(장치 자체의 응답)과 다음의 프로세스·경로·스택별 내역으로 확정합니다.
이어서 Utilization by Process, Path Name, Stack 프리셋으로, 어느 프로세스가·어느 파일에·어느 스택에서 I/O를 냈는지를 IO Time이나 Size가 큰 순으로 봅니다.15 현장에서 자주 나오는 답은 이 둘입니다.
- 바이러스 백신이 모든 파일을 훑고 있었다. 앱 시작이 느린 시간대에, 백신 프로세스가 대량 읽기를 내고 있는 형태로 보입니다. 제외 설정 논의 재료로, 프로세스 이름·경로·양의 증거가 그대로 갖춰집니다.
- 다른 프로세스가 대량 쓰기를 하고 있었다. 백업, 인덱서, 로그를 너무 많이 씀 등. 쓰기가 언제 디스크에 도착하는지는 캐시 관리자가 관여하므로, 「쓴 순간」과 「디스크가 바쁜 순간」이 어긋날 수 있다는 점까지 「캐시 관리자 ── WriteFile은 언제 디스크에 도착하는가」에서 설명합니다.
File I/O는 한 층 위, 즉 앱이 낸 파일 조작(Create/Read/Write 등)의 기록이며, Duration by Process, Thread, Type 등의 프리셋으로 파일 이름 단위·조작 단위 시간을 집계할 수 있습니다.15 디스크에 도착하기 전에 파일 시스템이나 필터 드라이버에서 시간을 쓰는 경우는 Disk Usage에 나오지 않으므로, 「Disk Usage는 평온한데 File I/O는 느리다」는 어긋남 자체가 단서가 됩니다. 동기 I/O와 비동기 I/O의 구조부터 알고 싶은 분은 「동기 I/O와 비동기 I/O ── OVERLAPPED의 진짜 의미」를 보십시오.
flowchart TB
accTitle: File IO와 Disk Usage가 보는 층의 차이
accDescr: 앱의 파일 조작은 파일 시스템과 필터 드라이버를 거쳐 OS의 IO 큐에서 디스크 장치로 도착한다. File IO는 위 층의 조작을, Disk Usage는 디스크에 도착한 IO를 기록하고, IO Time과 Disk Service Time의 차이가 대기열 시간을 나타낸다
app["앱: ReadFile / WriteFile"] --> fio["파일 시스템·필터 드라이버(File I/O가 보는 층)"]
fio --> queue["OS의 I/O 큐"]
queue --> dev["디스크 장치(Disk Usage가 보는 층)"]
fio -.-> n1["여기서 시간을 쓰면 Disk Usage에는 나오지 않는다"]
queue -.-> n2["IO Time − Disk Service Time = 대기열 시간"]
dev -.-> n3["Disk Service Time = 장치의 처리 시간"]
참고로 「메모리가 부족해 스왑하고 있는 것은 아닌가」라는 줄기는, WPA로 가기 전에 작업 관리자와 리소스 모니터로 1차 원인 분리를 할 수 있습니다. 다만 커밋된 메모리만 보고 부정하지 마십시오 ── 커밋에 여유가 있어도, 물리 메모리 압박으로 워킹 세트가 깎여 하드 폴트가 이어지는 상황은 있을 수 있습니다. 사용 가능한 물리 메모리와 리소스 모니터의 「하드 폴트/초」도 함께 확인합니다. 읽는 법은 「Windows의 「메모리 사용량」은 무엇을 나타내는가」를 참조하십시오.
8. 부팅·로그온이 느리다 ── 부트 트레이스의 입구
「부팅에 3분이 걸린다」유형은 손으로 wpr -start하기 전에 문제가 끝나 버립니다. WPR에는 부트 트레이스가 있어, 다음 시작 때 OS가 자동으로 기록을 시작하도록 심어 둘 수 있습니다.3
:: 1. 다음 시작 때의 자동 기록을 심는다
wpr -boottrace -addboot GeneralProfile -filemode
:: 2. 다시 시작한다(부팅이 느린 현상을 재현)
:: 3. 시작한 뒤, 기록을 멈추고 저장한다(심어 둔 것도 해제된다)
mkdir C:\temp 2>nul
wpr -boottrace -stopboot C:\temp\boot.etl "부팅에 3분이 걸리는 현상"
flowchart LR
accTitle: 부트 트레이스의 흐름
accDescr: addboot로 다음 시작 때의 자동 기록을 심은 뒤 다시 시작하면, 시작 때 OS가 자동으로 기록을 시작한다. 로그온 뒤에 stopboot로 저장하면 심어 둔 것도 해제된다. 그만둘 때는 cancelboot로 해제한다
add["wpr -boottrace -addboot 로 심는다"] --> rebootpc["다시 시작(부팅이 느린 현상을 재현)"]
rebootpc --> auto["시작 때 OS가 자동으로 기록 시작"]
auto --> stop2["로그온 뒤에 -stopboot 로 저장(심어 둔 것도 해제)"]
add -.-> cancel["그만두려면 -cancelboot"]
예전에 xbootmgr이 맡던 시작·종료 측정은, 지금의 WPR에서는 -onoffscenario Boot 같은 옵션으로도 실행할 수 있습니다.3 모은 트레이스는 앞 장과 같은 도구로 읽습니다. Processes 그래프에서 어느 프로세스가 언제 생겼는지를 시계열로 보고, 부팅이 막힌 시간대로 줌한 뒤 CPU인지·대기인지·디스크인지를 분류합니다── 시작 앱이 직렬로 무언가를 기다리고 있다, 서비스 시작이 특정 I/O에서 멈춰 있다, 같은 형태가 보입니다. 부트 분석은 그 자체로 깊은 전문 영역이므로, 이 글에서는 「손으로 맞추지 못하는 현상도 WPR이면 모을 수 있다」는 입구까지입니다. 먼저 GeneralProfile 부트 트레이스로 전체 그림을 잡는 것부터 시작하십시오.
9. 실무 패턴 ── 분류→줌→스택의 반복
도구가 정리되었으니, 조사 전체의 패턴을 정리합니다.
- 현상의 시각을 확정한다. 「느렸다」가 아니라 「10:23:40〜10:24:10이 느렸다」까지 굳힙니다. 앱 로그, 이벤트 로그, 조작한 사람의 메모, 무엇이든 됩니다. 자사 앱이 ETW나 이벤트 로그에 구간을 쓰고 있으면, 트레이스 안의 이벤트가 그대로 시각의 말뚝이 됩니다.
- 그 구간만으로 줌한다. 트레이스 전체의 집계는 평균으로 평탄화되어, 정작 중요한 이상이 옅어집니다. WPA 분석은 항상 「이상이던 구간」대 「정상이던 구간」의 비교입니다.
- 「CPU인가, 대기인가, I/O인가」를 먼저 분류한다. CPU Usage (Sampled)를 보고 뜨거우면 5장으로. 뜨겁지 않으면 CPU Usage (Precise)의 Waits로(6장). Disk Usage의 IO Time이 부풀어 있으면 7장으로. 이 세 갈래를 먼저 지나면 길을 잃지 않습니다.
- 가설→줌→스택을 반복한다. 「바이러스 백신인가?」라고 생각하면 그 프로세스로 좁혀 스택으로 뒷받침합니다. 아니면 다음 가설로. 스택까지 내려가 뒷받침하기 전에 결론을 내지 않는 것이, 이런 조사의 규율입니다.
flowchart LR
accTitle: 성능 조사의 반복 루프
accDescr: 현상의 시각을 확정하고 구간으로 줌한 뒤, CPU인가 대기인가 IO인가를 분류하고, 가설을 세워 좁히고, 스택으로 뒷받침한다. 뒷받침되면 원인 확정, 아니면 다음 가설로 반복한다
time["현상의 시각을 확정"] --> zoomstep["그 구간으로 줌"]
zoomstep --> triage["CPU인지·대기인지·I/O인지를 분류"]
triage --> hypo["가설을 세워 좁힌다"]
hypo --> stack["스택으로 뒷받침한다"]
stack -->|"뒷받침되었다"| fix["원인 확정 → 대책으로"]
stack -->|"아니었다"| hypo
마지막으로 수집 파일의 취급입니다. ETL 파일에는 모든 프로세스의 이름, 연 파일의 경로, 로드된 모듈, (프로필에 따라서는) 레지스트리 키 이름 등, 시스템의 내부가 넓게 담깁니다. GeneralProfile의 표준 수집에는 통신 내용 같은 데이터 본체는 들어가지 않지만, 커스텀 프로바이더를 켠 경우에는 그 이벤트의 페이로드(앱이 기록한 문자열 등)가 그대로 들어갑니다. 켠 프로바이더가 무엇을 내는가까지 확인한 뒤, 사외에 내보낼 때는 충분히 기밀한 파일로 다루십시오. 패킷 캡처와 같이 필요 최소의 수집·넘기는 상대와의 합의·보관 기한과 삭제를 절차에 넣으십시오.
flowchart LR
accTitle: ETL 파일에 담기는 것과 취급
accDescr: ETL에는 모든 프로세스 이름, 연 파일의 경로, 모듈, 프로필에 따라서는 레지스트리 키 이름이 담기고, 커스텀 프로바이더를 켜면 그 페이로드도 들어간다. 기밀 파일로서 필요 최소의 수집, 넘기는 상대와의 합의, 보관 기한과 삭제를 절차화한다
etl["ETL 파일"] --> a1["모든 프로세스 이름·파일 경로·모듈"]
etl --> a2["(프로필에 따라) 레지스트리 키 이름"]
etl --> a3["커스텀 프로바이더의 페이로드(앱이 기록한 문자열)"]
a1 -.-> rule["기밀로 다룬다: 필요 최소 수집·상대와의 합의·보관 기한과 삭제"]
a2 -.-> rule
a3 -.-> rule
10. 정리
- 작업 관리자로 설명하지 못하는 「PC 전체가 느리다」는 OS 전체 ETW 트레이스── WPR로 모으고, WPA로 읽기──로 조사합니다. wpr.exe는 Windows 8.1 이후 OS 기본 포함이므로, 고객 환경에서 모아 ETL을 가져오고 자기 PC의 WPA로 읽는 분담이 성립합니다.
- 수집은
wpr -start GeneralProfile -filemode→ 재현 →wpr -stop trace.etl의 세 절차. 재현할 수 있으면 File 모드로 몇 분 이내, 기다릴 거면 Memory 모드(링 버퍼). 오래 모을수록 좋은 것은 아닙니다. - WPA는 테이블의 황금률(금색 막대 왼쪽 = 그룹화), 시간 범위 줌, 심볼 설정(자사 앱은 PDB)의 세 점을 잡으면 읽기를 시작할 수 있습니다.
- CPU가 높으면 CPU Usage (Sampled)로 프로세스 → 스택 → 함수로. CPU가 낮은데도 느리면 CPU Usage (Precise)로 NewThreadStack(무엇을 하다가 멈췄는지) → Waits(얼마나 기다렸는지) → ReadyingProcess·ReadyThreadStack(누가 깨웠는지)의 사슬을 뿌리까지 따라갑니다.
- 디스크는 Disk Usage의 IO Time과 Service Time 차이로 「대기열에 있던 시간」을 보고, 그 원인(장치 자체가 느린지, 누가 줄을 만들었는지)은 Service Time과 프로세스·경로·스택별 내역으로 특정합니다. 부팅이 느린 것은
wpr -boottrace로 모을 수 있습니다. - 실무 패턴은 ①시각 확정 ②구간 줌 ③CPU인지 대기인지 I/O인지 분류 ④가설→줌→스택의 반복. ETL은 내부 정보를 담은 기밀로 다룹니다.
WPA는 화면이 위압적이고, 처음 한 시간은 누구나 길을 잃습니다. 그러나 「금색 막대 왼쪽이 그룹화」「Sampled는 태운 곳, Precise는 기다린 상대」라는 두 뼈대만 들어가면, 나머지는 같은 조작의 반복입니다. 다음에 「CPU는 남는데 느립니다」라는 상담이 오면, 작업 관리자를 닫고 트레이스를 모아 보십시오.
관련 글
- PerfView와 dotnet-trace로 「느림」을 특정한다 ── .NET 성능 조사의 실무 입문
- Process Monitor(ProcMon) 실전 가이드 ── 「설정이 읽히지 않는다」「ACCESS DENIED」를 10분에 특정하기
- Windows 이벤트 로그·ETW 입문 ── 업무 앱의 로그를 OS 표준 구조에 올리기
- Windows의 「메모리 사용량」은 무엇을 나타내는가 ── Working Set·Private Bytes·Commit·페이지 파일을 올바르게 읽기
- Windows의 프로세서 스케줄 설정 - 백그라운드 서비스와 P/E 코어
- PDB(프로그램 데이터베이스)란 무엇인가 ── 디버그 정보·심볼·Source Link를 이해하기
관련 상담 영역
합동회사 코무라소프트에서는 「PC 전체가 느려졌는데 원인을 모르겠다」「CPU에 여유가 있는데도 앱이 느리다」「특정 환경만 부팅이 극단적으로 느리다」와 같은 시스템 전체 성능 문제의 조사를 다룹니다. WPR/WPA 수집 설계(어느 환경에서·어느 프로필을·얼마나 모을지)부터 트레이스 분석, 원인이 된 앱 측·설정 측 수정까지를 한 줄기로 대응합니다.
참고 링크
-
Microsoft Learn, Introduction to WPR. WPR이 ETW 기반 성능 기록 도구라는 점, 명령줄 버전 WPR.exe가 Windows 8.1 이후 OS에 포함되어 추가 설치가 필요 없다는 점, GUI 버전 WPRUI.exe와의 관계, 기록 프로필의 생각에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Windows Performance Analyzer. WPA가 Windows ADK에 포함되며, WPR·Xperf 등이 기록한 ETW 이벤트에서 그래프와 데이터 테이블을 만드는 분석 도구이고, 임의의 ETL 파일을 열어 분석할 수 있다는 점에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, WPR Command-Line Options. wpr -start/-stop/-cancel/-status/-profiles의 구문, -filemode(기본은 메모리 모드), 여러 프로필의 동시 지정, -boottrace에 의한 부트 트레이스(addboot/stopboot/cancelboot), -onoffscenario에 의한 Boot 등 On/Off 전이 기록에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, CPU Analysis. CPU Usage (Precise) 그래프의 열(NewThreadStack·ReadyThreadStack·ReadyingProcess·Waits 등)의 정의와, ReadyThreadStack을 펼쳐 ReadyingProcess/ReadyingThread를 따라가 대기의 근본 원인에 도달하는 절차, KiTimerExpiration(타이머 대기)이나 I/O 완료에 의한 깨어남의 구별법에 대해. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Troubleshoot processes and threads by using WPR and WPA. CPU 사용이 높을 때 CPU Usage (Sampled)를 Process→Stack으로 읽는 구성, 대기 분석(Wait analysis)에서 CPU Usage (Precise)의 Readying Process·Readying Thread·Readying Stack과 Wait 열을 쓰는 구성 등, 증상별 프로필과 그래프의 대응표에 대해. ↩ ↩2
-
Microsoft Learn, Exercise 2 - Evaluate Fast Startup Using Windows Performance Toolkit. CPU Usage (Sampled)가 약 1밀리초 간격의 샘플링이며 샘플 사이의 짧은 활동은 기록되지 않는다는 점, 프로세스 → 스레드 → 스택으로 내려가 CPU 소비 내역을 특정하는 절차, Disk Usage의 IO Time(큐 시간 포함)과 Disk Service Time(디스크 처리 시간)의 의미에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Exercise 3 - Understand Critical Path and Wait Analysis. 크리티컬 패스 분석의 생각(Running·Ready·Waiting 분류), CPU Usage (Precise) 테이블의 NewThreadStack·ReadyThreadStack·ReadyingProcess·Waits·Ready 등 열의 의미, 깨운 쪽 스레드를 차례로 따라가 지연의 연쇄를 푸는 절차에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Loading Symbols. _NT_SYMBOL_PATH가 설정되지 않았을 때 WPA가 Microsoft 공개 심볼 서버(msdl.microsoft.com)를 기본적으로 참조한다는 점, 자사 구성 요소 PDB 경로 추가, WPR이 .NET 매니지드 심볼용 PDB를 트레이스 옆 .ngenpdb 폴더에 만들고 WPA가 자동 참조한다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Built-in Recording Profiles. WPR에 내장된 기록 프로필 목록(CPU usage, Disk I/O activity, File I/O activity, Registry I/O activity, Networking I/O activity 외)과 각 프로필이 기록하는 내용에 대해. ↩
-
Microsoft Learn, Logging Mode. 기록 모드에 File(연속 파일)과 Memory(메모리상의 순환 버퍼)가 있고 기본이 Memory라는 점, Memory는 언제 발생할지 모르는 현상에 맞으며 오래된 이벤트가 덮어쓰인다는 점, File은 디스크 여유가 유일한 상한이며 너무 큰 파일은 WPA에서 분석하지 못하는 경우가 있다는 점에 대해. ↩ ↩2
-
Microsoft Learn, WPR How-to Topics. WPRUI에서 기록을 시작·중지하는 절차, 프로필·상세 수준·Logging mode 선택, 장시간 기록에서는 파일이 거대해져 WPA에서 분석하지 못할 수 있으므로 Memory 모드를 고르라는 주의에 대해. ↩ ↩2
-
Microsoft Learn, Graph Explorer. Graph Explorer 창에 System Activity·Computation·Storage·Memory 등의 범주로 그래프 썸네일이 늘어선다는 점, 그래프를 Analysis 탭으로 끌어 표와 함께 표시한다는 점에 대해. ↩
-
Microsoft Learn, Graphs (WPA Features). WPA의 Flame(플레임 그래프) 표시, 금색 막대 왼쪽 열이 그룹화·파란색 막대 오른쪽이 집계값이라는 테이블 구성, CPU Usage (Sampled)의 Flame by Process, Stack 프리셋에 대해. ↩ ↩2
-
Microsoft Learn, Load Symbols or Configure Symbol Paths. WPA의 Trace 메뉴에서 Load Symbols로 심볼을 읽는다는 점, Configure Symbol Paths 대화 상자에서 심볼 경로를 설정·변경하는 절차에 대해. ↩
-
Microsoft Learn, List of WPA Graphs. WPA에서 쓸 수 있는 그래프 목록. Disk Usage의 IO Time by Process, IO Type·Service Time by Process, Path Name, Stack·Utilization by Process, Path Name, Stack, File I/O의 Duration by Process, Thread, Type 등 프리셋에 대해. ↩ ↩2 ↩3
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
PerfView와 dotnet-trace로 「느림」을 특정한다 ── .NET 성능 조사의 실무 입문
업무 앱이 「느리다」「CPU가 붙어 있다」일 때, 어떤 도구로 무엇을 볼지. PerfView와 dotnet-trace의 역할 분담, CPU 샘플링 읽는 법, ThreadTime으로 블록 시간을 조사하는 절차까지 실무 조사 흐름을 정리합니다.
절전에서 재개하면 깨지는 앱 ── 전원 이벤트의 구조와 재개에 강한 업무 앱을 만드는 방법
노트북을 열었더니 업무 앱의 통신이 끊어져 있었다――원인은 절전을 전제하지 않은 설계입니다. WM_POWERBROADCAST에 의한 알림의 흐름, Modern Standby의 동작, 끊김·재연결 설계, 절전 억제와 조사 명령까지를 1차 정보로 설...
「응답 없음」의 정체 ── Windows가 앱을 「멈췄다」고 판단하는 구조와, 멈추지 않는 설계
Windows의 「응답 없음」은 창이 5초 동안 메시지를 꺼내지 않으면 OS가 판단해 고스트 창으로 교체하는 구조입니다. 판단의 내부 동작부터 멈추는 전형적인 원인, UI 스레드에서 무거운 처리를 빼내는 설계, hang 조사 절차까지 설명합니다.
Windows 오류 코드 읽기 ── Win32·HRESULT·NTSTATUS 삼층 구조
0x80004005가 나오면 검색하기 전에 먼저 분해합니다. Win32 오류·HRESULT·NTSTATUS의 삼층 구조, 0x8007xxxx가 Win32 오류를 감싼 형태라는 가장 중요한 패턴, err.exe와 PowerShell로 코드를 찾는 ...
Windows의 「메모리 사용량」은 무엇을 나타내는가 ── Working Set·Private Bytes·Commit·페이지 파일을 올바르게 읽는 법
작업 관리자의 메모리, Working Set, Private Bytes, Commit은 같은 값이 아닙니다. Windows의 가상 메모리와 물리 메모리의 관계, 페이지 파일의 역할, 메모리 부족이나 누수 조사에서 봐야 할 지표를 설명합니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
장애 조사 & 장기 가동 장애
간헐적 장애, 통신 진단, 장기 가동 크래시, 실패 경로 테스트 기반을 정리한 토픽 페이지입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
장애 조사 & 원인 분석
간헐적 장애, 장기 가동 중 크래시, 누수, 통신 중단 등 까다로운 프로덕션 이슈를 조사합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- WPR과 WPA는 어디에서 구하나요? 설치할 수 없는 고객 환경에서도 쓸 수 있나요?
- 수집 도구 wpr.exe(명령줄 버전)는 Windows 8.1 이후 OS에 기본 포함되어 추가 설치 없이 씁니다. GUI 버전 WPRUI와 분석 도구 WPA(Windows Performance Analyzer)는 Windows ADK(Windows Assessment and Deployment Kit)에 들어 있어 별도 설치가 필요합니다. 실무에서는 「고객 환경에서는 OS 기본 wpr.exe만으로 ETL을 모으고, 가져와 자기 PC의 WPA로 분석한다」고 나누면, 소프트웨어를 추가할 수 없는 현장에서도 시스템 전체 성능을 조사할 수 있습니다.
- 작업 관리자에서 CPU에 여유가 있는데도 느린 이유는 무엇인가요? WPA에서는 무엇을 알 수 있나요?
- CPU 사용률이 낮은데도 느릴 때는, 처리가 CPU를 못 쓰는 것이 아니라 「무언가를 기다리며」 멈춰 있습니다. 락 경합, 동기 I/O 완료 대기, 다른 프로세스의 응답 대기가 전형입니다. 작업 관리자는 사용률이라는 결과만 보여 주지만, WPA의 CPU Usage (Precise)는 컨텍스트 스위치 단위 기록에서 스레드가 어디에서 대기를 시작했는지(NewThreadStack), 얼마나 기다렸는지(Waits), 누가 깨웠는지(ReadyingProcess·ReadyThreadStack)까지 보여 줍니다. 기다리게 한 쪽을 따라가면 「느림의 원인」을 함수 수준까지 특정할 수 있습니다.
- 트레이스는 얼마나 오래 모아야 하나요? 파일이 커지지 않나요?
- 재현할 수 있으면 재현 직전에 시작하고 직후에 멈춰, 몇 분 이내로 두는 것이 기본입니다. WPR 기본값은 메모리상의 순환 버퍼에 기록하는 Memory 모드이며, 오래된 이벤트부터 덮어쓰므로 언제 발생할지 모르는 현상을 기다릴 때 맞습니다. -filemode를 붙인 File 모드는 연속 파일에 모두 남지만, 상한은 디스크 여유뿐이고 너무 큰 파일은 WPA에서 분석하지 못하게 되는 경우가 있습니다. 장시간 대기는 Memory 모드, 짧은 확정 재현은 File 모드로 나눕니다.
- PerfView와 WPA는 어떻게 나누어 쓰나요?
- 둘 다 ETW 트레이스를 다루지만 잘하는 영역이 다릅니다. PerfView는 .NET 런타임을 깊게 이해하며 GC·할당·JIT 등 매니지드 앱 고유 조사에 강합니다. WPA는 OS 전체의 CPU·디스크·파일 I/O·전원을 그래프와 테이블로 가로질러 읽는 데 맞으며, 「특정 앱이 아니라 PC 전체가 느리다」「여러 프로세스가 얽힌다」「앱 밖(바이러스 백신, 드라이버, 다른 프로세스)이 의심된다」일 때의 본래 선택입니다. 자사 .NET 앱만의 느림은 PerfView, 시스템 전체의 느림은 WPR/WPA가 기준입니다.
- 고객의 프로덕션 환경에서 WPR을 실행해도 되나요?
- 짧은 수집은 실무에서 자주 하지만, 무조건 안전하지는 않습니다. ETW는 가볍다고 해도 스택이 붙은 이벤트를 대량 기록하므로 CPU와 메모리를 일정량 씁니다. 재현 직전에 시작하고 직후에 멈추기, 수집을 몇 분 이내로 두기, 업무 영향이 적은 시간대에 실시하기를 일반 변경 작업과 같은 승인 절차에 올리십시오. ETL에는 프로세스 이름·파일 경로·실행 파일 정보 등 시스템 내부 정보가 들어가므로, 사외로 가져갈 때의 취급(최소화·보관 기한·삭제)도 미리 정해 두어야 합니다.