diff options
author | Jan Kotas <jkotas@microsoft.com> | 2015-10-29 19:09:52 -0700 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2015-10-29 19:09:52 -0700 |
commit | a8192fbc7064ed96cfeb8872bcb6479c217f7b5f (patch) | |
tree | 738c092202d3ce5c7ed4ec08114c3c41b7b005d8 /src/ToolBox/SOS | |
parent | 3c50dec5796206c6042fd6adc3133a0ad22649e5 (diff) | |
download | coreclr-a8192fbc7064ed96cfeb8872bcb6479c217f7b5f.tar.gz coreclr-a8192fbc7064ed96cfeb8872bcb6479c217f7b5f.tar.bz2 coreclr-a8192fbc7064ed96cfeb8872bcb6479c217f7b5f.zip |
Port .NET Framework 4.6.1 changes
Core runtime and GC changes from https://github.com/Microsoft/dotnet/blob/master/docs/releases/net461/dotnet461-changes.md that are not in CoreCLR yet
[tfs-changeset: 1543382]
Diffstat (limited to 'src/ToolBox/SOS')
-rw-r--r-- | src/ToolBox/SOS/Strike/eeheap.cpp | 9 | ||||
-rw-r--r-- | src/ToolBox/SOS/Strike/sos.def | 18 | ||||
-rw-r--r-- | src/ToolBox/SOS/Strike/strike.cpp | 296 |
3 files changed, 312 insertions, 11 deletions
diff --git a/src/ToolBox/SOS/Strike/eeheap.cpp b/src/ToolBox/SOS/Strike/eeheap.cpp index 4b4fa1716e..d9484d2a0a 100644 --- a/src/ToolBox/SOS/Strike/eeheap.cpp +++ b/src/ToolBox/SOS/Strike/eeheap.cpp @@ -537,11 +537,11 @@ void GCPrintLargeHeapSegmentInfo(const DacpGcHeapDetails &heap, DWORD_PTR &total void GCHeapInfo(const DacpGcHeapDetails &heap, DWORD_PTR &total_size) { GCPrintGenerationInfo(heap); - ExtOut(WIN64_8SPACES " segment " WIN64_8SPACES " begin " WIN64_8SPACES "allocated size\n"); + ExtOut("%" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s\n", "segment", "begin", "allocated", "size"); GCPrintSegmentInfo(heap, total_size); ExtOut("Large object heap starts at 0x%p\n", (ULONG64)heap.generation_table[GetMaxGeneration()+1].allocation_start); - ExtOut(WIN64_8SPACES " segment " WIN64_8SPACES " begin " WIN64_8SPACES "allocated size\n"); + ExtOut("%" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s %" POINTERSIZE "s\n", "segment", "begin", "allocated", "size"); GCPrintLargeHeapSegmentInfo(heap,total_size); } @@ -758,7 +758,7 @@ void GCGenUsageStats(TADDR start, TADDR end, const std::unordered_set<TADDR> &li { genUsage->freed += objSize; } - else if (liveObjs.find(taddrObj) == liveObjs.end()) + else if (!(liveObjs.empty()) && liveObjs.find(taddrObj) == liveObjs.end()) { genUsage->unrooted += objSize; } @@ -782,7 +782,8 @@ BOOL GCHeapUsageStats(const DacpGcHeapDetails& heap, BOOL bIncUnreachable, HeapU #ifndef FEATURE_PAL // this will create the bitmap of rooted objects only if bIncUnreachable is true GCRootImpl gcroot; - const std::unordered_set<TADDR> &liveObjs = gcroot.GetLiveObjects(); + std::unordered_set<TADDR> emptyLiveObjs; + const std::unordered_set<TADDR> &liveObjs = (bIncUnreachable ? gcroot.GetLiveObjects() : emptyLiveObjs); // 1a. enumerate all non-ephemeral segments while (taddrSeg != (TADDR)heap.generation_table[0].start_segment) diff --git a/src/ToolBox/SOS/Strike/sos.def b/src/ToolBox/SOS/Strike/sos.def index e7a7ff9c7a..94dd351a28 100644 --- a/src/ToolBox/SOS/Strike/sos.def +++ b/src/ToolBox/SOS/Strike/sos.def @@ -21,7 +21,15 @@ EXPORTS dumpdomain=DumpDomain #ifdef TRACE_GC DumpGCLog -#endif + dumpgclog=DumpGCLog + dlog=DumpGCLog +#endif + DumpGCData + dumpgcdata=DumpGCData + dgc=DumpGCData + DumpGCConfigLog + dumpgcconfiglog=DumpGCConfigLog + dclog=DumpGCConfigLog DumpHeap dumpheap=DumpHeap DumpIL @@ -168,6 +176,10 @@ EXPORTS filthint #endif +#ifdef FEATURE_PAL + SetClrDebugDll + UnloadClrDebugDll +#else _EFN_GetManagedExcepStack _EFN_GetManagedExcepStackW _EFN_GetManagedObjectFieldInfo @@ -194,6 +206,8 @@ EXPORTS procinfo=ProcInfo VerifyStackTrace WatsonBuckets +#endif // !FEATURE_PAL + #ifdef FEATURE_CORESYSTEM // Only documented for Apollo internal usage @@ -214,4 +228,4 @@ EXPORTS getCodeTypeFlags=GetCodeTypeFlags TraceToCode tracetocode=TraceToCode -#endif
\ No newline at end of file +#endif diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp index 2434345d3c..730850eeca 100644 --- a/src/ToolBox/SOS/Strike/strike.cpp +++ b/src/ToolBox/SOS/Strike/strike.cpp @@ -2083,7 +2083,7 @@ struct StackTraceElement #if defined(FEATURE_EXCEPTIONDISPATCHINFO) // TRUE if this element represents the last frame of the foreign // exception stack trace. - BOOL fIsLastFrameFromForeignStackTrace; + BOOL fIsLastFrameFromForeignStackTrace; #endif // defined(FEATURE_EXCEPTIONDISPATCHINFO) }; @@ -8431,7 +8431,6 @@ DECLARE_API (DumpGCLog) INIT_API_NODAC(); MINIDUMP_NOT_SUPPORTED(); - if (GetEEFlavor() == UNKNOWNEE) { ExtOut("CLR not loaded\n"); @@ -8446,7 +8445,6 @@ DECLARE_API (DumpGCLog) if (*args != 0) fileName = args; - // Try to find stress log symbols DWORD_PTR dwAddr = GetValueFromExpression(MAIN_CLR_MODULE_NAME_A "!SVR::gc_log_buffer"); moveN (dwAddr, dwAddr); @@ -8460,7 +8458,7 @@ DECLARE_API (DumpGCLog) return E_FAIL; } } - + ExtOut("Dumping GC log at %08x\n", dwAddr); g_bDacBroken = FALSE; @@ -8511,6 +8509,7 @@ DECLARE_API (DumpGCLog) DWORD dwWritten = 0; WriteFile (hGCLog, bGCLog, iRealLogSize + 1, &dwWritten, NULL); + Status = S_OK; exit: @@ -8529,9 +8528,296 @@ exit: return Status; } - #endif //TRACE_GC +DECLARE_API (DumpGCConfigLog) +{ + INIT_API(); +#ifdef GC_CONFIG_DRIVEN + MINIDUMP_NOT_SUPPORTED(); + + if (GetEEFlavor() == UNKNOWNEE) + { + ExtOut("CLR not loaded\n"); + return Status; + } + + const char* fileName = "GCConfigLog.txt"; + + while (isspace (*args)) + args ++; + + if (*args != 0) + fileName = args; + + if (!InitializeHeapData ()) + { + ExtOut("GC Heap not initialized yet.\n"); + return S_OK; + } + + BOOL fIsServerGC = IsServerBuild(); + + DWORD_PTR dwAddr = 0; + DWORD_PTR dwAddrOffset = 0; + + if (fIsServerGC) + { + dwAddr = GetValueFromExpression(MAIN_CLR_MODULE_NAME_A "!SVR::gc_config_log_buffer"); + dwAddrOffset = GetValueFromExpression(MAIN_CLR_MODULE_NAME_A "!SVR::gc_config_log_buffer_offset"); + } + else + { + dwAddr = GetValueFromExpression(MAIN_CLR_MODULE_NAME_A "!WKS::gc_config_log_buffer"); + dwAddrOffset = GetValueFromExpression(MAIN_CLR_MODULE_NAME_A "!WKS::gc_config_log_buffer_offset"); + } + + moveN (dwAddr, dwAddr); + moveN (dwAddrOffset, dwAddrOffset); + + if (dwAddr == 0) + { + ExtOut("Can't get either WKS or SVR GC's config log buffer"); + return E_FAIL; + } + + ExtOut("Dumping GC log at %08x\n", dwAddr); + + g_bDacBroken = FALSE; + + ExtOut("Attempting to dump GC log to file '%s'\n", fileName); + + Status = E_FAIL; + + HANDLE hGCLog = CreateFileA( + fileName, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hGCLog == INVALID_HANDLE_VALUE) + { + ExtOut("failed to create file: %d\n", GetLastError()); + goto exit; + } + + int iLogSize = (int)dwAddrOffset; + + BYTE* bGCLog = new NOTHROW BYTE[iLogSize]; + if (bGCLog == NULL) + { + ReportOOM(); + goto exit; + } + + memset (bGCLog, 0, iLogSize); + if (!SafeReadMemory(dwAddr, bGCLog, iLogSize, NULL)) + { + ExtOut("failed to read memory from %08x\n", dwAddr); + } + + SetFilePointer (hGCLog, 0, 0, FILE_END); + DWORD dwWritten = 0; + WriteFile (hGCLog, bGCLog, iLogSize, &dwWritten, NULL); + + Status = S_OK; + +exit: + + if (hGCLog != INVALID_HANDLE_VALUE) + { + CloseHandle (hGCLog); + } + + if (Status == S_OK) + ExtOut("SUCCESS: Stress log dumped\n"); + else if (Status == S_FALSE) + ExtOut("No Stress log in the image, no file written\n"); + else + ExtOut("FAILURE: Stress log not dumped\n"); + + return Status; +#else + ExtOut("Not implemented\n"); + return S_OK; +#endif //GC_CONFIG_DRIVEN +} + +#ifdef GC_CONFIG_DRIVEN +static const char * const str_interesting_data_points[] = +{ + "pre short", // 0 + "post short", // 1 + "merged pins", // 2 + "converted pins", // 3 + "pre pin", // 4 + "post pin", // 5 + "pre and post pin", // 6 + "pre short padded", // 7 + "post short padded", // 7 +}; + +static char* str_heap_compact_reasons[] = +{ + "low on ephemeral space", + "high fragmetation", + "couldn't allocate gaps", + "user specfied compact LOH", + "last GC before OOM", + "induced compacting GC", + "fragmented gen0 (ephemeral GC)", + "high memory load (ephemeral GC)", + "high memory load and frag", + "very high memory load and frag", + "no gc mode" +}; + +static BOOL gc_heap_compact_reason_mandatory_p[] = +{ + TRUE, //compact_low_ephemeral = 0, + FALSE, //compact_high_frag = 1, + TRUE, //compact_no_gaps = 2, + TRUE, //compact_loh_forced = 3, + TRUE, //compact_last_gc = 4 + TRUE, //compact_induced_compacting = 5, + FALSE, //compact_fragmented_gen0 = 6, + FALSE, //compact_high_mem_load = 7, + TRUE, //compact_high_mem_frag = 8, + TRUE, //compact_vhigh_mem_frag = 9, + TRUE //compact_no_gc_mode = 10 +}; + +static char* str_heap_expand_mechanisms[] = +{ + "reused seg with normal fit", + "reused seg with best fit", + "expand promoting eph", + "expand with a new seg", + "no memory for a new seg", + "expand in next full GC" +}; + +static char* str_bit_mechanisms[] = +{ + "using mark list", + "demotion" +}; + +static const char * const str_gc_global_mechanisms[] = +{ + "concurrent GCs", + "compacting GCs", + "promoting GCs", + "GCs that did demotion", + "card bundles", + "elevation logic" +}; + +void PrintInterestingGCInfo(DacpGCInterestingInfoData* dataPerHeap) +{ + ExtOut("Interesting data points\n"); + size_t* data = dataPerHeap->interestingDataPoints; + for (int i = 0; i < NUM_GC_DATA_POINTS; i++) + { + ExtOut("%20s: %d\n", str_interesting_data_points[i], data[i]); + } + + ExtOut("\nCompacting reasons\n"); + data = dataPerHeap->compactReasons; + for (int i = 0; i < MAX_COMPACT_REASONS_COUNT; i++) + { + ExtOut("[%s]%35s: %d\n", (gc_heap_compact_reason_mandatory_p[i] ? "M" : "W"), str_heap_compact_reasons[i], data[i]); + } + + ExtOut("\nExpansion mechanisms\n"); + data = dataPerHeap->expandMechanisms; + for (int i = 0; i < MAX_EXPAND_MECHANISMS_COUNT; i++) + { + ExtOut("%30s: %d\n", str_heap_expand_mechanisms[i], data[i]); + } + + ExtOut("\nOther mechanisms enabled\n"); + data = dataPerHeap->bitMechanisms; + for (int i = 0; i < MAX_GC_MECHANISM_BITS_COUNT; i++) + { + ExtOut("%20s: %d\n", str_bit_mechanisms[i], data[i]); + } +} +#endif //GC_CONFIG_DRIVEN + +DECLARE_API(DumpGCData) +{ + INIT_API(); + +#ifdef GC_CONFIG_DRIVEN + MINIDUMP_NOT_SUPPORTED(); + + if (!InitializeHeapData ()) + { + ExtOut("GC Heap not initialized yet.\n"); + return S_OK; + } + + DacpGCInterestingInfoData interestingInfo; + interestingInfo.RequestGlobal(g_sos); + for (int i = 0; i < MAX_GLOBAL_GC_MECHANISMS_COUNT; i++) + { + ExtOut("%-30s: %d\n", str_gc_global_mechanisms[i], interestingInfo.globalMechanisms[i]); + } + + ExtOut("\n[info per heap]\n"); + + if (!IsServerBuild()) + { + if (interestingInfo.Request(g_sos) != S_OK) + { + ExtOut("Error requesting interesting GC info\n"); + return E_FAIL; + } + + PrintInterestingGCInfo(&interestingInfo); + } + else + { + DWORD dwNHeaps = GetGcHeapCount(); + DWORD dwAllocSize; + if (!ClrSafeInt<DWORD>::multiply(sizeof(CLRDATA_ADDRESS), dwNHeaps, dwAllocSize)) + { + ExtOut("Failed to get GCHeaps: integer overflow\n"); + return Status; + } + + CLRDATA_ADDRESS *heapAddrs = (CLRDATA_ADDRESS*)alloca(dwAllocSize); + if (g_sos->GetGCHeapList(dwNHeaps, heapAddrs, NULL) != S_OK) + { + ExtOut("Failed to get GCHeaps\n"); + return Status; + } + + for (DWORD n = 0; n < dwNHeaps; n ++) + { + if (interestingInfo.Request(g_sos, heapAddrs[n]) != S_OK) + { + ExtOut("Heap %d: Error requesting interesting GC info\n", n); + return E_FAIL; + } + + ExtOut("--------info for heap %d--------\n", n); + PrintInterestingGCInfo(&interestingInfo); + ExtOut("\n"); + } + } + + return S_OK; +#else + ExtOut("Not implemented\n"); + return S_OK; +#endif //GC_CONFIG_DRIVEN +} + #ifndef FEATURE_PAL /**********************************************************************\ * Routine Description: * |