Improve performance of !dumpasync SOS command
authorStephen Toub <stoub@microsoft.com>
Sat, 25 May 2019 02:06:37 +0000 (22:06 -0400)
committerStephen Toub <stoub@microsoft.com>
Tue, 28 May 2019 10:05:33 +0000 (06:05 -0400)
A significant majority of the time spent in dumpasync was in getting the type name of each object in order to compare it to "AsyncStateMachineBox".  This switches to comparing by module and mdTypeDef.  On an ~1GB dump, the time to execute !dumpasync dropped from 43 to 11 seconds on my machine.

Commit migrated from https://github.com/dotnet/coreclr/commit/25878db0c11bfb8d52088c75ccfcc13e4c8383f2

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

index 3e4f166..ed9b4cf 100644 (file)
@@ -4431,6 +4431,24 @@ void ExtOutStateMachineFields(AsyncRecord& ar)
     }
 }
 
+void FindStateMachineTypes(DWORD_PTR* corelibModule, mdTypeDef* stateMachineBox, mdTypeDef* debugStateMachineBox)
+{
+    int numModule;
+    ArrayHolder<DWORD_PTR> moduleList = ModuleFromName(const_cast<LPSTR>("System.Private.CoreLib.dll"), &numModule);
+    if (moduleList != NULL && numModule == 1)
+    {
+        *corelibModule = moduleList[0];
+        GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1", stateMachineBox);
+        GetInfoFromName(*corelibModule, "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+DebugFinalizableAsyncStateMachineBox`1", debugStateMachineBox);
+    }
+    else
+    {
+        *corelibModule = 0;
+        *stateMachineBox = 0;
+        *debugStateMachineBox = 0;
+    }
+}
+
 DECLARE_API(DumpAsync)
 {
     INIT_API();
@@ -4494,6 +4512,11 @@ DECLARE_API(DumpAsync)
             DisplayInvalidStructuresMessage();
         }
 
+        // Find the state machine types
+        DWORD_PTR corelibModule;
+        mdTypeDef stateMachineBoxMd, debugStateMachineBoxMd;
+        FindStateMachineTypes(&corelibModule, &stateMachineBoxMd, &debugStateMachineBoxMd);
+
         // 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.
         std::map<CLRDATA_ADDRESS, AsyncRecord> asyncRecords;
@@ -4519,8 +4542,10 @@ DECLARE_API(DumpAsync)
             {
                 // Otherwise, we only care about AsyncStateMachineBox`1 as well as the DebugFinalizableAsyncStateMachineBox`1
                 // that's used when certain ETW events are set.
-                if (_wcsncmp(itr->GetTypeName(), W("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1"), 79) != 0 &&
-                    _wcsncmp(itr->GetTypeName(), W("System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+DebugFinalizableAsyncStateMachineBox`1"), 95) != 0)
+                DacpMethodTableData mtdata;
+                if (mtdata.Request(g_sos, TO_TADDR(itr->GetMT())) != S_OK ||
+                    mtdata.Module != corelibModule ||
+                    (mtdata.cl != stateMachineBoxMd && mtdata.cl != debugStateMachineBoxMd))
                 {
                     continue;
                 }
index 9ff51d4..880c565 100644 (file)
@@ -2839,8 +2839,12 @@ Failure:
 *    Find the EE data given a name.                                    *  
 *                                                                      *
 \**********************************************************************/
-void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
+void GetInfoFromName(DWORD_PTR ModulePtr, const char* name, mdTypeDef* retMdTypeDef)
 {
+    DWORD_PTR ignoredModuleInfoRet = NULL;
+    if (retMdTypeDef)
+        *retMdTypeDef = 0;
+
     ToRelease<IMetaDataImport> pImport = MDImportForModule (ModulePtr);    
     if (pImport == 0)
         return;
@@ -2865,13 +2869,13 @@ void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
             BOOL fStatus = FALSE;
             while (ModuleDefinition->EnumMethodDefinitionByName(&h, &pMeth) == S_OK)
             {
-                if (fStatus)
+                if (fStatus && !retMdTypeDef)
                     ExtOut("-----------------------\n");
 
                 mdTypeDef token;
                 if (pMeth->GetTokenAndScope(&token, NULL) == S_OK)
                 {
-                    GetInfoFromModule(ModulePtr, token);
+                    GetInfoFromModule(ModulePtr, token, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
                     fStatus = TRUE;
                 }
                 pMeth->Release();
@@ -2900,7 +2904,10 @@ void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
     // @todo:  Handle Nested classes correctly.
     if (SUCCEEDED (pImport->FindTypeDefByName (pName, tkEnclose, &cl)))
     {
-        GetInfoFromModule(ModulePtr, cl);
+        if (retMdTypeDef)
+            *retMdTypeDef = cl;
+        
+        GetInfoFromModule(ModulePtr, cl, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
         return;
     }
     
@@ -2917,6 +2924,9 @@ void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
     // @todo:  Handle Nested classes correctly.
     if (SUCCEEDED(pImport->FindTypeDefByName (pName, tkEnclose, &cl)))
     {
+        if (retMdTypeDef)
+            *retMdTypeDef = cl;
+
         mdMethodDef token;
         ULONG cTokens;
         HCORENUM henum = NULL;
@@ -2927,8 +2937,8 @@ void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
                                                      &token, 1, &cTokens))
             && cTokens == 1)
         {
-            ExtOut("Member (mdToken token) of\n");
-            GetInfoFromModule(ModulePtr, cl);
+            if (!retMdTypeDef) ExtOut("Member (mdToken token) of\n");
+            GetInfoFromModule(ModulePtr, cl, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
             return;
         }
 
@@ -2938,8 +2948,8 @@ void GetInfoFromName(DWORD_PTR ModulePtr, const char* name)
                                                      &token, 1, &cTokens))
             && cTokens == 1)
         {
-            ExtOut("Field (mdToken token) of\n");
-            GetInfoFromModule(ModulePtr, cl);
+            if (!retMdTypeDef) ExtOut("Field (mdToken token) of\n");
+            GetInfoFromModule(ModulePtr, cl, retMdTypeDef ? &ignoredModuleInfoRet : NULL);
             return;
         }
     }
index 4303663..55c822e 100644 (file)
@@ -1862,7 +1862,7 @@ BOOL TryGetMethodDescriptorForDelegate(CLRDATA_ADDRESS delegateAddr, CLRDATA_ADD
  *      ArrayHolder class.
  */
 DWORD_PTR *ModuleFromName(__in_opt LPSTR name, int *numModules);
-void GetInfoFromName(DWORD_PTR ModuleAddr, const char* name);
+void GetInfoFromName(DWORD_PTR ModuleAddr, const char* name, mdTypeDef* retMdTypeDef=NULL);
 void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret=NULL);