Aplicación xperf WinDBG C#.NET 4.5.2: comprensión del volcado del proceso
jit (2)
Bajo una carga pesada, nuestra aplicación está haciendo que un servidor robusto use 100% de CPU. Leyendo el volcado del proceso, mirando los subprocesos, algunos de ellos tienen 10 minutos. Ninguno de ellos me da una idea cuando uso! CLRStack.
El fugitivo me está dando:
0:030> !runaway
User Mode Time
Thread Time
53:2e804 0 days 0:10:04.703
30:31894 0 days 0:07:51.593
33:47100 0 days 0:07:24.890
42:11e54 0 days 0:06:45.875
35:35e18 0 days 0:06:07.578
41:54464 0 days 0:05:49.796
47:57700 0 days 0:05:45.000
44:3c2d4 0 days 0:05:44.265
32:3898c 0 days 0:05:43.593
50:54894 0 days 0:05:41.968
51:5bc58 0 days 0:05:40.921
43:14af4 0 days 0:05:40.734
48:35074 0 days 0:05:40.406
...
Llamando! DumpStack en uno de esos hilos, obtengo:
0000001ab442f900 00007ff9ef4c1148 KERNELBASE!WaitForSingleObjectEx+0x94, calling ntdll!NtWaitForSingleObject
0000001ab442f980 00007ff9e920beb2 clr!SVR::gc_heap::compute_new_dynamic_data+0x17b, calling clr!SVR::gc_heap::desired_new_allocation
0000001ab442f9a0 00007ff9e90591eb clr!CLREventWaitHelper2+0x38, calling kernel32!WaitForSingleObjectEx
0000001ab442f9b0 00007ff9e90e0d2c clr!WriteBarrierManager::UpdateEphemeralBounds+0x1c, calling clr!WriteBarrierManager::NeedDifferentWriteBarrier
0000001ab442f9e0 00007ff9e9059197 clr!CLREventWaitHelper+0x1f, calling clr!CLREventWaitHelper2
0000001ab442fa40 00007ff9e9059120 clr!CLREventBase::WaitEx+0x70, calling clr!CLREventWaitHelper
0000001ab442fa70 00007ff9ef4c149c KERNELBASE!SetEvent+0xc, calling ntdll!NtSetEvent
0000001ab442faa0 00007ff9e90ef1e1 clr!SVR::gc_heap::set_gc_done+0x22, calling clr!CLREventBase::Set
0000001ab442fad0 00007ff9e90e9331 clr!SVR::gc_heap::gc_thread_function+0x8a, calling clr!CLREventBase::WaitEx
0000001ab442fb00 00007ff9e92048e7 clr!SVR::gc_heap::gc_thread_stub+0x7a, calling clr!SVR::gc_heap::gc_thread_function
0000001ab442fb60 00007ff9e91a0318 clr!Thread::CLRSetThreadStackGuarantee+0x48, calling kernel32!SetThreadStackGuaranteeStub
0000001ab442fb90 00007ff9e91a01ef clr!Thread::CommitThreadStack+0x10, calling clr!Thread::CLRSetThreadStackGuarantee
0000001ab442fbd0 00007ff9e910df0b clr!ClrFlsSetValue+0x57, calling kernel32!SetLastErrorStub
0000001ab442fc00 00007ff9e92048dc clr!SVR::gc_heap::gc_thread_stub+0x6f, calling clr!_chkstk
0000001ab442fc40 00007ff9f0d316ad kernel32!BaseThreadInitThunk+0xd
0000001ab442fc70 00007ff9f1e54409 ntdll!RtlUserThreadStart+0x1d
Que me esta diciendo Veo muchas llamadas al CLR, pero no puedo entender dónde estaría el problema. Después del .reload (sugerido por Thomas) ahora puedo ver las llamadas del GC.
Actualización 1
Después de ejecutar xperf, cada w3wp.exe consume algo alrededor del 45% de la CPU. Filtrando por uno de ellos y agrupando por Función, hay una función etiquetada como "?" eso es responsable del 13.62%, los otros son 2.67% o menos. ¿Cómo consigo saber qué es este "?"
Actualización 2
Ejecutó xperf nuevamente y la función
JIT_MonEnterWorker_InlineGetThread_GetThread_PatchLabel
es responsable del 12.31% del uso de la CPU.
Los "?"
La función aún permanece allí.
Agrupación por pila:
Line #, Stack, Count, Weight (in view), TimeStamp, % Weight
2, |- ?!?, 501191, 501222.365294, , 35.51
3, | |- clr.dll!JITutil_MonContention, 215749, 215752.552227, , 15.28
4, | |- clr.dll!JIT_MonEnterWorker_InlineGetThread_GetThread_PatchLabel, 170804, 170777.100191, , 12.10
Como puede ver, esos dos son responsables de más del 27% del uso de la CPU (para cada proceso, por lo que es significativo).
Actualización 3
Después de usar wpr.exe (sugerencia de @ magicandre1981):
wpr.exe -start cpu and wpr -stop result.etl
Descubrí que FormsAuthentication y algunas llamadas innecesarias a Ninject en la ruta crítica estaban contribuyendo a alrededor del 16% del uso de la CPU. Todavía no entiendo los hilos que corren gor 10 minutos o más.
Actualización 4
Intenté DebugDiag (sugerencia de @leppie) y simplemente confirmó que los hilos colgados son todos similares a:
Thread ID: 53 Total CPU Time: 00:09:11.406 Entry Point for Thread: clr!Thread::intermediateThreadProc
Thread ID: 35 Total CPU Time: 00:07:26.046 Entry Point for Thread: clr!SVR::gc_heap::gc_thread_stub
Thread ID: 50 Total CPU Time: 00:07:01.515 Entry Point for Thread: clr!SVR::gc_heap::gc_thread_stub
Thread ID: 29 Total CPU Time: 00:06:02.264 Entry Point for Thread: clr!SVR::gc_heap::gc_thread_stub
Thread ID: 31 Total CPU Time: 00:06:41.281 Entry Point for Thread: clr!SVR::gc_heap::gc_thread_stub
o debido a StackExchange.Redis:
DomainBoundILStubClass.IL_STUB_PInvoke(Int32, IntPtr[], IntPtr[], IntPtr[], TimeValue ByRef)+e1
[[InlinedCallFrame] (StackExchange.Redis.SocketManager.select)] StackExchange.Redis.SocketManager.select(Int32, IntPtr[], IntPtr[], IntPtr[], TimeValueByRef)
StackExchange.Redis.SocketManager.ReadImpl()+889
StackExchange.Redis.SocketManager.Read()+66
o
[[GCFrame]]
[[HelperMethodFrame_1OBJ] (System.Threading.Monitor.ObjWait)] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
mscorlib_ni!System.Threading.Monitor.Wait(System.Object, Int32)+19
StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[[System.__Canon, mscorlib]](StackExchange.Redis.Message, StackExchange.Redis.ResultProcessor`1, StackExchange.Redis.ServerEndPoint)+24f
StackExchange.Redis.RedisBase.ExecuteSync[[System.__Canon, mscorlib]](StackExchange.Redis.Message, StackExchange.Redis.ResultProcessor`1, StackExchange.Redis.ServerEndPoint)+77
[[StubHelperFrame]]
StackExchange.Redis.RedisDatabase.SetMembers(StackExchange.Redis.RedisKey, StackExchange.Redis.CommandFlags)+ee
Hacer esto a mano necesita valentía;) Por favor revise este MS DebugDiag 2.2 oficial : https://www.microsoft.com/en-us/download/details.aspx?id=49924 ha venido con un analizador para que no tenga que ver con tu mano Con DebugDiag , creo que encontrará su problema más rápido que nunca ...
La aplicación lenta, podría ser del código lento O tal vez sucede desde el motor .NET
al principio, si había comprobado el clr.dll si tiene problemas, puede descargarlo y reemplazarlo en su computadora. De lo contrario, si no tiene ningún problema. Intente esto
Creo que deberías revisar los códigos de tus aplicaciones, seleccionar cada rincón que requiere mucho proceso e intentar equilibrar la carga de operaciones de código entre la CPU y la RAM. bucles, inicialización de objetos o funciones de recursión, etc. todo se carga en la CPU Intenta almacenar los objetos de fragmento en estática o constante