/*++ Copyright (c) 1995 Microsoft Corporation Module Name: reducer.c Abstract: Trace Reducer Tool Author: 08-Apr-1998 mraghu Revision History: --*/ #ifdef __cplusplus extern "C"{ #endif #define _UNICODE #define UNICODE #include #include #include #include #include #include "pdhp.h" #define MAXSTR 1024 #define MAXLOGFILES 16 #define MAX_BUFFER_SIZE 1048576 #if DBG ULONG ETAAPITestFlag = 1; VOID TestETAApis( PTRACE_BASIC_INFO TraceBasicInfo ); #endif void ReducerUsage() { printf("Usage: reducer [Options] | [-h | -help | -?]\n"); printf("\t-out Output file name. Default is Workload.txt\n"); printf("\t-h \n"); printf("\t-help \n"); printf("\t-? Display usage information\n"); // printf("\t-start Start Time\n"); // printf("\t-end End Time\n"); // printf("\t can be found in tracedmp result\n"); // printf("\n"); // printf("\t-base Original reducer report (default report)\n"); // printf("\t-file Hot File Report\n"); // printf("\t-pf page fault report\n"); // printf("\t -summary processes summary of faults per process (default PF report).\n"); // printf("\t modules summary of faults per module.\n"); // printf("\t -process rundown for specific process.\n"); // printf("\t all\n"); // printf("\t -module rundown for specific modules.\n"); // printf("\t all\n"); // printf("\t -sort ALL sort by all fault total.\n"); // printf("\t HPF sort by HPF fault total.\n"); // printf("\t TF sort by TF fault total.\n"); // printf("\t DZF sort by DZF fault total.\n"); // printf("\t COW sort by COW fault total.\n"); // printf("\n"); // printf("\tNote: (1) Cannot generate HotFile Report and PageFault Report\n"); // printf("\t at the same time\n"); // printf("\t0x%08X,%d,\n", STATUS_SEVERITY_WARNING, RtlNtStatusToDosError(STATUS_SEVERITY_WARNING)); } ULONGLONG ParseTimeString(TCHAR * strTime) { #if 0 CHAR lstrTime[25]; PCHAR strYear, strMonth, strDate, strHour, strMinute, strSecond, strMilliSecond; LARGE_INTEGER largeTime; FILETIME localTime, stdTime; SYSTEMTIME sysTime; if (strTime == NULL) return (ULONGLONG) 0; strcpy(lstrTime, strTime); strMonth = lstrTime; for (strDate = strMonth; *strDate && *strDate >= '0' && *strDate <= '9'; strDate ++); *strDate = '\0'; strDate ++; for (strYear = strDate; *strYear && *strYear >= '0' && *strYear <= '9'; strYear ++); *strYear = '\0'; strYear ++; for (strHour = strYear; *strHour && *strHour >= '0' && *strHour <= '9'; strHour ++); *strHour = '\0'; strHour ++; for (strMinute = strHour; *strMinute && *strMinute >= '0' && *strMinute <= '9'; strMinute ++); *strMinute = '\0'; strMinute ++; for (strSecond = strMinute; *strSecond && *strSecond >= '0' && *strSecond <= '9'; strSecond ++); *strSecond = '\0'; strSecond ++; for (strMilliSecond = strSecond; *strMilliSecond && *strMilliSecond >= '0' && *strMilliSecond <= '9'; strMilliSecond ++); *strMilliSecond = '\0'; strMilliSecond ++; sysTime.wYear = atoi(strYear); sysTime.wMonth = atoi(strMonth); sysTime.wDay = atoi(strDate); sysTime.wHour = atoi(strHour); sysTime.wMinute = atoi(strMinute); sysTime.wSecond = atoi(strSecond); sysTime.wMilliseconds = atoi(strMilliSecond); SystemTimeToFileTime(&sysTime, &localTime); LocalFileTimeToFileTime(&localTime, &stdTime); largeTime.HighPart = stdTime.dwHighDateTime; largeTime.LowPart = stdTime.dwLowDateTime; return (ULONGLONG) largeTime.QuadPart; #else ULONGLONG TimeStamp = 0; ULONG i = 0; for (i = 0; strTime[i] != '\0'; i ++) { TimeStamp = TimeStamp * 10 + (strTime[i] - '0'); } return TimeStamp; #endif } VOID ProcessTrace( IN ULONG LogFileCount, IN LPCTSTR * LogFileName, IN ULONGLONG StartTime, IN ULONGLONG EndTime, IN ULONGLONG DSStartTime, IN ULONGLONG DSEndTime, IN ULONG MoreFlags, IN PVOID pUserContext, IN LPCTSTR pOutFileName ) { // Call TraceLib and process it. // TRACE_BASIC_INFO TraceBasicInfo; memset(&TraceBasicInfo, 0, sizeof(TRACE_BASIC_INFO)); TraceBasicInfo.Flags = TRACE_REDUCE | MoreFlags; TraceBasicInfo.LogFileName = LogFileName; TraceBasicInfo.LogFileCount = LogFileCount; TraceBasicInfo.pUserContext = pUserContext; TraceBasicInfo.StartTime = StartTime; TraceBasicInfo.EndTime = EndTime; TraceBasicInfo.DSStartTime = DSStartTime; TraceBasicInfo.DSEndTime = DSEndTime; TraceBasicInfo.ProcFileName = pOutFileName; InitTraceContext(&TraceBasicInfo); #if DBG if (ETAAPITestFlag) { TestETAApis( & TraceBasicInfo ); } #endif DeinitTraceContext(&TraceBasicInfo); } int __cdecl main(int argc ,char * argv[]) { WCHAR TraceLogFile[MAXSTR]; WCHAR PerfLogFile[MAXSTR]; BOOLEAN bTrace = FALSE; LPTSTR EvmFile[MAXLOGFILES]; ULONGLONG StartTime = 0, EndTime = 0; ULONG i; ULONG LogFileCount = 0; LPTSTR *targv; #ifdef UNICODE LPTSTR *cmdargv; #endif ULONG flagsMore = 0; PVOID pUserContext = NULL; CPD_USER_CONTEXT_MM UserContextMM; #ifdef UNICODE if ((cmdargv = CommandLineToArgvW( GetCommandLineW(), // pointer to a command-line string &argc // receives the argument count )) == NULL) { return(GetLastError()); }; targv = cmdargv ; #else targv = argv; #endif UserContextMM.reportNow = REPORT_SUMMARY_PROCESS; UserContextMM.sortNow = REPORT_SORT_ALL; UserContextMM.strImgName = NULL; memset(&TraceLogFile, 0, sizeof(WCHAR) * MAXSTR); while (--argc > 0) { ++targv; if (**targv == '-' || **targv == '/') { ** targv = '-'; if (!_tcsicmp(targv[0], _T("-out"))) { if (argc > 1) { TCHAR TempStr[MAXSTR]; _tcscpy(TempStr, targv[1]); ++targv; --argc; _tfullpath(TraceLogFile, TempStr, MAXSTR); printf("Setting output file to: '%ws'\n", TraceLogFile); bTrace = TRUE; } } else if (!_tcsicmp(targv[0], _T("-start"))) { if (argc > 1) { flagsMore |= TRACE_DS_ONLY | TRACE_LOG_REPORT_BASIC; StartTime = ParseTimeString(targv[1]); argc --; targv ++; } } else if (!_tcsicmp(targv[0], _T("-end"))) { if (argc > 1) { flagsMore |= TRACE_DS_ONLY | TRACE_LOG_REPORT_BASIC; EndTime = ParseTimeString(targv[1]); argc --; targv ++; } } else if (!_tcsicmp(targv[0], _T("-base"))) { flagsMore |= TRACE_LOG_REPORT_BASIC; } else if (!_tcsicmp(targv[0], _T("-spooler"))) { flagsMore |= TRACE_LOG_REPORT_BASIC; flagsMore |= TRACE_SPOOLER; } else if (!_tcsicmp(targv[0], _T("-total"))) { flagsMore |= TRACE_LOG_REPORT_TOTALS; } else if (!_tcsicmp(targv[0], _T("-file"))) { flagsMore |= TRACE_LOG_REPORT_FILE; /* if (argc > 1 && targv[1][0] >= '0' && targv[1][0] <= '9') { pUserContext = UlongToPtr(atoi(targv[1])); argc --; targv ++; } else { pUserContext = UlongToPtr(DEFAULT_FILE_REPORT_SIZE); } */ } else if (!_tcsicmp(targv[0], _T("-hpf"))) { flagsMore |= TRACE_LOG_REPORT_HARDFAULT; } else if (!_tcsicmp(targv[0], _T("-pf"))) { flagsMore |= TRACE_LOG_REPORT_MEMORY; pUserContext = (PVOID) & UserContextMM; } else if (!_tcsicmp(targv[0], _T("-summary"))) { if (argc > 1) { flagsMore |= TRACE_LOG_REPORT_MEMORY; pUserContext = (PVOID) & UserContextMM; if (!_tcsicmp(targv[1], _T("processes"))) { argc --; targv ++; UserContextMM.reportNow = REPORT_SUMMARY_PROCESS; } else if (!_tcsicmp(targv[1], _T("modules"))) { argc --; targv ++; UserContextMM.reportNow = REPORT_SUMMARY_MODULE; } } } else if (!_tcsicmp(targv[0], _T("-process"))) { flagsMore |= TRACE_LOG_REPORT_MEMORY; pUserContext = (PVOID) & UserContextMM; UserContextMM.reportNow = REPORT_LIST_PROCESS; if ((argc > 1) && (targv[1][0] != '-' || targv[1][0] != '/')) { if (_tcsicmp(targv[1], _T("all"))) { UserContextMM.strImgName = malloc(sizeof(TCHAR) * (_tcslen(targv[1]) + 1)); if (UserContextMM.strImgName) { _tcscpy(UserContextMM.strImgName, targv[1]); } } argc --; targv ++; } } else if (!_tcsicmp(targv[0], _T("-module"))) { flagsMore |= TRACE_LOG_REPORT_MEMORY; pUserContext = (PVOID) & UserContextMM; UserContextMM.reportNow = REPORT_LIST_MODULE; if ((argc > 1) && (targv[1][0] != '-' || targv[1][0] != '/')) { if (_tcsicmp(targv[1], _T("all"))) { UserContextMM.strImgName = malloc(sizeof(TCHAR) * (_tcslen(targv[1]) + 1)); if (UserContextMM.strImgName) { _tcscpy(UserContextMM.strImgName, targv[1]); } } argc --; targv ++; } } else if (!_tcsicmp(targv[0], _T("-sort"))) { flagsMore |= TRACE_LOG_REPORT_MEMORY; pUserContext = (PVOID) & UserContextMM; if ((argc > 1) && (targv[1][0] != '-' || targv[1][0] != '/')) { if (!_tcsicmp(targv[1], _T("hpf"))) { UserContextMM.sortNow = REPORT_SORT_HPF; } else if (!_tcsicmp(targv[1], _T("tf"))) { UserContextMM.sortNow = REPORT_SORT_TF; } else if (!_tcsicmp(targv[1], _T("dzf"))) { UserContextMM.sortNow = REPORT_SORT_DZF; } else if (!_tcsicmp(targv[1], _T("cow"))) { UserContextMM.sortNow = REPORT_SORT_COW; } else { UserContextMM.sortNow = REPORT_SORT_ALL; } argc --; targv ++; } } else { goto Usage; } } else { LPTSTR pLogFile; pLogFile = malloc(sizeof(TCHAR) * MAXSTR); RtlZeroMemory((char *) pLogFile, sizeof(TCHAR) * MAXSTR); EvmFile[LogFileCount] = pLogFile; _tcscpy(EvmFile[LogFileCount ++], targv[0]); bTrace = TRUE; printf("LogFile %ws\n", (char *) EvmFile[LogFileCount - 1]); } } if (LogFileCount == 0) { goto Usage; } if (flagsMore == 0) { flagsMore |= TRACE_LOG_REPORT_BASIC; } if ( (flagsMore & TRACE_LOG_REPORT_MEMORY) && (flagsMore & TRACE_LOG_REPORT_FILE)) { printf("Error: cannot generate HotFile report and PageFault report at the same time.\n"); goto Cleanup; } if (bTrace) { ProcessTrace(LogFileCount, EvmFile, (ULONGLONG) 0, (ULONGLONG) 0, StartTime, EndTime, flagsMore, pUserContext, TraceLogFile); } for (i=0; i < LogFileCount; i++) { free((char*)EvmFile[i]); } if (UserContextMM.strImgName) { free(UserContextMM.strImgName); } Cleanup: #ifdef UNICODE GlobalFree(cmdargv); #endif return 0; Usage: ReducerUsage(); goto Cleanup; } #if DBG VOID PrintHeader( FILE* f, TRACEINFOCLASS CurrentClass, TRACEINFOCLASS RootClass, BOOLEAN bDrillDown, LPCWSTR InstanceName ) { if (bDrillDown) { fprintf(f, "-------------------------------------------\n"); fprintf(f, "RootClass: %d Instance %ws\n", RootClass, InstanceName); fprintf(f, "-------------------------------------------\n"); } switch(CurrentClass) { case TraceProcessInformation: fprintf(f, "Trace Process Information\n"); fprintf(f, "------------------------\n"); fprintf(f, "\nPID Name Image UCpu KCpu ReadIO WriteIO\n\n"); break; case TraceDiskInformation: fprintf(f, "Trace Disk Information\n"); fprintf(f, "----------------------\n"); fprintf(f, "\nDiskId Name ReadIO WriteIO\n\n"); break; case TraceThreadInformation: fprintf(f, "Trace Thread Information\n"); fprintf(f, "------------------------\n"); fprintf(f, "\nTID PID UCpu KCpu ReadIO WriteIO \n\n"); break; case TraceFileInformation: fprintf(f, "Trace File Information\n"); fprintf(f, "------------------------\n"); fprintf(f, "\nFileName ReadIO WriteIO \n\n"); break; } } VOID PrintProcessInfo( FILE* f, PTRACE_PROCESS_INFO pProcessInfo ) { fprintf(f, "%4d %-10ws %-10ws %5d %5d %5d %5d\n", pProcessInfo->PID, pProcessInfo->UserName, pProcessInfo->ImageName, pProcessInfo->UserCPU, pProcessInfo->KernelCPU, pProcessInfo->ReadCount, pProcessInfo->WriteCount); } VOID PrintThreadInfo( FILE* f, PTRACE_THREAD_INFO pThreadInfo ) { fprintf(f, "%4x \n", pThreadInfo->ThreadId); } VOID PrintDiskInfo( FILE* f, PTRACE_DISK_INFO pDiskInfo ) { fprintf(f, "%d %-10ws %5d %5d \n", pDiskInfo->DiskNumber, pDiskInfo->DiskName, pDiskInfo->ReadCount, pDiskInfo->WriteCount); } VOID PrintFileInfo( FILE* f, PTRACE_FILE_INFO pFileInfo ) { fprintf(f, "%ws %5d %5d\n", pFileInfo->FileName, pFileInfo->ReadCount, pFileInfo->WriteCount ); } VOID TestETAApis( PTRACE_BASIC_INFO TraceBasicInfo ) { ULONG Status; ULONG OutLength; PTRACE_PROCESS_INFO pProcessInfo; PTRACE_DISK_INFO pDiskInfo; PTRACE_FILE_INFO pFileInfo; PTRACE_THREAD_INFO pThreadInfo; char* LargeBuffer1; ULONG CurrentBufferSize; BOOLEAN Done, FinshPrinting, bDrillDown; TRACEINFOCLASS CurrentClass, RootClass; ULONG TotalOffset; FILE* f; int i = 0; LPWSTR InstanceName; WCHAR Name[MAXSTR+1]; InstanceName = (LPWSTR)&Name; LargeBuffer1 = VirtualAlloc(NULL, MAX_BUFFER_SIZE, MEM_RESERVE, PAGE_READWRITE); if (LargeBuffer1 == NULL) { return; } CurrentBufferSize = 10*8192; if (VirtualAlloc(LargeBuffer1, 81920, MEM_COMMIT, PAGE_READWRITE) == NULL) { return; } f = _wfopen(L"TraceAPI.rpt", L"w"); if (f == NULL) { VirtualFree(LargeBuffer1, 0, MEM_RELEASE); return; } CurrentClass = TraceProcessInformation; RootClass = TraceProcessInformation; Done = FALSE; bDrillDown = FALSE; while (!Done) { Retry1: if (!bDrillDown) { Status = TraceQueryAllInstances( CurrentClass, LargeBuffer1, CurrentBufferSize, &OutLength); } else { Status = TraceDrillDown( RootClass, InstanceName, CurrentClass, LargeBuffer1, CurrentBufferSize, &OutLength ); } if (Status == ERROR_MORE_DATA) { CurrentBufferSize += OutLength; if (VirtualAlloc(LargeBuffer1, CurrentBufferSize, MEM_COMMIT, PAGE_READWRITE) == NULL) { return; } goto Retry1; } if (Status != ERROR_SUCCESS) { Done = TRUE; break; } // // Print Header // PrintHeader(f, CurrentClass, RootClass, bDrillDown, InstanceName); // // Walk the Process List and Print report. // TotalOffset = 0; pProcessInfo = (TRACE_PROCESS_INFO *) LargeBuffer1; pThreadInfo = (TRACE_THREAD_INFO *) LargeBuffer1; pFileInfo = (TRACE_FILE_INFO *) LargeBuffer1; pDiskInfo = (TRACE_DISK_INFO *) LargeBuffer1; FinshPrinting = FALSE; while (!FinshPrinting) { switch(CurrentClass) { case TraceProcessInformation: PrintProcessInfo(f, pProcessInfo); if (pProcessInfo->NextEntryOffset == 0) { FinshPrinting = TRUE; break; } TotalOffset += pProcessInfo->NextEntryOffset; pProcessInfo = (TRACE_PROCESS_INFO *) &LargeBuffer1[TotalOffset]; break; case TraceDiskInformation: PrintDiskInfo(f, pDiskInfo); if (pDiskInfo->NextEntryOffset == 0) { FinshPrinting = TRUE; break; } TotalOffset += pDiskInfo->NextEntryOffset; pDiskInfo = (TRACE_DISK_INFO *) &LargeBuffer1[TotalOffset]; default: FinshPrinting = TRUE; break; } if (TotalOffset == 0) break; } if (!bDrillDown) { switch(CurrentClass) { case TraceProcessInformation: CurrentClass = TraceDiskInformation; break; case TraceThreadInformation: CurrentClass = TraceDiskInformation; break; case TraceDiskInformation: RootClass = TraceProcessInformation; CurrentClass = TraceProcessInformation; bDrillDown = TRUE; break; case TraceFileInformation: Done = TRUE; break; default: Done = TRUE; break; } } if (bDrillDown) { switch(RootClass) { case TraceProcessInformation: wcscpy(InstanceName, L"\\\\NTDEV\\mraghu"); if (CurrentClass == TraceProcessInformation) { CurrentClass = TraceFileInformation; } else if (CurrentClass == TraceFileInformation) { CurrentClass = TraceDiskInformation; } else { RootClass = TraceDiskInformation; CurrentClass = TraceProcessInformation; wcscpy (InstanceName, L"Disk1"); } break; case TraceDiskInformation: if (CurrentClass == TraceProcessInformation) { CurrentClass = TraceFileInformation; wcscpy (InstanceName, L"Disk1"); } else { Done = TRUE; } break; case TraceFileInformation: default: Done = TRUE; break; } } } fclose (f); VirtualFree(LargeBuffer1, 0, MEM_RELEASE); } #endif #ifdef __cplusplus } #endif