windows-nt/Source/XPSP1/NT/sdktools/reducer/reducer.c

790 lines
22 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <shellapi.h>
#include <tchar.h>
#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] <EtlFile1 EtlFile2 ...> | [-h | -help | -?]\n");
printf("\t-out <filename> 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 <time-stamp> Start Time\n");
// printf("\t-end <time-stamp> End Time\n");
// printf("\t <time-stamp> 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 <image name> rundown for specific process.\n");
// printf("\t all\n");
// printf("\t -module <module name> 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