CPU de 24 núcleos, pero no puedo escribir un correo electrónico

No busqué problemas. No comencé el proceso de compilación de Chrome mil veces durante el fin de semana , pero solo realicé las tareas más comunes del siglo XXI: acabo de escribir un correo electrónico a las 10:30 de la mañana. Y de repente Gmail se aferró. Seguí imprimiendo durante unos segundos, pero no aparecieron caracteres en la pantalla. Entonces, de repente, Gmail se hundió y volví a mi correo electrónico muy importante . Pero luego todo se repitió, solo que esta vez Gmail no respondió solicitudes aún más. Esto es extraño ...

Es difícil resistirse a la oportunidad de realizar una buena investigación, pero en este caso el desafío es especialmente fuerte. Después de todo, estoy en Google trabajando para mejorar el rendimiento de Chrome para Windows. Descubrir la causa de la congelación es mi trabajo . Y después de muchos inicios falsos y trabajo arduo, logré descubrir cómo Chrome, Gmail, Windows y nuestro departamento de TI me impidieron escribir un correo electrónico. En el camino, había una manera de ahorrar una cantidad significativa de memoria para algunas páginas web en Chrome.

Hubo tantos matices en la investigación que dejaré algunos para otro artículo , y ahora explicaré completamente las razones de las suspensiones.

Como de costumbre, UIforETW funciona en mi fondo y monitorea los buffers circulares, así que solo tuve que escribir Ctrl + Win + R, y los buffers se guardaron en el disco durante los últimos treinta segundos de actividad del sistema. Los descargué en Windows Performance Analyzer (WPA), pero no pude instalar permanentemente el congelamiento.

Cuando el programa de Windows deja de enviar mensajes, se lanzan eventos ETW que indican exactamente dónde sucedió esto , por lo que es trivial encontrar este tipo de bloqueos. Pero aparentemente, Chrome continuó enviando mensajes. Miré por un momento cuando una de las transmisiones clave de Chrome entró en el ciclo activo o estaba completamente inactiva, pero no encontré nada explícito. Hubo algunos lugares donde Chrome permaneció inactivo en su mayoría , pero aun así todos los hilos clave continuaron funcionando, por lo que no podía estar seguro de dónde se produjo el bloqueo: Chrome simplemente podría permanecer inactivo en ausencia de eventos:



UIforETW tiene un keylogger incorporado, que a menudo es útil para identificar puntos clave en una traza. Sin embargo, por razones obvias de seguridad, por defecto anonimiza las pulsaciones de teclas, tratando cada número ingresado como "1" y cada letra como "A". Esto hace que sea difícil encontrar el momento exacto de congelación, por lo que cambié el tipo de rastreo de "privado" a "completo" y esperaba un congelamiento. Alrededor de las 10:30 de la mañana siguiente, se repitió el problema. Guardé los búferes de rastreo y guardé esta marca en el campo de información de rastreo UIforETW:

Escribió "posponer para aquellos que tienen más experiencia con el buceo" - y Gmail hizo una pausa al final de la palabra "esos", y luego reanudó el trabajo en el área de la palabra "experiencia". Pestaña Gmail con PID 27368.

Esta es una discusión común sobre las formas de llegar a la oficina , pero es importante que ahora haya una manera de encontrar un obstáculo en el rastreo de ETW. Cargo la traza, miro los datos del keylogger en el campo Eventos genéricos (los eventos son emitidos por UIforETW y cada uno es un rombo púrpura en la captura de pantalla a continuación), e inmediatamente veo dónde ocurrió el bloqueo, con lo que la falla en el uso de la CPU se correlaciona claramente:



Ok, pero ¿por qué se detuvo Chrome? Aquí hay algunos consejos: las capturas de pantalla no muestran que cada vez que WmiPrvSE.exe utilice completamente el hyperthread de la CPU. Pero eso no debería importar. Mi máquina tiene 24 núcleos / 48 subprocesos, por lo que consumir un hiperproceso significa que el sistema todavía es 98% libre.

Luego me acerqué a un período claramente importante cuando Chrome estaba inactivo, y examiné, en particular, el proceso CrRendererMain en chrome.exe (27368), correspondiente a la pestaña Gmail.

Nota: Quiero agradecerme a mí mismo desde 2015 por pedirle a Microsoft que mejore los mecanismos de nombres de flujo, y gracias a Microsoft por implementar todas las sugerencias: ¡los nombres de hilos en WPA son simplemente geniales!

El problema se solucionó. Durante un bloqueo de 2.81 segundos, este hilo se inició en un horario 440 veces. Por lo general, comenzar cada 6 ms es suficiente para que el programa responda, pero por alguna razón esto no sucedió. Me di cuenta de que cada vez que se despertaba, estaba en la misma pila. Para simplificar:

chrome_child.dll (stack base)
KernelBase.dll!VirtualAlloc
ntoskrnl.exe!MiCommitVadCfgBits
ntoskrnl.exe!MiPopulateCfgBitMap
ntoskrnl.exe!ExAcquirePushLockExclusiveEx
ntoskrnl.exe!KeWaitForSingleObject (stack leaf)

Chrome VirtualAlloc, “CfgBits” . , Chrome VirtualAlloc 440 , . . Chrome VirtualAlloc — . Chrome ,  — 439  — Chrome , . , .

Windows — , , . . .

, Chrome , WmiPrvSE., :

ntoskrnl.exe!KiSystemServiceCopyEnd (stack base)
ntoskrnl.exe!NtQueryVirtualMemory
ntoskrnl.exe!MmQueryVirtualMemory
ntoskrnl.exe!MiUnlockAndDereferenceVad
ntoskrnl.exe!ExfTryToWakePushLock (stack leaf)

WMI ( ), WMI. CPU, , WmiPrvSE.exe ( ):

WmiPerfClass.dll!EnumSelectCounterObjects (stack base)
WmiPerfClass.dll!ConvertCounterPath
pdh.dll!PdhiTranslateCounter
pdh.dll!GetSystemPerfData
KernelBase.dll!blah-blah-blah
advapi32.dll!blah-blah-blah
perfproc.dll!blah-blah-blah
perfproc.dll!GetProcessVaData
ntdll.dll!NtQueryVirtualMemory
ntoskrnl.exe!NtQueryVirtualMemory
ntoskrnl.exe!MmQueryVirtualMemory
ntoskrnl.exe!MiQueryAddressSpan
ntoskrnl.exe!MiQueryAddressState
ntoskrnl.exe!MiGetNextPageTable (stack leaf)

. NtQueryVirtualMemory, GetProcessVaData, Va, , . VirtualScan NtQueryVirtualMemory , Gmail (10-15 ) — . ?

, . NtQueryVirtualMemory . « », « » .. Gmail 26 000 , ( , WPA) 16 000 , .

- Gmail vmmap , Gmail (361 836 ) (49 719), — 2 147 483 648 , 2 . ?



, 2 Control Flow Guard (CFG), , “CFG” , Gmail Chrome — MiCommitVadCfgBits. , CFG !

Control Flow Guard (CFG) . , 128- . , CFG ( 2 ), . CFG , CFG . 98 24 866 CFG-. :

      Scan time,  Committed, page tables, committed blocks
Total: 41.763s, 1457.7 MiB,    67.7 MiB,  32112, 98 code blocks
CFG: 41.759s,  353.3 MiB,    59.2 MiB,  24866

vmmap ,  — vmmap 49 684 , 24 866

, CFG ? CFG , ? .


— VAllocStress, . 64- CFG, , , , . , / , , . VAllocStress:

  1. :
    • VirtualAlloc .
    • .
  2. :
    • 500 ( ).
    • VirtualAlloc .
    • , VirtualAlloc ~500 
    • .

. . , . , VirtualScan VAllocStress. , CFG , . VAllocStress !

CFG, . !


, JavaScript- v8 CodeRange , CodeRange 128 . , , CFG, .

, CodeRange, , ? CodeRange, Gmail — . ( ) CodeRange. , WorkerThread::Start . :

  1. Gmail -, , .
  2. , -.
  3. CodeRange, JITted- JavaScript 47- .
  4. CFG 2 .
  5. CFG .
  6. NtQueryVirtualMemory CFG ( 1  ) , .

CFG Windows 10 RS4 ( 2018 ), , . , .


CFG  — . CFG , . . , CFG ! , . CFG . , 2 !

, — Gmail 353,3  CFG 59,2  , 400 . - , .


v8 ( JavaScript Chrome) , CodeRange, . Microsoft CFG. , - Microsoft CFG , , , . vmmap .

. :

  • Gmail.
  • Windows 10.
  • IT- WMI- .
  • .
  • .

, , , . , , , , .

, 10:30 , IT- . , Control PanelConfiguration ManagerActions, Hardware Inventory Cycle Run Now.




, VAllocStress VirtualScan Github.


. ( ), (), ( WMI). vmmap. — — crbug.com/870054.

UPD.

Source: https://habr.com/ru/post/es420579/


All Articles