Diagnosticar retrasos de la interfaz de usuario causados por las extensiones
Cuando la interfaz de usuario deja de responder, Visual Studio examina la pila de llamadas del subproceso de interfaz de usuario, empezando por la hoja y avanzando hacia la base. Si Visual Studio determina que un marco de pila de llamadas pertenece a un módulo que forma parte de una extensión instalada y habilitada, muestra una notificación.
La notificación informa al usuario de que el retraso de la interfaz de usuario (es decir, la falta de respuesta de la interfaz de usuario) puede deberse al código de una extensión. También proporciona al usuario opciones para desactivar la extensión o futuras notificaciones para esa extensión.
Este documento describe cómo puede diagnosticar qué parte del código de su extensión está causando las notificaciones de retraso de la interfaz de usuario.
Nota:
No use la instancia experimental de Visual Studio para diagnosticar los retrasos de la interfaz de usuario. Algunas partes del análisis de pila de llamadas necesario para las notificaciones de retraso de la interfaz de usuario se desactivan cuando se usa la instancia experimental, lo que significa que es posible que no se muestren las notificaciones de retraso de la interfaz de usuario.
A continuación se ofrece un resumen del proceso de diagnóstico:
- Identificar el escenario desencadenador.
- Reinicie VS con el registro de actividad activado.
- Inicie el seguimiento de ETW.
- Desencadene la notificación para que aparezca de nuevo.
- Detener el seguimiento de ETW.
- Examine el registro de actividad para obtener el ID de retardo.
- Analice el rastreo ETW usando el ID de retardo del paso 6.
En las siguientes secciones, repasaremos estos pasos con más detalle.
Identificar el escenario desencadenador
Para diagnosticar un retraso de la interfaz de usuario, primero debe identificar qué (secuencia de acciones) hace que Visual Studio muestre la notificación. Esto es para poder desencadenar la notificación más tarde con el registro activado.
Reinicie VS con el registro de actividad activado
Visual Studio puede generar un "registro de actividad" que proporciona información útil a la hora de depurar un problema. Para activar el registro de actividad en Visual Studio, abra Visual Studio con la opción de línea de comandos /log
. Una vez iniciado Visual Studio, el registro de actividad se almacena en la siguiente ubicación:
%APPDATA%\Microsoft\VisualStudio\<vs_instance_id>\ActivityLog.xml
Para obtener más información sobre cómo encontrar el ID de instancia de VS, consulte Herramientas para detectar y administrar instancias de Visual Studio. Usaremos este registro de actividad más adelante para obtener más información sobre los retrasos de la interfaz de usuario y las notificaciones relacionadas.
Iniciar el seguimiento de ETW
Puede usar PerfView para recopilar una traza de ETW. PerfView proporciona una interfaz fácil de usar tanto para recopilar una traza ETW como para analizarla. Utilice el siguiente comando para recopilar un seguimiento:
Perfview.exe collect C:\trace.etl /BufferSizeMB=1024 -CircularMB:2048 -Merge:true -Providers:*Microsoft-VisualStudio:@StacksEnabled=true -NoV2Rundown /kernelEvents=default+FileIOInit+ContextSwitch+Dispatcher
Esto habilita el proveedor "Microsoft-VisualStudio", que es el proveedor que utiliza Visual Studio para los eventos relacionados con las notificaciones de retardo de la interfaz de usuario. También especifica la palabra clave para el proveedor de kernel que PerfView puede utilizar para generar la vista Thread Time Stacks.
Desencadene la notificación para que aparezca de nuevo
Una vez que PerfView ha iniciado la recopilación de seguimiento, puede utilizar la secuencia de acciones de desencadenador (del paso 1) para que vuelva a aparecer la notificación. Una vez mostrada la notificación, puede detener la recopilación de seguimientos para que PerfView las procese y genere el archivo de seguimientos de salida.
Detener el seguimiento de ETW
Para detener la recopilación de seguimientos, simplemente utilice el botón Detener recopilación de la ventana de PerfView. Una vez detenida la recopilación de seguimientos, PerfView procesará automáticamente los eventos ETW y generará un archivo de seguimientos de salida.
Examine el registro de actividad para obtener el ID de retardo
Como se ha mencionado anteriormente, puede encontrar el registro de actividad en %APPDATA%\Microsoft\VisualStudio<vs_instance_id>\ActivityLog.xml. Cada vez que Visual Studio detecta un retraso en la interfaz de usuario de la extensión, escribe un nodo en el registro de actividad con UIDelayNotifications
como el origen. Este nodo contiene cuatro fragmentos de información sobre el retraso de la interfaz de usuario:
- El ID de retardo de la interfaz de usuario, un número secuencial que identifica de forma exclusiva un retardo de la interfaz de usuario en una sesión de VS.
- El ID de sesión, que identifica de forma única la sesión de Visual Studio desde el inicio hasta el cierre
- Si se ha mostrado o no una notificación por el retraso de la interfaz de usuario
- La extensión que probablemente causó el retraso de la interfaz de usuario
<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>
Nota:
No todos los retrasos de la interfaz de usuario generan una notificación. Por lo tanto, siempre debe comprobar el valor ¿Notificación mostrada? para identificar correctamente el retardo de la interfaz de usuario correcto.
Después de encontrar el retardo de interfaz correcto en el registro de actividad, anote el ID del retardo de interfaz especificado en el nodo. Utilizará el ID para buscar el evento ETW correspondiente en el siguiente paso.
Análisis de la seguimiento ETW
A continuación, abra el archivo de seguimiento. Puede hacerlo utilizando la misma instancia de PerfView o iniciando una nueva instancia y estableciendo la ruta de la carpeta actual en la parte superior izquierda de la ventana en la ubicación del archivo de seguimientos.
A continuación, seleccione el archivo de seguimientos en el panel izquierdo y ábralo seleccionando Abrir en el menú contextual o del botón derecho del ratón.
Nota:
Por defecto, PerfView genera un archivo Zip. Al abrir trace.zip, se descomprime automáticamente el archivo y se abre la seguimiento. Puede omitir esto desmarcando la casilla Zip durante la recopilación de seguimientos. Sin embargo, si está planeando transferir y usar seguimientos a través de diferentes máquinas, le recomendamos encarecidamente que no desmarque la casilla Zip. Sin esta opción, los PDB necesarios para los ensamblajes Ngen no acompañarán a la seguimiento y, por lo tanto, los símbolos de los ensamblajes Ngen no se resolverán en la máquina de destino. (Consulte esta entrada del blog para obtener más información sobre PDB para ensamblajes Ngen).
PerfView puede tardar varios minutos en procesar y abrir la seguimiento. Una vez que la seguimiento está abierta, aparece una lista de varias "vistas" debajo de ella.
Primero usaremos la vista Eventos para obtener el rango de tiempo del retardo de la interfaz de usuario:
- Abra la vista Eventos seleccionando el nodo
Events
bajo la seguimiento y eligiendo Abrir en el menú contextual o del botón derecho del ratón. - En el panel izquierdo, seleccione "
Microsoft-VisualStudio/ExtensionUIUnresponsiveness
". - Presione Entrar
La selección se aplica y todos los eventos ExtensionUIUnresponsiveness
se muestran en el panel derecho.
Cada fila del panel derecho corresponde a un retardo de la interfaz de usuario. El evento incluye un valor "ID de retardo" que debería coincidir con el ID del retardo en el registro de actividad del paso 6. Dado que ExtensionUIUnresponsiveness
se dispara al final del retardo de la interfaz de usuario, la marca de tiempo del evento (aproximadamente) marca la hora de finalización del retardo de la interfaz de usuario. El evento también contiene la duración del retardo. Podemos restar la duración de la marca de tiempo final para obtener la marca de tiempo de cuando se inició el retardo de la interfaz de usuario.
En la captura de pantalla anterior, por ejemplo, la marca de tiempo del evento es 12.125,679 y la duración del retardo es 6.143,085 (ms). Así,
- El inicio del retardo es 12.125.679 - 6.143.085 = 5.982.594.
- El rango de tiempo de retardo de UI es de 5.982,594 a 12.125,679.
Una vez que tenemos el rango de tiempo, podemos salir de la vista Eventos y abrir la vista Thread Time Stacks (con Actividades StartStop). Esta vista es especialmente útil porque a menudo las extensiones que están bloqueando el subproceso de la interfaz de usuario están simplemente esperando en otros subprocesos o en una operación de E/S. Por lo tanto, la vista CPU Stack, que es la opción a la que se recurre en la mayoría de los casos, puede no capturar el tiempo que el subproceso pasa bloqueado, ya que no está utilizando la CPU durante ese tiempo. La Thread Time Stacks resuelve este problema mostrando adecuadamente el tiempo bloqueado.
Al abrir la vista Thread Time Stacks, elija el proceso devenv para iniciar el análisis.
En la vista Thread Time Stacks, en la parte superior izquierda de la página, puedes establecer el intervalo de tiempo a los valores que calculamos en el paso anterior y pulsar Intro para que las pilas se ajusten a ese intervalo de tiempo.
Nota:
Determinar qué subproceso es el de la interfaz de usuario (inicio) puede ser contraintuitivo si la recopilación de seguimientos se inicia después de que Visual Studio ya esté abierto. Sin embargo, lo más probable es que los primeros elementos de la pila del subproceso de interfaz de usuario (inicio) sean siempre DLL del sistema operativo (ntdll.dll y kernel32.dll), seguidos de devenv!?
y msenv!?
. Esta secuencia puede ayudar a identificar el subproceso de interfaz de usuario.
También puede filtrar aún más esta vista incluyendo solo las pilas que contengan módulos de su paquete.
- Establezca GroupPats como texto vacío para eliminar cualquier agrupación añadida por defecto.
- Establezca IncPats para incluir parte del nombre de su conjunto además del filtro de proceso existente. En este caso, debería ser devenv;UIDelayR2.
PerfView tiene una guía detallada en el menú Ayuda que puede utilizar para identificar cuellos de botella de rendimiento en su código. Además, los siguientes enlaces proporcionan más información sobre cómo utilizar las API de subprocesos de Visual Studio para optimizar el código:
https://github.com/Microsoft/vs-threading/blob/master/doc/index.md
https://github.com/Microsoft/vs-threading/blob/master/doc/cookbook_vs.md
También puede utilizar los nuevos analizadores estáticos de Visual Studio para extensiones (paquete NuGet aquí), que proporcionan orientación sobre las mejores prácticas para escribir extensiones eficientes. Consulte la lista de analizadores de VSSDK y analizadores de subprocesos.
Nota:
Si no puede solucionar la falta de respuesta debido a dependencias sobre las que no tienes control (por ejemplo, si su extensión tiene que llamar a servicios síncronos de VS en el subproceso de interfaz de usuario), nos gustaría saberlo. Si es miembro de nuestro programa Visual Studio Partner, puede ponerse en contacto con nosotros enviando una solicitud de soporte para desarrolladores. De lo contrario, use la herramienta "Notificar un problema" para enviar sus comentarios e incluir "Extension UI Delay Notifications"
en el título. Incluya también una descripción detallada de su análisis.