Improve perf of `!dumpasync -tasks` (#294)
authorStephen Toub <stoub@microsoft.com>
Fri, 31 May 2019 22:11:23 +0000 (18:11 -0400)
committerGitHub <noreply@github.com>
Fri, 31 May 2019 22:11:23 +0000 (18:11 -0400)
When the `-tasks` flag is set, we look at every object on the heap and walk its hierarchy to decide if it's a task or a task-derived type.  But we currently do that by comparing the name of every object against "System.Threading.Tasks.Task", which is very expensive.  This switches to comparing by module and type def.  On my machine, a `!dumpasync -tasks` command that previously took ~1 minute now takes ~30 seconds.

src/SOS/Strike/strike.cpp
src/SOS/Strike/util.cpp
src/SOS/Strike/util.h

index 2c8f1e7486c8cd99f4af8736850fc533577c4f56..6738487dfc9b052ea1d400e4ab932d7191e38d2c 100644 (file)
@@ -4428,7 +4428,7 @@ void ExtOutStateMachineFields(AsyncRecord& ar)
        }
 }
 
-void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox, mdTypeDef* debugStateMachineBox)
+void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox, mdTypeDef* debugStateMachineBox, mdTypeDef* task)
 {
     int numModule;
     ArrayHolder<DWORD_PTR> moduleList = ModuleFromName(const_cast<LPSTR>("System.Private.CoreLib.dll"), &numModule);
@@ -4437,6 +4437,7 @@ void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox,
         *corelibModule = moduleList[0];
         GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1", stateMachineBox);
         GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+DebugFinalizableAsyncStateMachineBox`1", debugStateMachineBox);
+        GetInfoFromName(*corelibModule, "System.Threading.Tasks.Task", task);
     }
     else
     {
@@ -4511,8 +4512,8 @@ DECLARE_API(DumpAsync)
 
         // Find the state machine types
         DWORD_PTR corelibModule;
-        mdTypeDef stateMachineBoxMd, debugStateMachineBoxMd;
-        FindStateMachineTypes(&corelibModule, &stateMachineBoxMd, &debugStateMachineBoxMd);
+        mdTypeDef stateMachineBoxMd, debugStateMachineBoxMd, taskMd;
+        FindStateMachineTypes(&corelibModule, &stateMachineBoxMd, &debugStateMachineBoxMd, &taskMd);
 
         // Walk each heap object looking for async state machine objects.  As we're targeting .NET Core 2.1+, all such objects
         // will be Task or Task-derived types.
@@ -4530,7 +4531,7 @@ DECLARE_API(DumpAsync)
             {
                 // If the user has selected to include all tasks and not just async state machine boxes, we simply need to validate
                 // that this is Task or Task-derived, and if it's not, skip it.
-                if (!IsDerivedFrom(itr->GetMT(), W("System.Threading.Tasks.Task")))
+                if (!IsDerivedFrom(itr->GetMT(), corelibModule, taskMd))
                 {
                     continue;
                 }
index 03f618d78dd750d3648c1827a8b706a934e5e0e4..f45ecc08029f2d9ed8989f73dbc66c353f501bfc 100644 (file)
@@ -2152,6 +2152,23 @@ BOOL IsDerivedFrom(CLRDATA_ADDRESS mtObj, __in_z LPCWSTR baseString)
     return FALSE;
 }
 
+BOOL IsDerivedFrom(CLRDATA_ADDRESS mtObj, DWORD_PTR modulePtr, mdTypeDef typeDef)
+{
+    DacpMethodTableData dmtd;
+    
+    for (CLRDATA_ADDRESS walkMT = mtObj;
+         walkMT != NULL && dmtd.Request(g_sos, walkMT) == S_OK;
+         walkMT = dmtd.ParentMethodTable)
+    {
+        if (dmtd.Module == modulePtr && dmtd.cl == typeDef)
+        {
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 BOOL TryGetMethodDescriptorForDelegate(CLRDATA_ADDRESS delegateAddr, CLRDATA_ADDRESS* pMD)
 {
     if (!sos::IsObject(delegateAddr, false))
index f32e4cefc204f0e3c710264d5614c10106fd1846..944dfcb787467015b2483e31ab9dcfd92ba8de9d 100644 (file)
@@ -1850,6 +1850,7 @@ BOOL IsStringObject (size_t obj);
 BOOL IsObjectArray (DWORD_PTR objPointer);
 BOOL IsObjectArray (DacpObjectData *pData);
 BOOL IsDerivedFrom(CLRDATA_ADDRESS mtObj, __in_z LPCWSTR baseString);
+BOOL IsDerivedFrom(CLRDATA_ADDRESS mtObj, DWORD_PTR modulePtr, mdTypeDef typeDef);
 BOOL TryGetMethodDescriptorForDelegate(CLRDATA_ADDRESS delegateAddr, CLRDATA_ADDRESS* pMD);
 
 #ifdef FEATURE_PAL