502 lines
13 KiB
C++
502 lines
13 KiB
C++
/*
|
|
|
|
DISKSPD
|
|
|
|
Copyright(c) Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
MIT License
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include "etw.h"
|
|
#include "common.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <Wmistr.h> //WNODE_HEADER
|
|
|
|
#define INITGUID //Include this #define to use SystemTraceControlGuid in Evntrace.h.
|
|
#include <Evntrace.h> //ETW
|
|
|
|
#include "IORequestGenerator.h"
|
|
|
|
// variables declared in IORequestGenerator.cpp
|
|
extern struct ETWEventCounters g_EtwEventCounters;
|
|
extern BOOL volatile g_bTracing;
|
|
|
|
|
|
DEFINE_GUID ( /* 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c */
|
|
DiskIoGuid,
|
|
0x3d6fa8d4,
|
|
0xfe05,
|
|
0x11d0,
|
|
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
|
);
|
|
|
|
DEFINE_GUID ( /* 90cbdc39-4a3e-11d1-84f4-0000f80464e3 */
|
|
FileIoGuid,
|
|
0x90cbdc39,
|
|
0x4a3e,
|
|
0x11d1,
|
|
0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3
|
|
);
|
|
|
|
DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */
|
|
ImageLoadGuid,
|
|
0x2cb15d1d,
|
|
0x5fc1,
|
|
0x11d2,
|
|
0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18
|
|
);
|
|
|
|
DEFINE_GUID ( /* 3d6fa8d3-fe05-11d0-9dda-00c04fd7ba7c */
|
|
PageFaultGuid,
|
|
0x3d6fa8d3,
|
|
0xfe05,
|
|
0x11d0,
|
|
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
|
);
|
|
|
|
DEFINE_GUID ( /* 9a280ac0-c8e0-11d1-84e2-00c04fb998a2 */
|
|
TcpIpGuid,
|
|
0x9a280ac0,
|
|
0xc8e0,
|
|
0x11d1,
|
|
0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2
|
|
);
|
|
|
|
DEFINE_GUID ( /* bf3a50c5-a9c9-4988-a005-2df0b7c80f80 */
|
|
UdpIpGuid,
|
|
0xbf3a50c5,
|
|
0xa9c9,
|
|
0x4988,
|
|
0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80
|
|
);
|
|
|
|
DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */
|
|
ProcessGuid,
|
|
0x3d6fa8d0,
|
|
0xfe05,
|
|
0x11d0,
|
|
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
|
);
|
|
|
|
DEFINE_GUID ( /* AE53722E-C863-11d2-8659-00C04FA321A1 */
|
|
RegistryGuid,
|
|
0xae53722e,
|
|
0xc863,
|
|
0x11d2,
|
|
0x86, 0x59, 0x0, 0xc0, 0x4f, 0xa3, 0x21, 0xa1
|
|
);
|
|
|
|
DEFINE_GUID ( /* 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c */
|
|
ThreadGuid,
|
|
0x3d6fa8d1,
|
|
0xfe05,
|
|
0x11d0,
|
|
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
|
);
|
|
|
|
/*****************************************************************************/
|
|
// consumes events' data
|
|
//
|
|
BOOL TraceEvents()
|
|
{
|
|
TRACEHANDLE handles[1];
|
|
EVENT_TRACE_LOGFILE logfile;
|
|
|
|
memset(&logfile, 0, sizeof(EVENT_TRACE_LOGFILE));
|
|
|
|
logfile.LoggerName = KERNEL_LOGGER_NAME;
|
|
logfile.LogFileName = NULL;
|
|
logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
|
|
|
logfile.IsKernelTrace = true;
|
|
|
|
handles[0] = OpenTrace(&logfile);
|
|
if( (TRACEHANDLE)INVALID_HANDLE_VALUE == handles[0] )
|
|
{
|
|
PrintError("ETW ERROR: OpenTrace failed (error code: %d)\n", GetLastError());
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
ProcessTrace(handles, 1, 0, 0);
|
|
CloseTrace(handles[0]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// allocates memory for ETW properties structure
|
|
//
|
|
PEVENT_TRACE_PROPERTIES allocateEventTraceProperties()
|
|
{
|
|
PEVENT_TRACE_PROPERTIES pProperties = NULL;
|
|
size_t size = 0;
|
|
|
|
|
|
size = sizeof(EVENT_TRACE_PROPERTIES)+sizeof(KERNEL_LOGGER_NAME);
|
|
pProperties = (PEVENT_TRACE_PROPERTIES)malloc(size);
|
|
if( NULL == pProperties )
|
|
{
|
|
PrintError("FATAL ERROR: unable to allocate memory (error code: %d)\n", GetLastError());
|
|
return NULL;
|
|
}
|
|
|
|
memset(pProperties, 0, size);
|
|
|
|
pProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
|
pProperties->Wnode.BufferSize = (ULONG)size;
|
|
pProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|
|
|
strcpy_s((char *)pProperties+pProperties->LoggerNameOffset,
|
|
size-pProperties->LoggerNameOffset, KERNEL_LOGGER_NAME);
|
|
|
|
return pProperties;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for disk I/O events
|
|
void WINAPI eventDiskIo(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_IO_READ == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullIORead;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_IO_WRITE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullIOWrite;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for LoadImage events
|
|
//
|
|
void WINAPI eventLoadImage(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_LOAD == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullImageLoad;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for memory events
|
|
//
|
|
void WINAPI eventPageFault(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_MM_COW == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullMMCopyOnWrite;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_MM_DZF == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullMMDemandZeroFault;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_MM_GPF == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullMMGuardPageFault;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_MM_HPF == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullMMHardPageFault;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_MM_TF == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullMMTransitionFault;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for network and TCP/IP events
|
|
//
|
|
void WINAPI eventTcpIp(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_ACCEPT == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetAccept;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_CONNECT == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetConnect;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_DISCONNECT == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetDisconnect;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetTcpReceive;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_RECONNECT == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetReconnect;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_RETRANSMIT == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetRetransmit;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetTcpSend;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for UDP/IP events
|
|
//
|
|
void WINAPI eventUdpIp(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_SEND == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetUdpSend;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_RECEIVE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullNetUdpReceive;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for thread events
|
|
//
|
|
void WINAPI eventThread(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullThreadStart;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullThreadEnd;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for process events
|
|
//
|
|
void WINAPI eventProcess(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_START == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullProcessStart;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_END == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullProcessEnd;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// callback function for registry events
|
|
//
|
|
void WINAPI eventRegistry(PEVENT_TRACE pEvent)
|
|
{
|
|
if( EVENT_TRACE_TYPE_REGCREATE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegCreate;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGDELETE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegDelete;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGDELETEVALUE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegDeleteValue;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGENUMERATEKEY == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegEnumerateKey;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegEnumerateValueKey;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGFLUSH == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegFlush;
|
|
}
|
|
// else if( EVENT_TRACE_TYPE_REGKCBDMP == pEvent->Header.Class.Type )
|
|
// {
|
|
// ++ETWEventCounters.ullRegKcbDmp;
|
|
// }
|
|
else if( EVENT_TRACE_TYPE_REGOPEN == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegOpen;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGQUERY == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegQuery;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegQueryMultipleValue;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGQUERYVALUE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegQueryValue;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGSETINFORMATION == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegSetInformation;
|
|
}
|
|
else if( EVENT_TRACE_TYPE_REGSETVALUE == pEvent->Header.Class.Type )
|
|
{
|
|
++g_EtwEventCounters.ullRegSetValue;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// starts ETW session and sets callback functions for various groups of events
|
|
//
|
|
TRACEHANDLE StartETWSession(const Profile& profile)
|
|
{
|
|
PEVENT_TRACE_PROPERTIES pProperties;
|
|
|
|
pProperties = allocateEventTraceProperties();
|
|
if (nullptr == pProperties)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
|
|
|
//use paged memory
|
|
if (profile.GetEtwUsePagedMemory())
|
|
{
|
|
pProperties->LogFileMode |= EVENT_TRACE_USE_PAGED_MEMORY;
|
|
}
|
|
|
|
//
|
|
// event classes
|
|
//
|
|
if (profile.GetEtwProcess())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_PROCESS;
|
|
SetTraceCallback(&ProcessGuid, eventThread);
|
|
}
|
|
|
|
if (profile.GetEtwThread())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_THREAD;
|
|
SetTraceCallback(&ThreadGuid, eventThread);
|
|
}
|
|
|
|
if (profile.GetEtwImageLoad())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_IMAGE_LOAD;
|
|
SetTraceCallback(&ImageLoadGuid, eventLoadImage);
|
|
}
|
|
|
|
if (profile.GetEtwDiskIO())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_DISK_IO;
|
|
SetTraceCallback(&DiskIoGuid, eventDiskIo);
|
|
}
|
|
|
|
if (profile.GetEtwMemoryPageFaults())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS;
|
|
SetTraceCallback(&PageFaultGuid, eventPageFault);
|
|
}
|
|
|
|
if (profile.GetEtwMemoryHardFaults())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS;
|
|
SetTraceCallback(&PageFaultGuid, eventPageFault);
|
|
}
|
|
|
|
if (profile.GetEtwNetwork())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP;
|
|
SetTraceCallback(&TcpIpGuid, eventTcpIp);
|
|
SetTraceCallback(&UdpIpGuid, eventUdpIp);
|
|
}
|
|
|
|
if (profile.GetEtwRegistry())
|
|
{
|
|
pProperties->EnableFlags |= EVENT_TRACE_FLAG_REGISTRY;
|
|
SetTraceCallback(&RegistryGuid, eventRegistry);
|
|
}
|
|
|
|
//
|
|
// timer
|
|
//
|
|
if (profile.GetEtwUsePerfTimer())
|
|
{
|
|
pProperties->Wnode.ClientContext = 1;
|
|
}
|
|
if (profile.GetEtwUseSystemTimer())
|
|
{
|
|
pProperties->Wnode.ClientContext = 2;
|
|
}
|
|
if (profile.GetEtwUseCyclesCounter())
|
|
{
|
|
pProperties->Wnode.ClientContext = 3;
|
|
}
|
|
|
|
pProperties->Wnode.Guid = SystemTraceControlGuid;
|
|
|
|
TRACEHANDLE hTraceSession;
|
|
ULONG ret = StartTrace(&hTraceSession, KERNEL_LOGGER_NAME, pProperties);
|
|
free(pProperties);
|
|
if (ERROR_SUCCESS != ret)
|
|
{
|
|
PrintError("Error starting trace session\n");
|
|
return 0;
|
|
}
|
|
|
|
return hTraceSession;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
// stops ETW session
|
|
//
|
|
PEVENT_TRACE_PROPERTIES StopETWSession(TRACEHANDLE hTraceSession)
|
|
{
|
|
PEVENT_TRACE_PROPERTIES pProperties;
|
|
|
|
pProperties = allocateEventTraceProperties();
|
|
if( NULL == pProperties )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ULONG ret;
|
|
|
|
ret = ControlTrace(hTraceSession, NULL, pProperties, EVENT_TRACE_CONTROL_STOP);
|
|
if( ERROR_SUCCESS != ret )
|
|
{
|
|
PrintError("Error stopping trace session\n");
|
|
return NULL;
|
|
}
|
|
|
|
//wait
|
|
while(g_bTracing)
|
|
{
|
|
Sleep(10); // TODO: remove active waiting
|
|
}
|
|
|
|
return pProperties;
|
|
} |