Диагностика задержек пользовательского интерфейса, вызванных расширениями
Когда пользовательский интерфейс не отвечает, Visual Studio проверяет стек вызовов потока пользовательского интерфейса, начиная с конца и продвигаясь к началу. Если Visual Studio определяет, что кадр стека вызовов принадлежит модулю, который является частью установленного и включенного расширения, отображается уведомление.
Уведомление сообщает пользователю, что задержка пользовательского интерфейса (т. е. отсутствие ответа в пользовательском интерфейсе) могла быть результатом кода из расширения. Он также предоставляет пользователю возможность отключить расширение или будущие уведомления для этого расширения.
В этом документе описывается, как диагностировать, что в коде расширения вызывает уведомления о задержке пользовательского интерфейса.
Заметка
Не используйте экспериментальный экземпляр Visual Studio для диагностики задержек пользовательского интерфейса. Некоторые части анализа стека вызовов, необходимые для уведомлений о задержке пользовательского интерфейса, отключены при использовании экспериментального экземпляра, что означает, что уведомления об задержке пользовательского интерфейса могут не отображаться.
Обзор процесса диагностики выглядит следующим образом:
- Определите сценарий триггера.
- Перезапустите VS с журналированием активности.
- Начните трассировку ETW.
- Активируйте уведомление, чтобы появиться снова.
- Остановите трассировку ETW.
- Проверьте журнал действий, чтобы получить идентификатор задержки.
- Анализируйте трассировку ETW, используя идентификатор задержки из шага 6.
В следующих разделах мы подробно рассмотрим эти действия.
Определение сценария триггера
Чтобы диагностировать задержку пользовательского интерфейса, сначала необходимо определить, что (последовательность действий) вызывает отображение уведомления в Visual Studio. Чтобы вы могли активировать уведомление позже при включенном ведении журнала.
Перезапустите VS с ведением журнала действий
Visual Studio может создать "журнал действий", который предоставляет сведения, полезные при отладке проблемы. Чтобы включить ведение журнала действий в Visual Studio, откройте Visual Studio с параметром командной строки /log
. После запуска Visual Studio журнал действий хранится в следующем расположении:
%APPDATA%\Microsoft\VisualStudio\<vs_instance_id>\ActivityLog.xml
Дополнительные сведения о том, как найти идентификатор экземпляра VS, см. в статье Средства для обнаружения экземпляров Visual Studio и управления ими. Позже мы будем использовать этот журнал действий для получения дополнительных сведений о задержках пользовательского интерфейса и связанных уведомлениях.
Запуск трассировки ETW
Для сбора трассировки ETW можно использовать PerfView. PerfView предоставляет простой интерфейс как для сбора трассировки ETW, так и для ее анализа. Используйте следующую команду для сбора трассировки:
Perfview.exe collect C:\trace.etl /BufferSizeMB=1024 -CircularMB:2048 -Merge:true -Providers:*Microsoft-VisualStudio:@StacksEnabled=true -NoV2Rundown /kernelEvents=default+FileIOInit+ContextSwitch+Dispatcher
Это активирует поставщика Microsoft-VisualStudio, который Visual Studio использует для событий, связанных с уведомлениями о задержке. Он также указывает ключевое слово для поставщика ядра, которое PerfView может использовать для создания представления стека времени потока .
Активируйте повторное отображение уведомления
После того как PerfView начал сбор трассировок, можно снова использовать последовательность действий триггера (с шага 1) для отображения уведомления. После отображения уведомления можно остановить сбор трассировок, чтобы PerfView обработал их и создал выходной файл трассировки.
Остановка трассировки ETW
Чтобы остановить коллекцию трассировок, просто нажмите кнопку Остановить коллекцию в окне PerfView. После остановки сбора трассировки PerfView автоматически обрабатывает события ETW и создает выходной файл трассировки.
Изучите журнал действий, чтобы получить идентификатор задержки
Как упоминалось ранее, вы можете найти журнал действий в %APPDATA%\Microsoft\VisualStudio<vs_instance_id>\ActivityLog.xml. Каждый раз, когда Visual Studio обнаруживает задержку пользовательского интерфейса расширения, он записывает узел в журнал действий с UIDelayNotifications
в качестве источника. Этот узел содержит четыре фрагмента сведений о задержке пользовательского интерфейса:
- Идентификатор задержки пользовательского интерфейса, последовательный номер, который однозначно идентифицирует задержку пользовательского интерфейса в сеансе VS
- Идентификатор сеанса, который однозначно идентифицирует сеанс Visual Studio от начала до закрытия.
- Было ли показано уведомление о задержке пользовательского интерфейса или нет
- Расширение, которое, вероятно, вызвало задержку пользовательского интерфейса
<entry>
<record>271</record>
<time>2018/02/03 12:02:52.867</time>
<type>Information</type>
<source>UIDelayNotifications</source>
<description>A UI delay (Delay ID = 0) has been detected. (Session ID=16e49d4b-26c2-4247-ad1c-488edeb185e0; Blamed extension="UIDelayR2"; Notification shown? Yes.)</description>
</entry>
Заметка
Не все задержки пользовательского интерфейса приводят к уведомлению. Поэтому всегда следует проверять отображаемые уведомления? значение, чтобы правильно определить правильную задержку пользовательского интерфейса.
После поиска правильной задержки пользовательского интерфейса в журнале действий запишите идентификатор задержки пользовательского интерфейса, указанный в узле. Идентификатор будет использоваться для поиска соответствующего события ETW на следующем шаге.
Анализ трассировки ETW
Затем откройте файл трассировки. Вы можете сделать это, либо используя тот же экземпляр PerfView, либо начав новый экземпляр и установив текущий путь к папке в левом верхнем углу окна на расположение файла трассировки.
Затем выберите файл трассировки в левой области и откройте его, выбрав Открыть в контекстном меню правым кликом мыши.
Заметка
По умолчанию PerfView выводит zip-архив. При открытии trace.zipон автоматически распаковывает архив и открывает трассировку. Это можно пропустить, сняв отметку с флажка Zip во время сбора данных трассировки. Однако если вы планируете передавать и использовать трассировки на разных компьютерах, мы настоятельно не рекомендуем снимать флажок Zip. Без этого параметра необходимые PDB для сборок Ngen не будут прилагаться к трассировке, и символы из сборок Ngen не будут определяться на целевом компьютере. (См. этот пост в блоге для получения дополнительной информации о PDB-файлах для сборок Ngen.)
Для обработки PerfView и открытия трассировки может потребоваться несколько минут. После открытия трассировки под ней появляется список различных «представлений».
Сначала мы будем использовать представление событий для получения диапазона времени задержки пользовательского интерфейса:
- Откройте представление событий, выбрав узел
Events
в разделе трассировки и выбрав Открыть из контекстного меню. - Выберите "
Microsoft-VisualStudio/ExtensionUIUnresponsiveness
" в левой области. - Нажмите клавишу ВВОД
Выбор применяется, а все события ExtensionUIUnresponsiveness
отображаются на правой панели.
Каждая строка в правой области соответствует задержке пользовательского интерфейса. Событие содержит значение "Идентификатор задержки", которое должно соответствовать идентификатору задержки в журнале действий из шага 6. Так как ExtensionUIUnresponsiveness
запускается в конце задержки пользовательского интерфейса, метка времени события (примерно) помечает время окончания задержки пользовательского интерфейса. Событие также содержит длительность задержки. Вычитаем длительность из метки времени окончания, чтобы получить метку времени начала задержки пользовательского интерфейса.
На предыдущем снимке экрана, например, метка времени события составляет 12 125,679, а длительность задержки — 6 143,085 (мс). Таким образом
- Начало задержки — 12 125,679 – 643,085 = 5 982,594.
- Диапазон времени задержки пользовательского интерфейса составляет от 5 982,594 до 12 125,679.
Как только у нас есть диапазон времени, мы можем закрыть представление события и открыть представление потокового времени (с действиями StartStop). Это представление особенно удобно, так как часто расширения, блокирующие поток пользовательского интерфейса, просто ожидают других потоков или операции ввода-вывода. Таким образом, представление стека ЦП, которое является вариантом go-to в большинстве случаев, может не захватить время, когда поток находится в состоянии блокировки, так как в это время он не использует ЦП. Стеки времени потока решают эту проблему, правильно показывая заблокированное время.
При открытии представления стеки времени потока выберите процесс devenv, чтобы начать анализ.
В представлении стека времени потока в левом верхнем углу страницы можно установить диапазон времени на значения, которые мы вычислили на предыдущем шаге, и нажмите клавишу ВВОД, чтобы стеки соответствовали этому диапазону времени.
Заметка
Определение потока пользовательского интерфейса (потока запуска) может быть неочевидным, если сбор трассировки начат после открытия Visual Studio. Однако первые элементы в стеке потока пользовательского интерфейса (запуска) скорее всего всегда являются библиотеками DLL операционной системы (ntdll.dll и kernel32.dll), за которыми следует devenv!?
, а затем msenv!?
. Эта последовательность может помочь определить поток пользовательского интерфейса.
Кроме того, вы можете отфильтровать это представление, добавив только стеки, содержащие модули из пакета.
- Установите для GroupPats пустой текст, чтобы удалить любую группировку, добавленную по умолчанию.
- Задайте IncPats, чтобы включить часть имени сборки в дополнение к существующему фильтру процессов. В этом случае это должно быть devenv; UIDelayR2.
PerfView содержит подробные рекомендации в разделе справки, которые вы можете использовать для выявления узких мест в коде. Кроме того, следующие ссылки содержат дополнительные сведения об использовании API потоков Visual Studio для оптимизации кода:
https://github.com/Microsoft/vs-threading/blob/main/doc/index.md
https://github.com/Microsoft/vs-threading/blob/main/doc/cookbook_vs.md
Вы также можете использовать новые статические анализаторы Visual Studio для расширений (пакет NuGet здесь), которые предоставляют рекомендации по написанию эффективных расширений. См. список анализаторов VSSDK и анализаторов потоков .
Заметка
Если вы не можете устранить неотзывчивость из-за зависимостей, которыми вы не управляете, например, если ваше расширение должно вызывать синхронные службы VS в потоке пользовательского интерфейса, мы хотели бы знать об этом. Если вы являетесь членом нашей партнерской программы Visual Studio, обратитесь к нам, отправив запрос в службу поддержки разработчиков. В противном случае используйте средство "Сообщить о проблеме" для отправки отзывов и включения "Extension UI Delay Notifications"
в заголовок. Также укажите подробное описание анализа.