WPR/WPA на практике: как разбирать «весь ПК тормозит» по всей системе

· Обновлено: · · Windows, Производительность, WPR, WPA, ETW, Расследование производительности, Устранение неполадок, Разработка под Windows

История изменений (первая версия, опубликована 21 Aug 2026)
Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.22176577)

Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.

Го Комура (2026). WPR/WPA на практике: как разбирать «весь ПК тормозит» по всей системе. KomuraSoft LLC. https://comcomponent.com/ru/blog/wpr-wpa-system-performance-analysis/

DOI (зарегистрированный архив)
10.5281/zenodo.22176577
DOI (последняя зарегистрированная версия)
10.5281/zenodo.22176578

«После установки приложения весь ПК стал тормозить, а в Диспетчере задач и по ЦП, и по памяти есть запас.» «Один ПК загружается три минуты.» То, что делает такие консультации трудными, — неизвестно даже, на какой процесс смотреть.

Даже когда тормозит приложение A, причина может быть в сканировании антивируса, в интенсивной записи другой службы или в цепочке блокировок через несколько процессов. Нужно записать работу всей ОС на одной шкале времени и проследить, куда ушло время.

Инструменты для этого — Windows Performance Recorder (WPR) и Windows Performance Analyzer (WPA). WPR снимает запись на базе ETW (Event Tracing for Windows), WPA читает эту запись графиками и таблицами. По шкале времени смотрят, какие процессы и стеки занимали ЦП, чего ждал каждый поток и какой процесс выдал дисковый I/O к какому файлу.

Вопрос, на который отвечает статья: «как записать общесистемную медленность и что из ЦП, времени ожидания и I/O смотреть?» Она рассчитана на сотрудников ИТ малых и средних компаний и разработчиков Windows-приложений и покрывает путь от практики записи до анализа по первичным источникам на август 2026 года. Читайте её с осью «ЦП высокий» против «ЦП низкий, а всё равно медленно».

Чем это отличается от Process Monitor, который смотрит обращения к файлам и реестру, и PerfView, который идёт по ЦП и GC .NET-приложения, разобрано в главе 2.

1. Сначала вывод

Базовый поток — «записать через WPR → сузить до интервала проблемы в WPA → отделить ЦП, ожидания или I/O». Даже проблему, которую один процесс не объясняет, можно разобрать, если смотреть все процессы и ядро на одной шкале времени.12

Разделите место записи и место чтения

Инструмент записи wpr.exe входит в Windows начиная с 8.1, ставить ничего не нужно. GUI-вариант WPRUI и анализатор WPA входят в Windows ADK. Поскольку работу можно разделить как «в среде заказчика только записать через wpr.exe; читать в WPA у себя», снимать можно даже на сервере, куда нельзя добавлять ПО.12

Если проблему можно воспроизвести, базовые три шага с правами администратора: wpr -start GeneralProfile -filemode → воспроизвести проблему → wpr -stop C:\temp\trace.etl.3 Папку назначения готовьте заранее, согласуйте запись и решите, как обращаться с ETL, до запуска. Ожидание неизвестного момента и проблемы при загрузке требуют других способов записи — см. главу 3 и главу 8.

Первый график, который открывать в WPA

Сначала сузьте до интервала проблемы, затем выберите направление расследования по таблице ниже.45

Состояние в этом интервале На что смотреть сначала Что подтвердить
ЦП высокий Глава 5: CPU Usage (Sampled) Какой процесс, стек и функция занимали ЦП
Общий ЦП низкий, но одно ядро или один поток прижат Глава 5: CPU Usage (Sampled) Не спрятан ли узкий ЦП под общей загрузкой
Медленно, хотя ни ЦП, ни конкретное ядро не прижаты Глава 6: CPU Usage (Precise) Где ждал, сколько ждал и кто снял ожидание
Подозревают диск или доступ к файлам Глава 7: Disk Usage / File I/O Время очереди против времени обслуживания устройства и какой процесс выдал I/O к какому файлу

Sampled показывает разбивку времени ЦП по выборкам примерно раз в миллисекунду.6 Precise идёт по ожиданиям по полной записи переключений контекста. Пройти сторону, которая сняла ожидание, по подсказкам Waits → ReadyingProcess → ReadyThreadStack — приём, который эта статья больше всего хочет передать.47

Как читать эту статью по цели

Если вы отвечаете за запись, начните с главы 2 и главы 3; если читаете уже снятый ETL — с главы 4. Чтобы читать стеки по именам функций, нужна настройка символов, а для своего приложения добавляют путь к его PDB.8 Когда разбираете JIT-код .NET, нужны ещё события CLR в момент записи, поэтому до записи сверьтесь с заметками о .NET в главе 4.

Общий рабочий поток расследования и обращение с ETL собраны в главе 9. В ETL есть внутренняя информация — имена процессов, пути файлов, — поэтому запись держите на минимуме необходимого и заранее решите условия передачи за пределы компании.

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 16, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. Где стоят инструменты — пишет WPR, читает WPA

Windows Performance Toolkit (WPT) — набор инструментов расследования производительности в Windows ADK (Windows Assessment and Deployment Kit), и его ядро — пара WPR и WPA.2 Роли чётко разделены.

WPR пишет, WPA анализирует

  • WPR (Windows Performance Recorder) = запись. Он собирает поставщиков ETW в единицы «профили», стартует и останавливает запись и выдаёт ETL-файл. Консольный вариант wpr.exe входит в Windows начиная с 8.1, без дополнительной установки. GUI-вариант (WPRUI.exe) входит в ADK.1
  • WPA (Windows Performance Analyzer) = анализ. Открывает ETL-файл и разбирает его графиками и таблицами. Нужна установка ADK.2

Иначе говоря, если с командной строки только пишете, в среде заказчика ничего дополнительно ставить не нужно. Запишите штатным wpr.exe ОС, унесите ETL и читайте в WPA у себя — то же разделение, что «снимать pktmon, читать в Wireshark» в захвате пакетов.

Разделение: пишет WPR, читает WPAВ среде заказчика записывают штатным wpr.exe ОС и получают ETL-файл, уносят его и разбирают в WPA, установленном через ADK, на своём ПКСвой ПК (WPA установлен через ADK)Среда заказчика (без дополнительной установки)УнестиАнализ графиками и таблицами в WPAETL-файлwpr -start → воспроизвести проблему → wpr -stop

Выбор между Procmon, PerfView и WPR/WPA

Сначала разведём, чем это отличается от похожих инструментов.

  Process Monitor PerfView WPR + WPA
На какой вопрос отвечает Какой процесс что сделал с каким путём и каков результат Что делают ЦП, GC и выделения .NET-приложения Куда по всей ОС ушло время
Охват Журнал операций с файлами, реестром и запуском процессов В основном управляемый код Вся система: ЦП, ожидания, диск, файловый I/O, питание и прочее
Симптомы, которым подходит Настройки не читаются, ACCESS DENIED Медленность или память только своего .NET-приложения Весь ПК тормозит, ЦП свободен а всё равно медленно, неизвестен процесс-виновник
Статья Практическое руководство по 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

Что решить до запуска

В продакшене не считайте даже короткую запись безусловно безопасной. ETW лёгок, но запись большого объёма событий со стеками занимает заметные ЦП и память. Выбирайте окно с малым влиянием на работу и проводите через тот же процесс согласования, что и обычное изменение.

Если проблему можно воспроизвести, стартуйте непосредственно перед, останавливайте сразу после и укладывайтесь в несколько минут. Папку назначения готовьте заранее и заранее решите, кто получает ETL, сколько его хранят и как удаляют. Предостережения о содержимом — в главе 9.

Ниже — пример записи проблемы, которую можно воспроизвести на месте, в режиме File. Для проблемы, момент которой неизвестен, переходите к режиму Memory в разделе 3.1; для проблем при загрузке или входе — к главе 8.

Обычная запись — «start → воспроизвести → stop»

Запускайте в командной строке от имени администратора. -profiles заранее перечисляет доступные профили, -status проверяет состояние во время записи. -cancel в конце используют только чтобы прервать посередине и отбросить; это не часть обычной процедуры сохранения.

:: Список встроенных профилей
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 тормозит весь ПК"

:: Если нужно прервать без сохранения
wpr -cancel

Что записывать, выбирайте профилем

То, что передаёте в -start, — профиль, набор поставщиков ETW, которые нужны расследованию.3 Достаточно помнить часто используемые.9

Профиль Что записывает Когда использовать
GeneralProfile Универсальный набор: выборки ЦП, переключения контекста, дисковый I/O и прочее Начните отсюда. Первый ход, когда ещё неизвестно, что не так
CPU Подробности использования ЦП Когда уже известно, что ЦП горит
DiskIO Активность дискового I/O Когда подозревают диск
FileIO Активность файлового I/O Когда нужно проследить, к какому файлу обращаются

Несколько профилей можно указать сразу, повторяя -start (например, wpr -start GeneralProfile -start FileIO -filemode).3

Поток записи WPR и как выбирать режимПроблему, которую можно воспроизвести на месте, коротко и надёжно снимают в режиме файла; проблему, момент которой неизвестен, ждут в кольцевом буфере режима памяти по умолчанию. Проблема при загрузке или входе — загрузочная трасса. Во всех случаях процедура start, воспроизвести, stop одна и та жеВоспроизводится на местеМомент неизвестенПри загрузке или входеКогда возникает проблема?Снять коротко и надёжно через -filemodeЖдать в режиме Memory (по умолчанию, кольцевой буфер) (раздел 3.1)Загрузочная трасса (глава 8)wpr -start → воспроизвести или ждать проблему → wpr -stop

3.1. Режим Memory и режим File — можно воспроизвести или нужно ждать?

У WPR два режима назначения записи, и по умолчанию — режим Memory (кольцевой буфер в памяти).

Режим Memory — чтобы ждать возникновения проблемы. Это кольцевой буфер, который сначала перезаписывает самые старые события, поэтому он подходит, чтобы оставить запись идущей, пока ждёте проблему, момент которой неизвестен, и остановить, когда она случится.

Режим File — для проблем, которые надёжно воспроизводятся за короткое время. Добавление -filemode переключает в режим File, и всё пишется в непрерывный файл. Ничего не теряется из-за перезаписи, но взамен потолок только свободное место на диске, и файл растёт без границы.10

Как пишут режим Memory и режим FileРежим Memory пишет в кольцевой буфер в памяти, где самые старые события перезаписываются и остаются только самые новые, поэтому он подходит, чтобы ждать проблему. Режим File держит всё в файле, но потолок только свободное место на диске, поэтому он подходит для короткого надёжного воспроизведенияПоток событий ETWРежим Memory: кольцевой буфер (старые перезаписываются первыми → остаются только самые новые)Режим File: всё держится в файле (потолок — свободное место на диске)Подходит, чтобы ждать проблему, момент которой неизвестенПодходит для проблемы, которую можно надёжно воспроизвести за короткое время

Правило выбора такое.

  • Воспроизводится на месте → режим File. Стартуйте непосредственно перед воспроизведением, останавливайте сразу после и укладывайте запись в несколько минут
  • Момент неизвестен → ждите в режиме Memory (по умолчанию). Как только случилось, выполните wpr -stop
  • Даже несколько минут GeneralProfile могут дать ETL от сотен МБ до ГБ. Слишком большой файл WPA иногда уже не открывает, поэтому «чем дольше запись, тем лучше» работает против цели1011

Запись из GUI

Чтобы писать из GUI, запустите WPRUI, выберите профиль и Logging mode и нажмите Start, затем Save. Подробности процедуры — в официальных темах How-to.11 Когда просите контакт на площадке заказчика снять запись, можно написать процедуру вокруг шагов start, воспроизвести и stop, а предпосылки и операцию прерывания вынести отдельно.

4. Основы чтения WPA — графики, золотое правило таблиц и сужение диапазона времени

Когда открываете снятый ETL в WPA, Graph Explorer слева перечисляет миниатюры графиков по категориям вроде System Activity, Computation, Storage и Memory.12 Перетащите нужный график на вкладку Analysis справа — сверху появится график, снизу таблица.

Три вещи, которые нужно освоить, — порядок столбцов, сужение диапазона времени и настройка символов. Вместо того чтобы заново учить операции для каждого графика, начните с этого общего способа чтения.

4.1. Порядок столбцов решает, как данные агрегируются

У таблицы WPA две вертикальные полосы, золотая и синяя: столбцы слева от золотой полосы иерархизируют (группируют) данные в этом порядке, а столбцы справа от синей — агрегаты.13

Порядок «Process → Stack» даёт агрегацию стеков по процессу; «Stack → Process» — агрегацию по всем процессам, которые используют тот же стек. Перетаскивание столбцов, чтобы изменить порядок, само по себе и есть операция анализа. Поняв этот один пункт, все таблицы WPA читаются одинаково.

Золотое правило таблиц — две полосы и роли столбцовПорядок столбцов слева от золотой полосы иерархизирует данные, столбцы между золотой и синей — столбцы отображения, столбцы справа от синей — агрегаты. Перетаскивание столбцов само по себе операция анализаСлева от золотой полосы: столбцы группировки (порядок = иерархия)Золотая полосаМежду полосами: столбцы отображенияСиняя полосаСправа от синей полосы: агрегаты (Sum, % и т. д.)Перетащить столбец = операция анализа (Process → Stack даёт агрегацию стеков по процессу)

4.2. Сузьте до интервала, когда возникала проблема

Перетащите на графике диапазон, затем щёлкните правой кнопкой и выберите «Zoom» — агрегация переключится только на этот интервал. Принцип расследования производительности — всегда смотреть только «интервал, когда проблема шла» (глава 9).

4.3. Загрузите символы и смотрите стеки по именам функций

Чтобы читать стеки по именам функций, выполните Trace > Load Symbols из меню.14 По умолчанию он обращается к публичному серверу символов Microsoft (msdl.microsoft.com), поэтому стеки самой Windows разрешаются, пока есть подключение к Интернету.

Чтобы видеть имена функций и своего приложения, добавьте папку с PDB приложения в Trace > Configure Symbol Paths.8 Что такое PDB и почему его стоит всегда хранить даже для release-сборок, собрано в «Что такое PDB (Program Database)?».

Для .NET разделяйте образы NGen и JIT-код

Для нативных образов NGen .NET Framework WPR в момент записи генерирует NGen PDB (.ngenpdb), кладёт их в папку рядом с трассой, и WPA ссылается на них автоматически.8 Этот механизм специфичен для образов NGen; свой код обычного .NET-приложения, которое работает под JIT, сюда не входит.

Сопоставление адресов JIT-кода с именами функций разрешается из событий JIT, которые выдаёт CLR. Поэтому когда разбираете .NET-приложение, подготовьте профиль записи (.wprp), который включает поставщиков CLR (Microsoft-Windows-DotNETRuntime и его Rundown-пару), совместите в форме wpr -start GeneralProfile -start MyDotNet.wprp!ProfileName, как со своим поставщиком в главе 2, чтобы события CLR попали в трассу (какие встроенные профили даёт ваш локальный WPR, можно проверить через wpr -profiles).

Поверх этого храните PDB, которые генерирует сборка, для сопоставления со строками исходников и добавьте их в путь символов, описанный выше.

Разрешение символов, чтобы читать стеки по именам функцийКогда выполняете Trace Load Symbols, сама Windows разрешается с публичного сервера символов Microsoft, а своё приложение — из PDB сборки, добавленных в путь символов. Образы NGen разрешаются из NGen PDB, которые генерирует WPR, а JIT-код .NET — из событий JIT CLR в трассе плюс PDB сборкиTrace > Load SymbolsСама Windows: публичный сервер символов (msdl)Своё приложение: PDB сборки, добавленные в Configure Symbol PathsОбразы NGen .NET Framework: .ngenpdb, которые генерирует WPRJIT-код .NET: события JIT CLR в трассе + PDB сборки

4.4. Решите, разбирать ЦП, ожидания или I/O

Когда настройка готова, смотрите, был ли ЦП высоким или низким в интервале проблемы. Если высоким — к Sampled в главе 5. Если низким, сначала проверьте, не прижато ли конкретное ядро или поток; если нет — идите по ожиданиям с Precise в главе 6. Если подозревают диск — к главе 7.

Выбор графика WPA по симптомуПриблизить интервал проблемы; если ЦП высокий — к CPU Usage Sampled; если низкий, но медленно, проверить прижатое ядро и затем анализ ожиданий в CPU Usage Precise; если подозревают диск — к Disk Usage и File IOВысокийНизкий, но медленноДаНетПодозревают дискПриблизить интервал проблемыЦП в этом интервале?Глава 5: CPU Usage (Sampled) — «кто жжёт ЦП в какой функции»Одно ядро или один поток прижаты?Глава 6: CPU Usage (Precise) — «чего он ждал»Глава 7: Disk Usage / File I/O, чтобы найти виновника

5. Когда ЦП высокий — «кто жжёт ЦП в какой функции» через CPU Usage (Sampled)

Эта глава ищет путь вызовов, который занимает большую долю времени ЦП.

Если ЦП прижат, смотрят CPU Usage (Sampled). Это данные выборки, которые примерно раз в миллисекунду на каждом ЦП записывают «стек какого процесса сейчас выполняется», и отношение числа выборок напрямую даёт разбивку времени ЦП.6

Как работает CPU Usage SampledПримерно раз в миллисекунду записывается стек, выполняющийся на каждом ЦП, и отношение агрегированных выборок — разбивка времени ЦП. Читайте вниз от процесса к потоку, стеку и функции. Короткая активность, которая укладывается между выборками, не захватываетсяПрерывание примерно раз в 1 мсЗаписать «стек, выполняющийся прямо сейчас» на каждом ЦПАгрегировать выборки (отношение = разбивка времени ЦП)Спуститься Process → Thread → Stack → функцияКороткая активность, которая укладывается между выборками, не захватывается

Спускайтесь от процесса к стеку и к функции

  1. Из Computation в Graph Explorer положите CPU Usage (Sampled) на вкладку Analysis и выберите пресет Utilization by Process, Stack.5
  2. Смотрите процессы по убыванию Weight (или Count). То, что в Диспетчере задач было «50%», сначала идентифицируется на уровне процесса.
  3. Раскройте столбец Stack процесса-виновника. Стеки агрегируются деревом, и спуск по пути, где на каждой ветке числа почти не падают, приводит к функции, которая жжёт ЦП. Если символы разрешились, это прямая линия до конкретной функции своего кода.
  4. Если раскрывать дерево утомительно, переключите отображение графика на Flame (flame graph). Ширина рисуется как доля времени ЦП, поэтому какой путь вызовов доминирует, видно сразу. У CPU Usage (Sampled) есть и пресет Flame by Process, Stack.13

Sampled не измеряет точную длительность одного прогона

Поскольку это выборка, короткая активность, которая укладывается между выборками, не захватывается.6 Помните: это инструмент, чтобы видеть «где ЦП использовался в сумме», а не чтобы измерять точное время выполнения каждого отдельного прогона.

6. Когда ЦП низкий, а всё равно медленно — CPU Usage (Precise) и анализ ожиданий

6.1. Перед анализом ожиданий проверьте одно прижатое ядро

«Общая загрузка ЦП низкая» не значит «ЦП не узкое место». На ПК с 16 ядрами последовательная работа, прижатая к одному ядру (один UI-поток, который крутится на полную), даёт всего около 6% в целом.

Сначала проверьте через Sampled из главы 5 или через Utilization by CPU в CPU Usage (Precise), не прижато ли конкретное ядро или поток. Если и там ничего не прижато, считайте, что обработка не «не может занять ЦП», а чего-то ждёт, и переходите к анализу ожиданий. Дальше инструмент — CPU Usage (Precise).

6.2. Отделите «время в ожидании» от «ожидания ЦП после пробуждения»

Где Sampled — выборка, Precise — полная запись переключений контекста (переключений потоков). Поток входит в ожидание, его кто-то будит (Ready), он попадает на ЦП — каждый такой круговой проход хранится как одна строка, и можно читать следующие столбцы.74

Столбец Смысл
NewThreadStack На каком стеке поток вошёл в ожидание (= что он делал, когда остановился)
Waits (us) Время, проведённое в ожидании
Ready (us) Время, которое пришлось ждать между пробуждением и попаданием на ЦП (конкуренция за ЦП)
ReadyingProcess / ReadyingThreadId Процесс и поток, которые его разбудили (сняли ожидание)
ReadyThreadStack На каком стеке сторона, которая будила, его разбудила
Один круговой проход ожидания и соответствующие столбцыПоток входит в ожидание на стеке, который хранится в NewThreadStack, и ждёт время Waits. Когда кто-то его будит, эта сторона хранится в ReadyingProcess и ReadyThreadStack, и поток ждёт время Ready из-за конкуренции за ЦП, прежде чем снова выполнятьсяВходит в ожидание (хранится в NewThreadStack)Кто-то будит (ReadyingProcess / ReadyThreadStack)Попадает на ЦПВыполняетсяОжидает (Waits (us))Ready (ждёт конкуренции за ЦП)Снова выполняется

6.3. От задержанного потока проследите каждого, кто будил, по очереди

Порядок чтения такой.4

1. Настройте график и столбцы

Примените пресет Utilization by Process, Thread и добавьте в столбцы NewThreadStack и ReadyThreadStack.

2. Выберите поток задержанной операции

Сначала найдите поток, который выполнял задержанную операцию, например UI-поток или поток, обрабатывающий данный запрос. Если смотреть только по убыванию суммарных Waits, сверху выходят здоровые потоки, которые ждут намеренно, вроде насоса сообщений или таймера.

Если у целевого потока велик CPU Usage (ms), это проблема ЦП из главы 5; если доминируют Waits — проблема ожидания.

3. В NewThreadStack смотрите «что он делал, когда остановился»

Раскройте NewThreadStack. WaitForSingleObject или EnterCriticalSection значит ожидание блокировки; внутри синхронного I/O вроде ReadFile — ожидание I/O; внутри приёма сокета — ожидание ответа другой стороны.

4. В ReadyThreadStack смотрите «кто снял ожидание»

Раскройте ReadyThreadStack и проверьте ReadyingProcess / ReadyingThreadId. Если его разбудили из KiTimerExpiration ядра, это был таймер (спал до тайм-аута); если из обработки завершения I/O, это подтверждает ожидание I/O.4

5. Повторите то же расследование на стороне, которая будила

Если будил другой поток или другой процесс, следующим исследуйте тот поток той же процедурой.

Например, цепочка вроде A ждал, пока B отпустит блокировку, B ждал ответа RPC от C, а C ждал дискового I/O. Пройдя эту цепочку до корня, получаете критический путь задержки.7

Цепочка критического пути, которую прослеживает анализ ожиданийВ NewThreadStack задержанного потока A увидеть, что он делал, когда остановился, идентифицировать будившего B из ReadyThreadStack и ReadyingProcess, исследовать B той же процедурой и спуститься до корневого дискового I/ONewThreadStack: остановился в ожидании блокировкиNewThreadStack: ждёт ответа RPCNewThreadStack: ждёт синхронного I/OЗавершение будит CОтвет будит BОтпускание блокировки будит A (видно в ReadyThreadStack)Поток A (задержанная операция)Поток B (держит блокировку)Процесс CДисковый I/O (корень)

Превратите причину ожидания в ревью проекта

В проекте, где «сделали многопоточность, а быстрее не стало», эта процедура показывает всех рабочих, выстроившихся за одной блокировкой, как есть. Как избегать конкуренции за блокировки проектом, разобрано в «Практических рекомендациях по многопоточности: .NET», а механизм Windows, который работает по уведомлениям о завершении вместо ожидания в синхронном I/O, — в «Портах завершения I/O (IOCP) и пуле потоков .NET». Зафиксировать в WPA «кого он ждал» и затем чинить этими принципами проектирования — один непрерывный поток.

7. Диск и файловый I/O — найти «кто-то сканирует диск»

Классический виновник «весь ПК тормозит» — не ЦП, а диск. Разбирайте через Disk Usage и File I/O в категории Storage.15

7.1. В Disk Usage отделите «обработку устройством» от «очереди»

Disk Usage — запись дискового I/O. Начните с различения двух следующих столбцов.6

Столбец Время, которое он представляет
Disk Service Time Время, которое дисковое устройство реально потратило на обработку этого I/O
IO Time Время от входа I/O в очередь ОС до завершения

IO Time всегда не меньше Service Time, разница — время в очереди. Если IO Time намного больше Service Time, этот I/O ждал в очереди.6

Однако не решайте причину только по разнице времён. Строил ли очередь другой процесс или собственный тяжёлый I/O процесса выстроился на медленном устройстве, ещё не решено. Смотрите отклик самого устройства в Service Time, затем закрывайте разбивкой по процессу, пути и стеку.

7.2. Какой процесс выдал I/O к какому файлу

Итак, пресетом Utilization by Process, Path Name, Stack смотрите, какой процесс выдал I/O к какому файлу с какого стека, по убыванию IO Time или Size.15 Два ответа, которые на местах встречаются чаще всего, такие.

  • Антивирус сканировал каждый файл. Это видно как процесс антивируса, выдающий большой объём чтений в интервале, когда приложение медленно стартовало. Имя процесса, путь и объём — готовые доказательства для разговора об исключениях.
  • Другой процесс интенсивно писал. Резервное копирование, индексатор, избыточное журналирование и т. п. Когда запись доходит до диска, задействован диспетчер кэша, поэтому факт, что «момент записи» и «момент, когда диск занят» могут разойтись, также объяснён в «Диспетчере кэша — когда WriteFile на самом деле оказывается на диске?».

7.3. Медленность до диска смотрите в File I/O

File I/O — на слой выше: запись файловых операций, которые выдало приложение (Create, Read, Write и т. д.), а пресеты вроде Duration by Process, Thread, Type агрегируют время по имени файла и по операции.15

Случай, когда время тратится в файловой системе или драйвере фильтра до попадания на диск, в Disk Usage не появляется, поэтому само расхождение «Disk Usage тих, а File I/O медленный» — подсказка. Если хотите начать с того, как работают синхронный и асинхронный I/O, см. «Синхронный и асинхронный I/O — что на самом деле значит OVERLAPPED».

Разные слои, которые видят File IO и Disk UsageФайловая операция приложения проходит через файловую систему и драйверы фильтра и доходит до дискового устройства из очереди IO ОС. File IO записывает операции верхнего слоя, Disk Usage — IO, дошедший до диска, а разница между IO Time и Disk Service Time показывает время в очередиПриложение: ReadFile / WriteFileФайловая система и драйверы фильтра (слой, который видит File I/O)Очередь I/O ОСДисковое устройство (слой, который видит Disk Usage)Время, потраченное здесь, в Disk Usage не появляетсяIO Time − Disk Service Time = время в очередиDisk Service Time = время обработки устройством

7.4. Когда подозреваете нехватку памяти, проверьте и физическую память

Цепочку рассуждений «может, памяти мало и идёт подкачка» можно сначала отсортировать в Диспетчере задач и Мониторе ресурсов, прежде чем переходить к WPA.

Не исключайте нехватку памяти, глядя только на выделенную (committed) память. Даже при запасе commit давление на физическую память может обрезать рабочие наборы и держать поток жёстких ошибок страниц. Также проверьте доступную физическую память и «Hard Faults/sec» в Мониторе ресурсов. Как их читать — в статье Что на самом деле значит «использование памяти» в Windows?.

8. Медленная загрузка и вход — вход в загрузочную трассу

С типом «загрузка занимает 3 минуты» проблема заканчивается раньше, чем вы успеете вручную запустить wpr -start. У WPR есть загрузочная трасса, которую можно настроить так, чтобы ОС начинала запись автоматически при следующей загрузке.3

Настройте запись на следующую загрузку, затем сохраните после перезапуска

Как в главе 3, решите согласование записи и обращение с ETL, затем работайте из командной строки от имени администратора.

:: 1. Настроить автозапись при следующей загрузке
wpr -boottrace -addboot GeneralProfile -filemode

:: 2. Перезагрузить (воспроизвести медленную загрузку)

:: 3. После загрузки остановить запись и сохранить (настройка тоже снимается)
mkdir C:\temp 2>nul
wpr -boottrace -stopboot C:\temp\boot.etl "Загрузка занимает 3 минуты"
Поток загрузочной трассыНастроить автоматическую запись на следующую загрузку через addboot, затем перезапустить; ОС начинает запись автоматически при загрузке. Сохранение через stopboot после входа также снимает настройку. Чтобы отказаться, снимите через cancelbootНастроить через wpr -boottrace -addbootПерезапустить (воспроизвести медленную загрузку)ОС начинает запись автоматически при загрузкеСохранить через -stopboot после входа (также снимает настройку)Чтобы отказаться, -cancelboot

После записи — та же сортировка «ЦП, ожидание или I/O»

Измерение загрузки и завершения, которым когда-то занимался xbootmgr, в текущем WPR тоже можно запускать опциями вроде -onoffscenario Boot.3

Снятую трассу читают тем же набором, что и предыдущие главы. Смотрите, какой процесс когда создавался, в хронологическом порядке, на графике Processes; приблизьте интервал, где загрузка застряла; и классифицируйте как ЦП, ожидание или диск. Проявляются шаблоны вроде приложений автозагрузки, которые ждут чего-то по очереди, или старта службы, застрявшего на конкретном I/O.

Анализ загрузки — глубокая специальность сама по себе, поэтому эта статья доходит только до входа: «проблему, которую нельзя поймать вручную, всё равно можно снять через WPR». Начните с общей картины загрузочной трассы GeneralProfile.

9. Рабочий шаблон — классифицировать, приблизить, стек, повторить

Когда инструменты ясны, вот шаблон расследования в целом. Порядок зафиксировать время и сузить интервал, классифицировать, затем проследить стек один и тот же для каждого симптома.

От фиксации времени до проверки гипотезы

  1. Зафиксируйте время явления. Не «было медленно», а «было медленно с 10:23:40 до 10:24:10». Журналы приложения, журнал событий, заметка того, кто работал, — подойдёт что угодно. Если своё приложение пишет вехи в ETW или журнал событий, события внутри трассы служат метками времени напрямую.
  2. Приблизьте только этот интервал. Агрегация по всей трассе сглаживается в средние, и аномалия, которая важна, размывается. Анализ WPA всегда сравнение «интервала, который был ненормальным» с «интервалом, который был нормальным».
  3. Сначала классифицируйте «ЦП, ожидание или I/O». Смотрите CPU Usage (Sampled); если горит — к главе 5. Если не горит — к Waits в CPU Usage (Precise) (глава 6). Если в Disk Usage раздут IO Time — к главе 7. Пройти эту развилку из трёх сначала не даёт заблудиться.
  4. Повторяйте гипотеза → приближение → стек. Если думаете «антивирус?», сузьте до этого процесса и подтвердите стеком. Если не держится, переходите к следующей гипотезе. Не делать вывод, пока не спустились до стека и не подтвердили — дисциплина такого расследования.
Итеративный цикл расследования производительностиЗафиксировать время явления, приблизить интервал, классифицировать ЦП, ожидание или IO, сформировать гипотезу и сузить, подтвердить стеком. Если держится — причина подтверждена; если нет — повторить со следующей гипотезойПодтвержденоНе держитсяЗафиксировать время явленияПриблизить этот интервалКлассифицировать ЦП, ожидание или I/OСформировать гипотезу и сузитьПодтвердить стекомПричина найдена → чинить

Решите, как обращаться с ETL, до записи

ETL-файл снимает широкий вид внутренностей системы: имена всех процессов, пути открытых файлов, загруженные модули и (в зависимости от профиля) имена ключей реестра.

Стандартная запись GeneralProfile не включает тела данных вроде содержимого обмена, но если вы включили собственного поставщика, полезная нагрузка его событий (например, строки, которые записало приложение) идёт как есть.

Подтвердите, что выдают включённые поставщики, и затем относитесь к файлу как к достаточно конфиденциальному, чтобы проявлять осторожность, прежде чем он уйдёт за пределы компании. Как и с захватом пакетов, встройте в процедуру минимальную запись, согласование с получателем и срок хранения и удаление.

Что снимает ETL-файл и как с ним обращатьсяETL снимает имена всех процессов, пути открытых файлов, модули и в зависимости от профиля имена ключей реестра; включение собственного поставщика добавляет и его полезную нагрузку. Относитесь как к конфиденциальному и встройте в процедуру минимальную запись, согласование с получателем и срок хранения и удалениеETL-файлИмена всех процессов, пути файлов, модули(В зависимости от профиля) имена ключей реестраПолезные нагрузки собственных поставщиков (строки, которые записало приложение)Относиться как к конфиденциальному: минимальная запись, согласование с получателем, срок хранения и удаление

10. Итог

Расследование WPR/WPA можно организовать в три следующих этапа.

  1. Снимите нужный интервал. Пишите через wpr.exe, который входит в Windows начиная с 8.1, и читайте ETL в WPA у себя. База — wpr -start GeneralProfile -filemode → воспроизвести → wpr -stop trace.etl. Если можно воспроизвести — режим File в пределах нескольких минут; если ждёте — режим Memory. Для медленности при загрузке используйте wpr -boottrace. Дольше не значит лучше, а внутреннюю информацию в ETL считают конфиденциальной.
  2. Сузьте диапазон времени и выберите направление расследования. В WPA слева от золотой полосы — группировка, справа от синей — агрегаты. Освойте порядок столбцов, приближение к интервалу и настройку символов, затем отделите ЦП, ожидания или I/O. Для своего приложения дайте PDB, а для JIT-кода .NET сверьтесь ещё и с событиями CLR в момент записи.
  3. Спуститесь до стека и проверьте гипотезу. Если ЦП высокий, спускайтесь от процесса к функции в Sampled. Даже если общий ЦП низкий, сначала проверьте одно прижатое ядро или поток, и если его нет, идите по ожиданиям в Precise. Для диска не решайте причину только по разнице времён; смотрите отклик устройства и разбивку того, кто выдал I/O.

То, что прослеживают в анализе ожиданий, — NewThreadStack (что он делал, когда остановился) → Waits (сколько ждал) → ReadyingProcess и ReadyThreadStack (кто его разбудил). Исследуйте будившего так же — и цепочку задержек можно пройти до корня.

WPA сначала может подавить объёмом информации на экране. И всё же, если держаться «порядок столбцов — это как данные агрегируются» и «Sampled — где использовался ЦП, Precise — кого ждал», остальное — повторение фиксации времени, приближения, классификации и проверки стека. В следующий раз, когда придёт консультация «по ЦП есть запас, а всё равно медленно», снимите трассу в этом порядке и прочитайте её.

Похожие статьи

Смежные области консультирования

KomuraSoft LLC занимается расследованиями общесистемных проблем производительности вроде «весь ПК стал тормозить и причину не находим», «по ЦП есть запас, а приложение медленное» и «только в одной среде крайне медленная загрузка». Мы ведём всё как одно непрерывное сопровождение: от проекта записи WPR/WPA (какая среда, какой профиль и сколько снимать) через анализ трассы до исправления причины на стороне приложения или настроек.

Справочные ссылки

  1. Microsoft Learn, Introduction to WPR. О том, что WPR — инструмент записи производительности на базе ETW; о том, что консольный вариант WPR.exe входит в Windows начиная с 8.1 без дополнительной установки; о связи с GUI-вариантом WPRUI.exe; и о понятии профилей записи. ↩ ↩2 ↩3

  2. Microsoft Learn, Windows Performance Analyzer. О том, что WPA входит в Windows ADK, является инструментом анализа, который строит графики и таблицы данных из событий ETW, записанных WPR, Xperf и подобными, и может открывать и разбирать любой ETL-файл. ↩ ↩2 ↩3 ↩4

  3. Microsoft Learn, WPR Command-Line Options. О синтаксисе wpr -start/-stop/-cancel/-status/-profiles; о -filemode (по умолчанию режим памяти); об указании нескольких профилей сразу; о загрузочных трассах через -boottrace (addboot/stopboot/cancelboot); и о записи переходов On/Off вроде Boot через -onoffscenario. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  4. Microsoft Learn, CPU Analysis. Об определениях столбцов графика CPU Usage (Precise) (NewThreadStack, ReadyThreadStack, ReadyingProcess, Waits и подобные); о процедуре раскрытия ReadyThreadStack и следования ReadyingProcess/ReadyingThread до корневой причины ожидания; и о том, как отличить пробуждение из KiTimerExpiration (ожидание таймера) от вызванного завершением I/O. ↩ ↩2 ↩3 ↩4 ↩5

  5. Microsoft Learn, Troubleshoot processes and threads by using WPR and WPA. О конфигурациях вроде чтения CPU Usage (Sampled) как Process→Stack при высокой загрузке ЦП и использования CPU Usage (Precise) Readying Process, Readying Thread, Readying Stack и столбца Wait в анализе ожиданий; и о таблице соответствия профилей и графиков по симптомам. ↩ ↩2

  6. Microsoft Learn, Exercise 2 - Evaluate Fast Startup Using Windows Performance Toolkit. О том, что CPU Usage (Sampled) — выборка примерно с интервалом 1 миллисекунда и короткая активность между выборками не записывается; о процедуре спуска процесс → поток → стек, чтобы идентифицировать разбивку потребления ЦП; и о смысле Disk Usage IO Time (включая время очереди) и Disk Service Time (время обработки диском). ↩ ↩2 ↩3 ↩4 ↩5

  7. Microsoft Learn, Exercise 3 - Understand Critical Path and Wait Analysis. О понятии анализа критического пути (классификация Running, Ready и Waiting); о смысле столбцов таблицы CPU Usage (Precise) NewThreadStack, ReadyThreadStack, ReadyingProcess, Waits, Ready и подобных; и о процедуре следования каждому будящему потоку по очереди, чтобы распутать цепочку задержек. ↩ ↩2 ↩3

  8. Microsoft Learn, Loading Symbols. О том, что когда _NT_SYMBOL_PATH не задан, WPA по умолчанию обращается к публичному серверу символов Microsoft (msdl.microsoft.com); о добавлении путей PDB для своих компонентов; и о том, что WPR генерирует PDB для управляемых символов .NET в папке .ngenpdb рядом с трассой и WPA ссылается на них автоматически. ↩ ↩2 ↩3

  9. 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 и другие) и о том, что записывает каждый профиль. ↩

  10. Microsoft Learn, Logging Mode. О том, что режимы записи — File (непрерывный файл) и Memory (кольцевой буфер в памяти) и по умолчанию Memory; о том, что Memory подходит для проблемы, момент которой неизвестен, и старые события перезаписываются; и о том, что у File потолок только свободное место на диске и слишком большой файл WPA может не разобрать. ↩ ↩2

  11. Microsoft Learn, WPR How-to Topics. О процедуре старта и остановки записи в WPRUI; о выборе профиля, уровня детализации и Logging mode; и о предостережении, что длинная запись может сделать файл огромным и неразбираемым в WPA, поэтому следует выбирать режим Memory. ↩ ↩2

  12. Microsoft Learn, Graph Explorer. О том, что окно Graph Explorer перечисляет миниатюры графиков по категориям вроде System Activity, Computation, Storage и Memory; и о том, что график перетаскивают на вкладку Analysis, чтобы показать его вместе с таблицей. ↩

  13. Microsoft Learn, Graphs (WPA Features). Об отображении графика Flame в WPA; о структуре таблицы, в которой столбцы слева от золотой полосы — группировка, а столбцы справа от синей — агрегаты; и о пресете CPU Usage (Sampled) Flame by Process, Stack. ↩ ↩2

  14. Microsoft Learn, Load Symbols or Configure Symbol Paths. О загрузке символов через Load Symbols из меню Trace WPA; и о процедуре задания и изменения путей символов в диалоге Configure Symbol Paths. ↩

  15. 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

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Где взять WPR и WPA? Можно ли ими пользоваться в среде заказчика, куда нельзя ставить ПО?
Консольный инструмент записи wpr.exe входит в Windows начиная с 8.1, ставить ничего не нужно. GUI-вариант WPRUI и анализатор WPA (Windows Performance Analyzer) входят в Windows ADK (Windows Assessment and Deployment Kit) и ставятся отдельно. На практике работу делят так: в среде заказчика ETL-файл записывают только штатным wpr.exe ОС, уносят его и разбирают в WPA у себя. Тогда общесистемную производительность можно разбирать и на площадке, куда нельзя добавлять ПО.
Почему медленно, если в Диспетчере задач по ЦП есть запас? Что видно в WPA?
Когда загрузка ЦП низкая, а всё равно медленно, обработка не «не может занять ЦП» — она стоит, потому что чего-то ждёт. Типичны конкуренция за блокировки, ожидание завершения синхронного I/O, ожидание ответа другого процесса. Диспетчер задач показывает только итог — загрузку. CPU Usage (Precise) в WPA по полной записи переключений контекста показывает, на каком стеке поток начал ждать (NewThreadStack), сколько ждал (Waits) и кто его разбудил (ReadyingProcess, ReadyThreadStack). Пройдя по тому, кто заставил ждать, причину медленности можно довести до конкретной функции.
Как долго писать трассу? Файл не раздуется?
Если проблему можно воспроизвести, базовая схема такая: стартовать непосредственно перед воспроизведением, остановить сразу после и уложиться в несколько минут. По умолчанию у WPR режим Memory: запись идёт в кольцевой буфер в памяти, старые события перезаписываются, поэтому он удобен, когда момент неизвестен и нужно ждать. Режим File с -filemode пишет всё в непрерывный файл, но потолок только свободное место на диске, и слишком большой файл WPA иногда уже не открывает. Режим Memory — чтобы ждать неизвестный момент, режим File — для короткого надёжного воспроизведения.
Как выбирать между PerfView и WPA?
Оба работают с ETW-трассировками, но сильны в разном. PerfView глубоко понимает runtime .NET и удобен для расследований, специфичных для управляемых приложений: GC, выделения, JIT. WPA лучше читает ЦП, диск, файловый I/O, питание и остальное по всей ОС — графиками и таблицами. Это основной выбор, когда «тормозит не одно приложение, а весь ПК», «задействовано несколько процессов» или «подозревают что-то вне приложения: антивирус, драйвер, другой процесс». Ориентир: PerfView — когда медлит только своё .NET-приложение, WPR/WPA — когда медлит вся система.
Можно ли запускать WPR в продакшене заказчика?
Короткую запись на практике делают часто, но это не безусловно безопасно. ETW лёгок, однако запись большого объёма событий со стеками всё равно занимает заметные ЦП и память. Соображения вроде «стартовать непосредственно перед шагом воспроизведения и остановить сразу после», «уложить запись в несколько минут» и «делать это в окно с малым влиянием на работу» нужно проводить через тот же процесс согласования, что и обычное изменение. Кроме того, в ETL-файле есть внутренняя информация системы — имена процессов, пути файлов, сведения об исполняемых файлах, — поэтому заранее решите, как с ним обращаться, если он уйдёт за пределы компании (минимум необходимого, срок хранения, удаление).

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог