diff options
Diffstat (limited to 'src/ToolBox/SOS/Strike/stressLogDump.cpp')
-rw-r--r-- | src/ToolBox/SOS/Strike/stressLogDump.cpp | 549 |
1 files changed, 0 insertions, 549 deletions
diff --git a/src/ToolBox/SOS/Strike/stressLogDump.cpp b/src/ToolBox/SOS/Strike/stressLogDump.cpp deleted file mode 100644 index 756cc73f7b..0000000000 --- a/src/ToolBox/SOS/Strike/stressLogDump.cpp +++ /dev/null @@ -1,549 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// ==++== -// - -// -// ==--== - -#include "strike.h" -#include "util.h" -#include <stdio.h> -#include <ctype.h> - -#ifndef STRESS_LOG -#define STRESS_LOG -#endif // STRESS_LOG -#define STRESS_LOG_READONLY -#include "stresslog.h" - - -void GcHistClear(); -void GcHistAddLog(LPCSTR msg, StressMsg* stressMsg); - - -/*********************************************************************************/ -static const WCHAR* getTime(const FILETIME* time, __out_ecount (buffLen) WCHAR* buff, int buffLen) -{ - SYSTEMTIME systemTime; - static const WCHAR badTime[] = W("BAD TIME"); - - if (!FileTimeToSystemTime(time, &systemTime)) - return badTime; - -#ifdef FEATURE_PAL - int length = _snwprintf_s(buff, buffLen, _TRUNCATE, W("%02d:%02d:%02d"), systemTime.wHour, systemTime.wMinute, systemTime.wSecond); - if (length <= 0) - return badTime; -#else // FEATURE_PAL - static const WCHAR format[] = W("HH:mm:ss"); - - SYSTEMTIME localTime; - SystemTimeToTzSpecificLocalTime(NULL, &systemTime, &localTime); - - // we want a non null buff for the following - int ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &localTime, format, buff, buffLen); - if (ret == 0) - return badTime; -#endif // FEATURE_PAL else - - return buff; -} - -/*********************************************************************************/ -static inline __int64& toInt64(FILETIME& t) -{ - return *((__int64 *) &t); -} - -/*********************************************************************************/ -ThreadStressLog* ThreadStressLog::FindLatestThreadLog() const -{ - const ThreadStressLog* latestLog = 0; - for (const ThreadStressLog* ptr = this; ptr != NULL; ptr = ptr->next) - { - if (ptr->readPtr != NULL) - if (latestLog == 0 || ptr->readPtr->timeStamp > latestLog->readPtr->timeStamp) - latestLog = ptr; - } - return const_cast<ThreadStressLog*>(latestLog); -} - -const char *getFacilityName(DWORD_PTR lf) -{ - struct FacilityName_t { size_t lf; const char* lfName; }; - #define DEFINE_LOG_FACILITY(logname, value) {logname, #logname}, - static FacilityName_t facilities[] = - { - #include <loglf.h> - { LF_ALWAYS, "LF_ALWAYS" } - }; - static char buff[1024] = "`"; - if ( lf == LF_ALL ) - { - return "`ALL`"; - } - else - { - buff[1] = '\0'; - for ( int i = 0; i < 32; ++i ) - { - if ( lf & 0x1 ) - { - strcat_s ( buff, _countof(buff), &(facilities[i].lfName[3]) ); - strcat_s ( buff, _countof(buff), "`" ); - } - lf >>= 1; - } - return buff; - } -} - -/***********************************************************************************/ -/* recognize special pretty printing instructions in the format string */ -/* Note that this function might have side effect such that args array value might */ -/* be altered if format string contains %s */ -// TODO: This function assumes the pointer size of the target equals the pointer size of the host -// TODO: replace uses of void* with appropriate TADDR or CLRDATA_ADDRESS -void formatOutput(struct IDebugDataSpaces* memCallBack, ___in FILE* file, __inout __inout_z char* format, unsigned threadId, double timeStamp, DWORD_PTR facility, ___in void** args) -{ - fprintf(file, "%4x %13.9f : ", threadId, timeStamp); - fprintf(file, "%-20s ", getFacilityName ( facility )); - - CQuickBytes fullname; - char* ptr = format; - void** argsPtr = args; - const SIZE_T capacity_buff = 2048; - LPWSTR buff = (LPWSTR)alloca(capacity_buff * sizeof(WCHAR)); - static char formatCopy[256]; - - int iArgCount = 0; - - strcpy_s(formatCopy, _countof(formatCopy), format); - for(;;) - { - char c = *ptr++; - if (c == 0) - break; - if (c == '{') // Reverse the '{' 's because the log is displayed backwards - ptr[-1] = '}'; - else if (c == '}') - ptr[-1] = '{'; - else if (c == '%') - { - argsPtr++; // This format will consume one of the args - if (*ptr == '%') - { - ptr++; // skip the whole %% - --argsPtr; // except for a %% - } - else if (*ptr == 'p') - { // It is a %p - ptr++; - if (isalpha(*ptr)) - { // It is a special %p formatter - // Print the string up to that point - c = *ptr; - *ptr = 0; // Terminate the string temporarily - fprintf(file, format, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - *ptr = c; // Put it back - - // move the argument pointers past the part the was printed - format = ptr + 1; - args = argsPtr; - iArgCount = -1; - DWORD_PTR arg = DWORD_PTR(argsPtr[-1]); - - switch (c) - { - case 'M': // format as a method Desc - if (g_bDacBroken) - { - fprintf(file," (MethodDesc: %p)",arg); - } - else - { - if (!IsMethodDesc(arg)) - { - if (arg != 0) - fprintf(file, " (BAD Method)"); - } - else - { - DacpMethodDescData MethodDescData; - MethodDescData.Request(g_sos,(CLRDATA_ADDRESS)arg); - - static WCHAR wszNameBuffer[1024]; // should be large enough - if (g_sos->GetMethodDescName(arg, 1024, wszNameBuffer, NULL) != S_OK) - { - wcscpy_s(wszNameBuffer, _countof(wszNameBuffer), W("UNKNOWN METHODDESC")); - } - - wcscpy_s(buff, capacity_buff, wszNameBuffer); - fprintf(file, " (%S)", wszNameBuffer); - } - } - break; - - // fall through - case 'T': // format as a MethodTable - if (g_bDacBroken) - { - fprintf(file, "(MethodTable: %p)",arg); - } - else - { - if (arg & 3) - { - arg &= ~3; // GC steals the lower bits for its own use during GC. - fprintf(file, " Low Bit(s) Set"); - } - if (!IsMethodTable(arg)) - { - fprintf(file, " (BAD MethodTable)"); - } - else - { - NameForMT_s (arg, g_mdName, mdNameLen); - fprintf(file, " (%S)", g_mdName); - } - } - break; - - case 'V': - { // format as a C vtable pointer - char Symbol[1024]; - ULONG64 Displacement; - HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(arg), Symbol, 1024, NULL, &Displacement); - if (SUCCEEDED(hr) && Symbol[0] != '\0' && Displacement == 0) - fprintf(file, " (%s)", Symbol); - else - fprintf(file, " (Unknown VTable)"); - } - break; - case 'K': - { // format a frame in stack trace - char Symbol[1024]; - ULONG64 Displacement; - HRESULT hr = g_ExtSymbols->GetNameByOffset (TO_CDADDR(arg), Symbol, 1024, NULL, &Displacement); - if (SUCCEEDED (hr) && Symbol[0] != '\0') - { - fprintf (file, " (%s", Symbol); - if (Displacement) - { - fprintf (file, "+%#x", Displacement); - } - fprintf (file, ")"); - } - else - fprintf (file, " (Unknown function)"); - } - break; - default: - format = ptr; // Just print the character. - } - } - } - else if (*ptr == 's' || (*ptr == 'h' && *(ptr+1) == 's' && ++ptr)) - { - HRESULT hr; - - // need to _alloca, instead of declaring a local buffer - // since we may have more than one %s in the format - ULONG cbStrBuf = 256; - char* strBuf = (char *)_alloca(cbStrBuf); - - hr = memCallBack->ReadVirtual(TO_CDADDR((char* )args[iArgCount]), strBuf, cbStrBuf, 0); - if (hr != S_OK) - { - strcpy_s(strBuf, cbStrBuf, "(#Could not read address of string#)"); - } - - args[iArgCount] = strBuf; - } - else if (*ptr == 'S' || (*ptr == 'l' && *(ptr+1) == 's' && ++ptr)) - { - HRESULT hr; - - // need to _alloca, instead of declaring a local buffer - // since we may have more than one %s in the format - ULONG cbWstrBuf = 256 * sizeof(WCHAR); - WCHAR* wstrBuf = (WCHAR *)_alloca(cbWstrBuf); - - hr = memCallBack->ReadVirtual(TO_CDADDR((char* )args[iArgCount]), wstrBuf, cbWstrBuf, 0); - if (hr != S_OK) - { - wcscpy_s(wstrBuf, cbWstrBuf/sizeof(WCHAR), W("(#Could not read address of string#)")); - } - - args[iArgCount] = wstrBuf; - } - iArgCount++; - } - } - // Print anything after the last special format instruction. - fprintf(file, format, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - fprintf(file, "\n"); -} - -void __cdecl -vDoOut(BOOL bToConsole, FILE* file, PCSTR Format, ...) -{ - va_list Args; - - va_start(Args, Format); - - if (bToConsole) - { - g_ExtControl->OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args); - } - else - { - vfprintf(file, Format, Args); - } - - va_end(Args); -} - - -/*********************************************************************************/ -HRESULT StressLog::Dump(ULONG64 outProcLog, const char* fileName, struct IDebugDataSpaces* memCallBack) -{ - ULONG64 g_hThisInst; - BOOL bDoGcHist = (fileName == NULL); - FILE* file = NULL; - - // Fetch the circular buffer bookkeeping data - StressLog inProcLog; - HRESULT hr = memCallBack->ReadVirtual(UL64_TO_CDA(outProcLog), &inProcLog, sizeof(StressLog), 0); - if (hr != S_OK) - { - return hr; - } - if (inProcLog.logs.Load() == NULL || inProcLog.moduleOffset == 0) - { - ExtOut ( "----- No thread logs in the image: The stress log was probably not initialized correctly. -----\n"); - return S_FALSE; - } - - g_hThisInst = (ULONG64) inProcLog.moduleOffset; - - if (bDoGcHist) - { - GcHistClear(); - } - else - { - ExtOut("Writing to file: %s\n", fileName); - ExtOut("Stress log in module 0x%p\n", SOS_PTR(g_hThisInst)); - ExtOut("Stress log address = 0x%p\n", SOS_PTR(outProcLog)); - } - // Fetch the circular buffers for each thread into the 'logs' list - ThreadStressLog* logs = 0; - - CLRDATA_ADDRESS outProcPtr = TO_CDADDR(inProcLog.logs.Load()); - ThreadStressLog* inProcPtr; - ThreadStressLog** logsPtr = &logs; - int threadCtr = 0; - unsigned __int64 lastTimeStamp = 0;// timestamp of last log entry - - while(outProcPtr != 0) { - inProcPtr = new ThreadStressLog; - hr = memCallBack->ReadVirtual(outProcPtr, inProcPtr, sizeof (*inProcPtr), 0); - if (hr != S_OK || inProcPtr->chunkListHead == NULL) - { - delete inProcPtr; - goto FREE_MEM; - } - - CLRDATA_ADDRESS outProcListHead = TO_CDADDR(inProcPtr->chunkListHead); - CLRDATA_ADDRESS outProcChunkPtr = outProcListHead; - StressLogChunk ** chunksPtr = &inProcPtr->chunkListHead; - StressLogChunk * inProcPrevChunkPtr = NULL; - BOOL curPtrInitialized = FALSE; - do - { - StressLogChunk * inProcChunkPtr = new StressLogChunk; - hr = memCallBack->ReadVirtual (outProcChunkPtr, inProcChunkPtr, sizeof (*inProcChunkPtr), NULL); - if (hr != S_OK || !inProcChunkPtr->IsValid ()) - { - if (hr != S_OK) - ExtOut ("ReadVirtual failed with code hr = %x.\n", hr ); - else - ExtOut ("Invalid stress log chunk: %p", SOS_PTR(outProcChunkPtr)); - - // Now cleanup - delete inProcChunkPtr; - // if this is the first time through, inProcPtr->chunkListHead may still contain - // the out-of-process value for the chunk pointer. NULL it to avoid AVs - if (TO_CDADDR(inProcPtr->chunkListHead) == outProcListHead) - inProcPtr->chunkListHead = NULL; - delete inProcPtr; - goto FREE_MEM; - } - - if (!curPtrInitialized && outProcChunkPtr == TO_CDADDR(inProcPtr->curWriteChunk)) - { - inProcPtr->curPtr = (StressMsg *)((BYTE *)inProcChunkPtr + ((BYTE *)inProcPtr->curPtr - (BYTE *)inProcPtr->curWriteChunk)); - inProcPtr->curWriteChunk = inProcChunkPtr; - curPtrInitialized = TRUE; - } - - outProcChunkPtr = TO_CDADDR(inProcChunkPtr->next); - *chunksPtr = inProcChunkPtr; - chunksPtr = &inProcChunkPtr->next; - inProcChunkPtr->prev = inProcPrevChunkPtr; - inProcPrevChunkPtr = inProcChunkPtr; - - if (outProcChunkPtr == outProcListHead) - { - inProcChunkPtr->next = inProcPtr->chunkListHead; - inProcPtr->chunkListHead->prev = inProcChunkPtr; - inProcPtr->chunkListTail = inProcChunkPtr; - } - } while (outProcChunkPtr != outProcListHead); - - if (!curPtrInitialized) - { - delete inProcPtr; - goto FREE_MEM; - } - - // TODO: fix on 64 bit - inProcPtr->Activate (); - if (inProcPtr->readPtr->timeStamp > lastTimeStamp) - { - lastTimeStamp = inProcPtr->readPtr->timeStamp; - } - - outProcPtr = TO_CDADDR(inProcPtr->next); - *logsPtr = inProcPtr; - logsPtr = &inProcPtr->next; - threadCtr++; - } - - if (!bDoGcHist && ((file = fopen(fileName, "w")) == NULL)) - { - hr = GetLastError(); - goto FREE_MEM; - } - hr = S_FALSE; // return false if there are no message to print to the log - - vDoOut(bDoGcHist, file, "STRESS LOG:\n" - " facilitiesToLog = 0x%x\n" - " levelToLog = %d\n" - " MaxLogSizePerThread = 0x%x (%d)\n" - " MaxTotalLogSize = 0x%x (%d)\n" - " CurrentTotalLogChunk = %d\n" - " ThreadsWithLogs = %d\n", - inProcLog.facilitiesToLog, inProcLog.levelToLog, inProcLog.MaxSizePerThread, inProcLog.MaxSizePerThread, - inProcLog.MaxSizeTotal, inProcLog.MaxSizeTotal, inProcLog.totalChunk.Load(), threadCtr); - - FILETIME endTime; - double totalSecs; - totalSecs = ((double) (lastTimeStamp - inProcLog.startTimeStamp)) / inProcLog.tickFrequency; - toInt64(endTime) = toInt64(inProcLog.startTime) + ((__int64) (totalSecs * 1.0E7)); - - WCHAR timeBuff[64]; - vDoOut(bDoGcHist, file, " Clock frequency = %5.3f GHz\n", inProcLog.tickFrequency / 1.0E9); - vDoOut(bDoGcHist, file, " Start time %S\n", getTime(&inProcLog.startTime, timeBuff, 64)); - vDoOut(bDoGcHist, file, " Last message time %S\n", getTime(&endTime, timeBuff, 64)); - vDoOut(bDoGcHist, file, " Total elapsed time %5.3f sec\n", totalSecs); - - if (!bDoGcHist) - { - fprintf(file, "\nTHREAD TIMESTAMP FACILITY MESSAGE\n"); - fprintf(file, " ID (sec from start)\n"); - fprintf(file, "--------------------------------------------------------------------------------------\n"); - } - char format[257]; - format[256] = format[0] = 0; - void** args; - unsigned msgCtr; - msgCtr = 0; - for (;;) - { - ThreadStressLog* latestLog = logs->FindLatestThreadLog(); - - if (IsInterrupt()) - { - vDoOut(bDoGcHist, file, "----- Interrupted by user -----\n"); - break; - } - - if (latestLog == 0) - { - break; - } - - StressMsg* latestMsg = latestLog->readPtr; - if (latestMsg->formatOffset != 0 && !latestLog->CompletedDump()) - { - TADDR taFmt = (latestMsg->formatOffset) + TO_TADDR(g_hThisInst); - hr = memCallBack->ReadVirtual(TO_CDADDR(taFmt), format, 256, 0); - if (hr != S_OK) - strcpy_s(format, _countof(format), "Could not read address of format string"); - - double deltaTime = ((double) (latestMsg->timeStamp - inProcLog.startTimeStamp)) / inProcLog.tickFrequency; - if (bDoGcHist) - { - if (strcmp(format, ThreadStressLog::TaskSwitchMsg()) == 0) - { - latestLog->threadId = (unsigned)(size_t)latestMsg->args[0]; - } - GcHistAddLog(format, latestMsg); - } - else - { - if (strcmp(format, ThreadStressLog::TaskSwitchMsg()) == 0) - { - fprintf (file, "Task was switched from %x\n", (unsigned)(size_t)latestMsg->args[0]); - latestLog->threadId = (unsigned)(size_t)latestMsg->args[0]; - } - else - { - args = latestMsg->args; - formatOutput(memCallBack, file, format, (unsigned)latestLog->threadId, deltaTime, latestMsg->facility, args); - } - } - msgCtr++; - } - - latestLog->readPtr = latestLog->AdvanceRead(); - if (latestLog->CompletedDump()) - { - latestLog->readPtr = NULL; - if (!bDoGcHist) - { - fprintf(file, "------------ Last message from thread %x -----------\n", latestLog->threadId); - } - } - - if (msgCtr % 64 == 0) - { - ExtOut("."); // to indicate progress - if (msgCtr % (64*64) == 0) - ExtOut("\n"); - } - } - ExtOut("\n"); - - vDoOut(bDoGcHist, file, "---------------------------- %d total entries ------------------------------------\n", msgCtr); - if (!bDoGcHist) - { - fclose(file); - } - -FREE_MEM: - // clean up the 'logs' list - while (logs) { - ThreadStressLog* temp = logs; - logs = logs->next; - delete temp; - } - - return hr; -} - |