diff options
Diffstat (limited to 'external/optick/optick_core.win.h')
-rw-r--r-- | external/optick/optick_core.win.h | 1664 |
1 files changed, 0 insertions, 1664 deletions
diff --git a/external/optick/optick_core.win.h b/external/optick/optick_core.win.h deleted file mode 100644 index 0d8a11a..0000000 --- a/external/optick/optick_core.win.h +++ /dev/null @@ -1,1664 +0,0 @@ -#pragma once -#if defined(_MSC_VER) - -#include "optick.config.h" - -#if USE_OPTICK - -#include "optick_core.platform.h" - -namespace Optick -{ - const char* Platform::GetName() - { - #if defined(OPTICK_PC) - return "Windows"; - #else - return "XBox"; - #endif - } - - ThreadID Platform::GetThreadID() - { - return GetCurrentThreadId(); - } - - ProcessID Platform::GetProcessID() - { - return GetCurrentProcessId(); - } - - int64 Platform::GetFrequency() - { - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - return frequency.QuadPart; - } - - int64 Platform::GetTime() - { - LARGE_INTEGER largeInteger; - QueryPerformanceCounter(&largeInteger); - return largeInteger.QuadPart; - } -} - -#if OPTICK_ENABLE_TRACING -#include <psapi.h> -#include "optick_core.h" - -/* -Event Tracing Functions - API -https://msdn.microsoft.com/en-us/library/windows/desktop/aa363795(v=vs.85).aspx -*/ - -#define DECLARE_ETW (!OPTICK_PC) - -#if DECLARE_ETW -// Copied from Windows SDK -#ifndef WMIAPI -#ifndef MIDL_PASS -#ifdef _WMI_SOURCE_ -#define WMIAPI __stdcall -#else -#define WMIAPI DECLSPEC_IMPORT __stdcall -#endif // _WMI_SOURCE -#endif // MIDL_PASS -#endif // WMIAPI -#define INITGUID -#include <guiddef.h> -#if defined(_NTDDK_) || defined(_NTIFS_) || defined(_WMIKM_) -#define _EVNTRACE_KERNEL_MODE -#endif -#if !defined(_EVNTRACE_KERNEL_MODE) -#include <wmistr.h> -#endif - -#if _MSC_VER <= 1600 -#define EVENT_DESCRIPTOR_DEF -#define EVENT_HEADER_DEF -#define EVENT_HEADER_EXTENDED_DATA_ITEM_DEF -#define EVENT_RECORD_DEF -#endif - -#ifndef _TRACEHANDLE_DEFINED -#define _TRACEHANDLE_DEFINED -typedef ULONG64 TRACEHANDLE, *PTRACEHANDLE; -#endif - -// -// EventTraceGuid is used to identify a event tracing session -// -DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */ - EventTraceGuid, - 0x68fdd900, - 0x4a3e, - 0x11d1, - 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 -); - -// -// SystemTraceControlGuid. Used to specify event tracing for kernel -// -DEFINE_GUID( /* 9e814aad-3204-11d2-9a82-006008a86939 */ - SystemTraceControlGuid, - 0x9e814aad, - 0x3204, - 0x11d2, - 0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39 -); - -// -// EventTraceConfigGuid. Used to report system configuration records -// -DEFINE_GUID( /* 01853a65-418f-4f36-aefc-dc0f1d2fd235 */ - EventTraceConfigGuid, - 0x01853a65, - 0x418f, - 0x4f36, - 0xae, 0xfc, 0xdc, 0x0f, 0x1d, 0x2f, 0xd2, 0x35 -); - -// -// DefaultTraceSecurityGuid. Specifies the default event tracing security -// -DEFINE_GUID( /* 0811c1af-7a07-4a06-82ed-869455cdf713 */ - DefaultTraceSecurityGuid, - 0x0811c1af, - 0x7a07, - 0x4a06, - 0x82, 0xed, 0x86, 0x94, 0x55, 0xcd, 0xf7, 0x13 -); - - -/////////////////////////////////////////////////////////////////////////////// -#define PROCESS_TRACE_MODE_REAL_TIME 0x00000100 -#define PROCESS_TRACE_MODE_RAW_TIMESTAMP 0x00001000 -#define PROCESS_TRACE_MODE_EVENT_RECORD 0x10000000 -/////////////////////////////////////////////////////////////////////////////// -#define EVENT_HEADER_FLAG_EXTENDED_INFO 0x0001 -#define EVENT_HEADER_FLAG_PRIVATE_SESSION 0x0002 -#define EVENT_HEADER_FLAG_STRING_ONLY 0x0004 -#define EVENT_HEADER_FLAG_TRACE_MESSAGE 0x0008 -#define EVENT_HEADER_FLAG_NO_CPUTIME 0x0010 -#define EVENT_HEADER_FLAG_32_BIT_HEADER 0x0020 -#define EVENT_HEADER_FLAG_64_BIT_HEADER 0x0040 -#define EVENT_HEADER_FLAG_CLASSIC_HEADER 0x0100 -#define EVENT_HEADER_FLAG_PROCESSOR_INDEX 0x0200 -/////////////////////////////////////////////////////////////////////////////// -#define KERNEL_LOGGER_NAMEW L"NT Kernel Logger" -/////////////////////////////////////////////////////////////////////////////// -#define EVENT_TRACE_REAL_TIME_MODE 0x00000100 // Real time mode on -/////////////////////////////////////////////////////////////////////////////// -#define EVENT_TRACE_CONTROL_STOP 1 -/////////////////////////////////////////////////////////////////////////////// - -// -// Enable flags for Kernel Events -// -#define EVENT_TRACE_FLAG_PROCESS 0x00000001 // process start & end -#define EVENT_TRACE_FLAG_THREAD 0x00000002 // thread start & end -#define EVENT_TRACE_FLAG_IMAGE_LOAD 0x00000004 // image load - -#define EVENT_TRACE_FLAG_DISK_IO 0x00000100 // physical disk IO -#define EVENT_TRACE_FLAG_DISK_FILE_IO 0x00000200 // requires disk IO - -#define EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS 0x00001000 // all page faults -#define EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS 0x00002000 // hard faults only - -#define EVENT_TRACE_FLAG_NETWORK_TCPIP 0x00010000 // tcpip send & receive - -#define EVENT_TRACE_FLAG_REGISTRY 0x00020000 // registry calls -#define EVENT_TRACE_FLAG_DBGPRINT 0x00040000 // DbgPrint(ex) Calls - -// -// Enable flags for Kernel Events on Vista and above -// -#define EVENT_TRACE_FLAG_PROCESS_COUNTERS 0x00000008 // process perf counters -#define EVENT_TRACE_FLAG_CSWITCH 0x00000010 // context switches -#define EVENT_TRACE_FLAG_DPC 0x00000020 // deffered procedure calls -#define EVENT_TRACE_FLAG_INTERRUPT 0x00000040 // interrupts -#define EVENT_TRACE_FLAG_SYSTEMCALL 0x00000080 // system calls - -#define EVENT_TRACE_FLAG_DISK_IO_INIT 0x00000400 // physical disk IO initiation -#define EVENT_TRACE_FLAG_ALPC 0x00100000 // ALPC traces -#define EVENT_TRACE_FLAG_SPLIT_IO 0x00200000 // split io traces (VolumeManager) - -#define EVENT_TRACE_FLAG_DRIVER 0x00800000 // driver delays -#define EVENT_TRACE_FLAG_PROFILE 0x01000000 // sample based profiling -#define EVENT_TRACE_FLAG_FILE_IO 0x02000000 // file IO -#define EVENT_TRACE_FLAG_FILE_IO_INIT 0x04000000 // file IO initiation - -#define EVENT_TRACE_FLAG_PMC_PROFILE 0x80000000 // sample based profiling (PMC) - NOT CONFIRMED! - -// -// Enable flags for Kernel Events on Win7 and above -// -#define EVENT_TRACE_FLAG_DISPATCHER 0x00000800 // scheduler (ReadyThread) -#define EVENT_TRACE_FLAG_VIRTUAL_ALLOC 0x00004000 // VM operations - -// -// Enable flags for Kernel Events on Win8 and above -// -#define EVENT_TRACE_FLAG_VAMAP 0x00008000 // map/unmap (excluding images) -#define EVENT_TRACE_FLAG_NO_SYSCONFIG 0x10000000 // Do not do sys config rundown - -/////////////////////////////////////////////////////////////////////////////// - -#pragma warning(push) -#pragma warning (disable:4201) - -#ifndef EVENT_DESCRIPTOR_DEF -#define EVENT_DESCRIPTOR_DEF -typedef struct _EVENT_DESCRIPTOR { - - USHORT Id; - UCHAR Version; - UCHAR Channel; - UCHAR Level; - UCHAR Opcode; - USHORT Task; - ULONGLONG Keyword; - -} EVENT_DESCRIPTOR, *PEVENT_DESCRIPTOR; -typedef const EVENT_DESCRIPTOR *PCEVENT_DESCRIPTOR; -#endif -/////////////////////////////////////////////////////////////////////////////// -#ifndef EVENT_HEADER_DEF -#define EVENT_HEADER_DEF -typedef struct _EVENT_HEADER { - - USHORT Size; - USHORT HeaderType; - USHORT Flags; - USHORT EventProperty; - ULONG ThreadId; - ULONG ProcessId; - LARGE_INTEGER TimeStamp; - GUID ProviderId; - EVENT_DESCRIPTOR EventDescriptor; - union { - struct { - ULONG KernelTime; - ULONG UserTime; - } DUMMYSTRUCTNAME; - ULONG64 ProcessorTime; - - } DUMMYUNIONNAME; - GUID ActivityId; - -} EVENT_HEADER, *PEVENT_HEADER; -#endif -/////////////////////////////////////////////////////////////////////////////// -#ifndef EVENT_HEADER_EXTENDED_DATA_ITEM_DEF -#define EVENT_HEADER_EXTENDED_DATA_ITEM_DEF -typedef struct _EVENT_HEADER_EXTENDED_DATA_ITEM { - - USHORT Reserved1; // Reserved for internal use - USHORT ExtType; // Extended info type - struct { - USHORT Linkage : 1; // Indicates additional extended - // data item - USHORT Reserved2 : 15; - }; - USHORT DataSize; // Size of extended info data - ULONGLONG DataPtr; // Pointer to extended info data - -} EVENT_HEADER_EXTENDED_DATA_ITEM, *PEVENT_HEADER_EXTENDED_DATA_ITEM; -#endif -/////////////////////////////////////////////////////////////////////////////// -#ifndef ETW_BUFFER_CONTEXT_DEF -#define ETW_BUFFER_CONTEXT_DEF -typedef struct _ETW_BUFFER_CONTEXT { - union { - struct { - UCHAR ProcessorNumber; - UCHAR Alignment; - } DUMMYSTRUCTNAME; - USHORT ProcessorIndex; - } DUMMYUNIONNAME; - USHORT LoggerId; -} ETW_BUFFER_CONTEXT, *PETW_BUFFER_CONTEXT; -#endif -/////////////////////////////////////////////////////////////////////////////// -#ifndef EVENT_RECORD_DEF -#define EVENT_RECORD_DEF -typedef struct _EVENT_RECORD { - EVENT_HEADER EventHeader; - ETW_BUFFER_CONTEXT BufferContext; - USHORT ExtendedDataCount; - - USHORT UserDataLength; - PEVENT_HEADER_EXTENDED_DATA_ITEM ExtendedData; - PVOID UserData; - PVOID UserContext; -} EVENT_RECORD, *PEVENT_RECORD; -#endif -/////////////////////////////////////////////////////////////////////////////// -typedef struct _EVENT_TRACE_PROPERTIES { - WNODE_HEADER Wnode; - // - // data provided by caller - ULONG BufferSize; // buffer size for logging (kbytes) - ULONG MinimumBuffers; // minimum to preallocate - ULONG MaximumBuffers; // maximum buffers allowed - ULONG MaximumFileSize; // maximum logfile size (in MBytes) - ULONG LogFileMode; // sequential, circular - ULONG FlushTimer; // buffer flush timer, in seconds - ULONG EnableFlags; // trace enable flags - union { - LONG AgeLimit; // unused - LONG FlushThreshold; // Number of buffers to fill before flushing - } DUMMYUNIONNAME; - - // data returned to caller - ULONG NumberOfBuffers; // no of buffers in use - ULONG FreeBuffers; // no of buffers free - ULONG EventsLost; // event records lost - ULONG BuffersWritten; // no of buffers written to file - ULONG LogBuffersLost; // no of logfile write failures - ULONG RealTimeBuffersLost; // no of rt delivery failures - HANDLE LoggerThreadId; // thread id of Logger - ULONG LogFileNameOffset; // Offset to LogFileName - ULONG LoggerNameOffset; // Offset to LoggerName -} EVENT_TRACE_PROPERTIES, *PEVENT_TRACE_PROPERTIES; - -typedef struct _EVENT_TRACE_HEADER { // overlays WNODE_HEADER - USHORT Size; // Size of entire record - union { - USHORT FieldTypeFlags; // Indicates valid fields - struct { - UCHAR HeaderType; // Header type - internal use only - UCHAR MarkerFlags; // Marker - internal use only - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME; - union { - ULONG Version; - struct { - UCHAR Type; // event type - UCHAR Level; // trace instrumentation level - USHORT Version; // version of trace record - } Class; - } DUMMYUNIONNAME2; - ULONG ThreadId; // Thread Id - ULONG ProcessId; // Process Id - LARGE_INTEGER TimeStamp; // time when event happens - union { - GUID Guid; // Guid that identifies event - ULONGLONG GuidPtr; // use with WNODE_FLAG_USE_GUID_PTR - } DUMMYUNIONNAME3; - union { - struct { - ULONG KernelTime; // Kernel Mode CPU ticks - ULONG UserTime; // User mode CPU ticks - } DUMMYSTRUCTNAME; - ULONG64 ProcessorTime; // Processor Clock - struct { - ULONG ClientContext; // Reserved - ULONG Flags; // Event Flags - } DUMMYSTRUCTNAME2; - } DUMMYUNIONNAME4; -} EVENT_TRACE_HEADER, *PEVENT_TRACE_HEADER; - -typedef struct _EVENT_TRACE { - EVENT_TRACE_HEADER Header; // Event trace header - ULONG InstanceId; // Instance Id of this event - ULONG ParentInstanceId; // Parent Instance Id. - GUID ParentGuid; // Parent Guid; - PVOID MofData; // Pointer to Variable Data - ULONG MofLength; // Variable Datablock Length - union { - ULONG ClientContext; - ETW_BUFFER_CONTEXT BufferContext; - } DUMMYUNIONNAME; -} EVENT_TRACE, *PEVENT_TRACE; - -typedef struct _TRACE_LOGFILE_HEADER { - ULONG BufferSize; // Logger buffer size in Kbytes - union { - ULONG Version; // Logger version - struct { - UCHAR MajorVersion; - UCHAR MinorVersion; - UCHAR SubVersion; - UCHAR SubMinorVersion; - } VersionDetail; - } DUMMYUNIONNAME; - ULONG ProviderVersion; // defaults to NT version - ULONG NumberOfProcessors; // Number of Processors - LARGE_INTEGER EndTime; // Time when logger stops - ULONG TimerResolution; // assumes timer is constant!!! - ULONG MaximumFileSize; // Maximum in Mbytes - ULONG LogFileMode; // specify logfile mode - ULONG BuffersWritten; // used to file start of Circular File - union { - GUID LogInstanceGuid; // For RealTime Buffer Delivery - struct { - ULONG StartBuffers; // Count of buffers written at start. - ULONG PointerSize; // Size of pointer type in bits - ULONG EventsLost; // Events losts during log session - ULONG CpuSpeedInMHz; // Cpu Speed in MHz - } DUMMYSTRUCTNAME; - } DUMMYUNIONNAME2; -#if defined(_WMIKM_) - PWCHAR LoggerName; - PWCHAR LogFileName; - RTL_TIME_ZONE_INFORMATION TimeZone; -#else - LPWSTR LoggerName; - LPWSTR LogFileName; - TIME_ZONE_INFORMATION TimeZone; -#endif - LARGE_INTEGER BootTime; - LARGE_INTEGER PerfFreq; // Reserved - LARGE_INTEGER StartTime; // Reserved - ULONG ReservedFlags; // ClockType - ULONG BuffersLost; -} TRACE_LOGFILE_HEADER, *PTRACE_LOGFILE_HEADER; - -typedef enum _TRACE_QUERY_INFO_CLASS { - TraceGuidQueryList, - TraceGuidQueryInfo, - TraceGuidQueryProcess, - TraceStackTracingInfo, // Win7 - TraceSystemTraceEnableFlagsInfo, - TraceSampledProfileIntervalInfo, - TraceProfileSourceConfigInfo, - TraceProfileSourceListInfo, - TracePmcEventListInfo, - TracePmcCounterListInfo, - MaxTraceSetInfoClass -} TRACE_QUERY_INFO_CLASS, TRACE_INFO_CLASS; - -typedef struct _CLASSIC_EVENT_ID { - GUID EventGuid; - UCHAR Type; - UCHAR Reserved[7]; -} CLASSIC_EVENT_ID, *PCLASSIC_EVENT_ID; - -typedef struct _TRACE_PROFILE_INTERVAL { - ULONG Source; - ULONG Interval; -} TRACE_PROFILE_INTERVAL, *PTRACE_PROFILE_INTERVAL; - -typedef struct _EVENT_TRACE_LOGFILEW -EVENT_TRACE_LOGFILEW, *PEVENT_TRACE_LOGFILEW; - -typedef ULONG(WINAPI * PEVENT_TRACE_BUFFER_CALLBACKW) -(PEVENT_TRACE_LOGFILEW Logfile); - -typedef VOID(WINAPI *PEVENT_CALLBACK)(PEVENT_TRACE pEvent); - -typedef struct _EVENT_RECORD -EVENT_RECORD, *PEVENT_RECORD; - -typedef VOID(WINAPI *PEVENT_RECORD_CALLBACK) (PEVENT_RECORD EventRecord); - -struct _EVENT_TRACE_LOGFILEW { - LPWSTR LogFileName; // Logfile Name - LPWSTR LoggerName; // LoggerName - LONGLONG CurrentTime; // timestamp of last event - ULONG BuffersRead; // buffers read to date - union { - // Mode of the logfile - ULONG LogFileMode; - // Processing flags used on Vista and above - ULONG ProcessTraceMode; - } DUMMYUNIONNAME; - EVENT_TRACE CurrentEvent; // Current Event from this stream. - TRACE_LOGFILE_HEADER LogfileHeader; // logfile header structure - PEVENT_TRACE_BUFFER_CALLBACKW // callback before each buffer - BufferCallback; // is read - // - // following variables are filled for BufferCallback. - // - ULONG BufferSize; - ULONG Filled; - ULONG EventsLost; - // - // following needs to be propaged to each buffer - // - union { - // Callback with EVENT_TRACE - PEVENT_CALLBACK EventCallback; - // Callback with EVENT_RECORD on Vista and above - PEVENT_RECORD_CALLBACK EventRecordCallback; - } DUMMYUNIONNAME2; - - ULONG IsKernelTrace; // TRUE for kernel logfile - - PVOID Context; // reserved for internal use -}; - -#pragma warning(pop) - -#define PEVENT_TRACE_BUFFER_CALLBACK PEVENT_TRACE_BUFFER_CALLBACKW -#define EVENT_TRACE_LOGFILE EVENT_TRACE_LOGFILEW -#define PEVENT_TRACE_LOGFILE PEVENT_TRACE_LOGFILEW -#define KERNEL_LOGGER_NAME KERNEL_LOGGER_NAMEW -#define GLOBAL_LOGGER_NAME GLOBAL_LOGGER_NAMEW -#define EVENT_LOGGER_NAME EVENT_LOGGER_NAMEW - -EXTERN_C -ULONG -WMIAPI -ProcessTrace( - _In_reads_(HandleCount) PTRACEHANDLE HandleArray, - _In_ ULONG HandleCount, - _In_opt_ LPFILETIME StartTime, - _In_opt_ LPFILETIME EndTime -); - -EXTERN_C -ULONG -WMIAPI -StartTraceW( - _Out_ PTRACEHANDLE TraceHandle, - _In_ LPCWSTR InstanceName, - _Inout_ PEVENT_TRACE_PROPERTIES Properties -); - -EXTERN_C -ULONG -WMIAPI -ControlTraceW( - _In_ TRACEHANDLE TraceHandle, - _In_opt_ LPCWSTR InstanceName, - _Inout_ PEVENT_TRACE_PROPERTIES Properties, - _In_ ULONG ControlCode -); - -EXTERN_C -TRACEHANDLE -WMIAPI -OpenTraceW( - _Inout_ PEVENT_TRACE_LOGFILEW Logfile -); - -EXTERN_C -ULONG -WMIAPI -CloseTrace( - _In_ TRACEHANDLE TraceHandle -); - -EXTERN_C -ULONG -WMIAPI -TraceSetInformation( - _In_ TRACEHANDLE SessionHandle, - _In_ TRACE_INFO_CLASS InformationClass, - _In_reads_bytes_(InformationLength) PVOID TraceInformation, - _In_ ULONG InformationLength -); - -EXTERN_C -ULONG -WMIAPI -TraceQueryInformation( - _In_ TRACEHANDLE SessionHandle, - _In_ TRACE_INFO_CLASS InformationClass, - _Out_writes_bytes_(InformationLength) PVOID TraceInformation, - _In_ ULONG InformationLength, - _Out_opt_ PULONG ReturnLength -); - -////////////////////////////////////////////////////////////////////////// -#define RegisterTraceGuids RegisterTraceGuidsW -#define StartTrace StartTraceW -#define ControlTrace ControlTraceW -#define StopTrace StopTraceW -#define QueryTrace QueryTraceW -#define UpdateTrace UpdateTraceW -#define FlushTrace FlushTraceW -#define QueryAllTraces QueryAllTracesW -#define OpenTrace OpenTraceW -////////////////////////////////////////////////////////////////////////// -#else -#define INITGUID // Causes definition of SystemTraceControlGuid in evntrace.h. -#include <wmistr.h> -#include <evntrace.h> -#include <strsafe.h> -#include <evntcons.h> -#endif //DECLARE_ETW - -namespace Optick -{ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -class ETW : public Trace -{ - static const int ETW_BUFFER_SIZE = 1024 << 10; // 1Mb - static const int ETW_BUFFER_COUNT = 32; - static const int ETW_MAXIMUM_SESSION_NAME = 1024; - - EVENT_TRACE_PROPERTIES *traceProperties; - EVENT_TRACE_LOGFILE logFile; - TRACEHANDLE traceSessionHandle; - TRACEHANDLE openedHandle; - - HANDLE processThreadHandle; - DWORD currentProcessId; - - bool isActive; - - static DWORD WINAPI RunProcessTraceThreadFunction(LPVOID parameter); - static void AdjustPrivileges(); - - unordered_map<uint64_t, const EventDescription*> syscallDescriptions; - - void ResolveSysCalls(); -public: - - unordered_set<uint64> activeThreadsIDs; - - ETW(); - ~ETW(); - - virtual CaptureStatus::Type Start(Mode::Type mode, int frequency, const ThreadList& threads) override; - virtual bool Stop() override; - - DWORD GetProcessID() const { return currentProcessId; } -}; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct CSwitch -{ - // New thread ID after the switch. - uint32 NewThreadId; - - // Previous thread ID. - uint32 OldThreadId; - - // Thread priority of the new thread. - int8 NewThreadPriority; - - // Thread priority of the previous thread. - int8 OldThreadPriority; - - //The index of the C-state that was last used by the processor. A value of 0 represents the lightest idle state with higher values representing deeper C-states. - uint8 PreviousCState; - - // Not used. - int8 SpareByte; - - // Wait reason for the previous thread. The following are the possible values: - // 0 Executive - // 1 FreePage - // 2 PageIn - // 3 PoolAllocation - // 4 DelayExecution - // 5 Suspended - // 6 UserRequest - // 7 WrExecutive - // 8 WrFreePage - // 9 WrPageIn - // 10 WrPoolAllocation - // 11 WrDelayExecution - // 12 WrSuspended - // 13 WrUserRequest - // 14 WrEventPair - // 15 WrQueue - // 16 WrLpcReceive - // 17 WrLpcReply - // 18 WrVirtualMemory - // 19 WrPageOut - // 20 WrRendezvous - // 21 WrKeyedEvent - // 22 WrTerminated - // 23 WrProcessInSwap - // 24 WrCpuRateControl - // 25 WrCalloutStack - // 26 WrKernel - // 27 WrResource - // 28 WrPushLock - // 29 WrMutex - // 30 WrQuantumEnd - // 31 WrDispatchInt - // 32 WrPreempted - // 33 WrYieldExecution - // 34 WrFastMutex - // 35 WrGuardedMutex - // 36 WrRundown - // 37 MaximumWaitReason - int8 OldThreadWaitReason; - - // Wait mode for the previous thread. The following are the possible values: - // 0 KernelMode - // 1 UserMode - int8 OldThreadWaitMode; - - // State of the previous thread. The following are the possible state values: - // 0 Initialized - // 1 Ready - // 2 Running - // 3 Standby - // 4 Terminated - // 5 Waiting - // 6 Transition - // 7 DeferredReady (added for Windows Server 2003) - int8 OldThreadState; - - // Ideal wait time of the previous thread. - int8 OldThreadWaitIdealProcessor; - - // Wait time for the new thread. - uint32 NewThreadWaitTime; - - // Reserved. - uint32 Reserved; - - static const byte OPCODE = 36; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct StackWalk_Event -{ - // Original event time stamp from the event header - uint64 EventTimeStamp; - - // The process identifier of the original event - uint32 StackProcess; - - // The thread identifier of the original event - uint32 StackThread; - - // Callstack head - uint64 Stack0; - - static const byte OPCODE = 32; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct Thread_TypeGroup1 -{ - // Process identifier of the thread involved in the event. - uint32 ProcessId; - // Thread identifier of the thread involved in the event. - uint32 TThreadId; - // Base address of the thread's stack. - uint64 StackBase; - // Limit of the thread's stack. - uint64 StackLimit; - // Base address of the thread's user-mode stack. - uint64 UserStackBase; - // Limit of the thread's user-mode stack. - uint64 UserStackLimit; - // The set of processors on which the thread is allowed to run. - uint32 Affinity; - // Starting address of the function to be executed by this thread. - uint64 Win32StartAddr; - // Thread environment block base address. - uint64 TebBase; - // Identifies the service if the thread is owned by a service; otherwise, zero. - uint32 SubProcessTag; - // The scheduler priority of the thread - uint8 BasePriority; - // A memory page priority hint for memory pages accessed by the thread. - uint8 PagePriority; - // An IO priority hint for scheduling IOs generated by the thread. - uint8 IoPriority; - // Not used. - uint8 ThreadFlags; - - enum struct Opcode : uint8 - { - Start = 1, - End = 2, - DCStart = 3, - DCEnd = 4, - }; -}; - -size_t GetSIDSize(uint8* ptr) -{ - size_t result = 0; - - int sid = *((int*)ptr); - - if (sid != 0) - { - size_t tokenSize = 16; - ptr += tokenSize; - result += tokenSize; - result += 8 + (4 * ((SID*)ptr)->SubAuthorityCount); - } - else - { - result = 4; - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// https://github.com/Microsoft/perfview/blob/688a8564062d51321bbab53cd71d9e174a77d2ce/src/TraceEvent/TraceEvent.cs -struct Process_TypeGroup1 -{ - // The address of the process object in the kernel. - uint64 UniqueProcessKey; - // Global process identifier that you can use to identify a process. - uint32 ProcessId; - // Unique identifier of the process that creates this process. - uint32 ParentId; - // Unique identifier that an operating system generates when it creates a new session. - uint32 SessionId; - // Exit status of the stopped process. - int32 ExitStatus; - // The physical address of the page table of the process. - uint64 DirectoryTableBase; - // (?) uint8 Flags; - // object UserSID; - // string ImageFileName; - // wstring CommandLine; - - static size_t GetSIDOffset(PEVENT_RECORD pEvent) - { - if (pEvent->EventHeader.EventDescriptor.Version >= 4) - return 36; - - if (pEvent->EventHeader.EventDescriptor.Version == 3) - return 32; - - return 24; - } - - const char* GetProcessName(PEVENT_RECORD pEvent) const - { - OPTICK_ASSERT((pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_64_BIT_HEADER) != 0, "32-bit is not supported! Disable OPTICK_ENABLE_TRACING on 32-bit platform if needed!"); - size_t sidOffset = GetSIDOffset(pEvent); - size_t sidSize = GetSIDSize((uint8*)this + sidOffset); - return (char*)this + sidOffset + sidSize; - } - - enum struct Opcode - { - Start = 1, - End = 2, - DCStart = 3, - DCEnd = 4, - Defunct = 39, - }; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct SampledProfile -{ - uint32 InstructionPointer; - uint32 ThreadId; - uint32 Count; - - static const byte OPCODE = 46; -}; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct SysCallEnter -{ - uintptr_t SysCallAddress; - - static const byte OPCODE = 51; -}; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct SysCallExit -{ - uint32 SysCallNtStatus; - - static const byte OPCODE = 52; -}; - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// ce1dbfb4-137e-4da6-87b0-3f59aa102cbc -DEFINE_GUID(SampledProfileGuid, 0xce1dbfb4, 0x137e, 0x4da6, 0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc); - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c -// https://docs.microsoft.com/en-us/windows/desktop/etw/thread -DEFINE_GUID(ThreadGuid, 0x3d6fa8d1, 0xfe05, 0x11d0, 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c); - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c -// https://docs.microsoft.com/en-us/windows/desktop/etw/process -DEFINE_GUID(ProcessGuid, 0x3d6fa8d0, 0xfe05, 0x11d0, 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c); - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const int MAX_CPU_CORES = 256; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -struct ETWRuntime -{ - array<ThreadID, MAX_CPU_CORES> activeCores; - vector<std::pair<uint8_t, SysCallData*>> activeSyscalls; - - ETWRuntime() - { - Reset(); - } - - void Reset() - { - activeCores.fill(INVALID_THREAD_ID); - activeSyscalls.resize(0);; - } -}; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -ETWRuntime g_ETWRuntime; -ETW g_ETW; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void WINAPI OnRecordEvent(PEVENT_RECORD eventRecord) -{ - //static uint8 cpuCoreIsExecutingThreadFromOurProcess[256] = { 0 }; - - const byte opcode = eventRecord->EventHeader.EventDescriptor.Opcode; - - if (opcode == CSwitch::OPCODE) - { - if (sizeof(CSwitch) == eventRecord->UserDataLength) - { - CSwitch* pSwitchEvent = (CSwitch*)eventRecord->UserData; - - SwitchContextDesc desc; - desc.reason = pSwitchEvent->OldThreadWaitReason; - desc.cpuId = eventRecord->BufferContext.ProcessorNumber; - desc.oldThreadId = (uint64)pSwitchEvent->OldThreadId; - desc.newThreadId = (uint64)pSwitchEvent->NewThreadId; - desc.timestamp = eventRecord->EventHeader.TimeStamp.QuadPart; - Core::Get().ReportSwitchContext(desc); - - // Assign ThreadID to the cores - if (g_ETW.activeThreadsIDs.find(desc.newThreadId) != g_ETW.activeThreadsIDs.end()) - { - g_ETWRuntime.activeCores[desc.cpuId] = desc.newThreadId; - } - else if (g_ETW.activeThreadsIDs.find(desc.oldThreadId) != g_ETW.activeThreadsIDs.end()) - { - g_ETWRuntime.activeCores[desc.cpuId] = INVALID_THREAD_ID; - } - } - } - else if (opcode == StackWalk_Event::OPCODE) - { - if (eventRecord->UserData && eventRecord->UserDataLength >= sizeof(StackWalk_Event)) - { - //TODO: Support x86 windows kernels - const size_t osKernelPtrSize = sizeof(uint64); - - StackWalk_Event* pStackWalkEvent = (StackWalk_Event*)eventRecord->UserData; - uint32 count = 1 + (eventRecord->UserDataLength - sizeof(StackWalk_Event)) / osKernelPtrSize; - - if (count && pStackWalkEvent->StackThread != 0) - { - if (pStackWalkEvent->StackProcess == g_ETW.GetProcessID()) - { - CallstackDesc desc; - desc.threadID = pStackWalkEvent->StackThread; - desc.timestamp = pStackWalkEvent->EventTimeStamp; - - static_assert(osKernelPtrSize == sizeof(uint64), "Incompatible types!"); - desc.callstack = &pStackWalkEvent->Stack0; - - desc.count = (uint8)count; - Core::Get().ReportStackWalk(desc); - } - } - } - } - else if (opcode == SampledProfile::OPCODE) - { - SampledProfile* pEvent = (SampledProfile*)eventRecord->UserData; - OPTICK_UNUSED(pEvent); - } - else if (opcode == SysCallEnter::OPCODE) - { - if (eventRecord->UserDataLength >= sizeof(SysCallEnter)) - { - uint8_t cpuId = eventRecord->BufferContext.ProcessorNumber; - uint64_t threadId = g_ETWRuntime.activeCores[cpuId]; - - if (threadId != INVALID_THREAD_ID) - { - SysCallEnter* pEventEnter = (SysCallEnter*)eventRecord->UserData; - - SysCallData& sysCall = Core::Get().syscallCollector.Add(); - sysCall.start = eventRecord->EventHeader.TimeStamp.QuadPart; - sysCall.finish = EventTime::INVALID_TIMESTAMP; - sysCall.threadID = threadId; - sysCall.id = pEventEnter->SysCallAddress; - sysCall.description = nullptr; - - g_ETWRuntime.activeSyscalls.push_back(std::make_pair(cpuId, &sysCall)); - } - } - } - else if (opcode == SysCallExit::OPCODE) - { - if (eventRecord->UserDataLength >= sizeof(SysCallExit)) - { - uint8_t cpuId = eventRecord->BufferContext.ProcessorNumber; - if (g_ETWRuntime.activeCores[cpuId] != INVALID_THREAD_ID) - { - for (int i = (int)g_ETWRuntime.activeSyscalls.size() - 1; i >= 0; --i) - { - if (g_ETWRuntime.activeSyscalls[i].first == cpuId) - { - g_ETWRuntime.activeSyscalls[i].second->finish = eventRecord->EventHeader.TimeStamp.QuadPart; - g_ETWRuntime.activeSyscalls.erase(g_ETWRuntime.activeSyscalls.begin() + i); - break; - } - } - } - } - } - else - { - // VS TODO: We might have a situation where a thread was deleted and the new thread was created with the same threadID - // Ignoring for now - profiling sessions are quite short - not critical - if (IsEqualGUID(eventRecord->EventHeader.ProviderId, ThreadGuid)) - { - if (eventRecord->UserDataLength >= sizeof(Thread_TypeGroup1)) - { - const Thread_TypeGroup1* pThreadEvent = (const Thread_TypeGroup1*)eventRecord->UserData; - Core::Get().RegisterThreadDescription(ThreadDescription("", pThreadEvent->TThreadId, pThreadEvent->ProcessId, 1, pThreadEvent->BasePriority)); - } - - } - else if (IsEqualGUID(eventRecord->EventHeader.ProviderId, ProcessGuid)) - { - if (eventRecord->UserDataLength >= sizeof(Process_TypeGroup1)) - { - const Process_TypeGroup1* pProcessEvent = (const Process_TypeGroup1*)eventRecord->UserData; - Core::Get().RegisterProcessDescription(ProcessDescription(pProcessEvent->GetProcessName(eventRecord), pProcessEvent->ProcessId, pProcessEvent->UniqueProcessKey)); - } - } - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static ULONG WINAPI OnBufferRecord(_In_ PEVENT_TRACE_LOGFILE Buffer) -{ - OPTICK_UNUSED(Buffer); - return true; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const TRACEHANDLE INVALID_TRACEHANDLE = (TRACEHANDLE)-1; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -DWORD WINAPI ETW::RunProcessTraceThreadFunction(LPVOID parameter) -{ - Core::Get().RegisterThreadDescription(ThreadDescription("[Optick] ETW", GetCurrentThreadId(), GetCurrentProcessId())); - ETW* etw = (ETW*)parameter; - ULONG status = ProcessTrace(&etw->openedHandle, 1, 0, 0); - OPTICK_UNUSED(status); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void ETW::AdjustPrivileges() -{ -#if OPTICK_PC - HANDLE token = 0; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) - { - TOKEN_PRIVILEGES tokenPrivileges; - memset(&tokenPrivileges, 0, sizeof(tokenPrivileges)); - tokenPrivileges.PrivilegeCount = 1; - tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - LookupPrivilegeValue(NULL, SE_SYSTEM_PROFILE_NAME, &tokenPrivileges.Privileges[0].Luid); - - AdjustTokenPrivileges(token, FALSE, &tokenPrivileges, 0, (PTOKEN_PRIVILEGES)NULL, 0); - CloseHandle(token); - } -#endif -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void ETW::ResolveSysCalls() -{ - if (SymbolEngine* symEngine = Platform::GetSymbolEngine()) - { - Core::Get().syscallCollector.syscallPool.ForEach([this, symEngine](SysCallData& data) - { - auto it = syscallDescriptions.find(data.id); - if (it == syscallDescriptions.end()) - { - const Symbol* symbol = symEngine->GetSymbol(data.id); - if (symbol != nullptr) - { - string name(symbol->function.begin(), symbol->function.end()); - - data.description = EventDescription::CreateShared(name.c_str(), "SysCall", (long)data.id); - syscallDescriptions.insert(std::pair<const uint64_t, const EventDescription *>(data.id, data.description)); - } - } - else - { - data.description = it->second; - } - }); - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -ETW::ETW() - : isActive(false) - , traceSessionHandle(INVALID_TRACEHANDLE) - , openedHandle(INVALID_TRACEHANDLE) - , processThreadHandle(INVALID_HANDLE_VALUE) - , traceProperties(nullptr) -{ - currentProcessId = GetCurrentProcessId(); -} - -CaptureStatus::Type ETW::Start(Mode::Type mode, int frequency, const ThreadList& threads) -{ - if (!isActive) - { - AdjustPrivileges(); - - g_ETWRuntime.Reset(); - - activeThreadsIDs.clear(); - for (auto it = threads.begin(); it != threads.end(); ++it) - { - ThreadEntry* entry = *it; - if (entry->isAlive) - { - activeThreadsIDs.insert(entry->description.threadID); - } - } - - - ULONG bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + (ETW_MAXIMUM_SESSION_NAME + MAX_PATH) * sizeof(WCHAR); - if (traceProperties == nullptr) - traceProperties = (EVENT_TRACE_PROPERTIES*)Memory::Alloc(bufferSize); - ZeroMemory(traceProperties, bufferSize); - traceProperties->Wnode.BufferSize = bufferSize; - traceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); - StringCchCopyW((LPWSTR)((PCHAR)traceProperties + traceProperties->LoggerNameOffset), ETW_MAXIMUM_SESSION_NAME, KERNEL_LOGGER_NAMEW); - traceProperties->EnableFlags = 0; - - traceProperties->BufferSize = ETW_BUFFER_SIZE; - traceProperties->MinimumBuffers = ETW_BUFFER_COUNT; - - if (mode & Mode::SWITCH_CONTEXT) - { - traceProperties->EnableFlags |= EVENT_TRACE_FLAG_CSWITCH; - } - - if (mode & Mode::AUTOSAMPLING) - { - traceProperties->EnableFlags |= EVENT_TRACE_FLAG_PROFILE; - } - - if (mode & Mode::SYS_CALLS) - { - traceProperties->EnableFlags |= EVENT_TRACE_FLAG_SYSTEMCALL; - } - - if (mode & Mode::OTHER_PROCESSES) - { - traceProperties->EnableFlags |= EVENT_TRACE_FLAG_PROCESS; - traceProperties->EnableFlags |= EVENT_TRACE_FLAG_THREAD; - } - - traceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; - traceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; - // - // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364160(v=vs.85).aspx - // Clock resolution = QPC - traceProperties->Wnode.ClientContext = 1; - traceProperties->Wnode.Guid = SystemTraceControlGuid; - - // ERROR_BAD_LENGTH(24): The Wnode.BufferSize member of Properties specifies an incorrect size. Properties does not have sufficient space allocated to hold a copy of SessionName. - // ERROR_ALREADY_EXISTS(183): A session with the same name or GUID is already running. - // ERROR_ACCESS_DENIED(5): Only users with administrative privileges, users in the Performance Log Users group, and services running as LocalSystem, LocalService, NetworkService can control event tracing sessions. - // ERROR_INVALID_PARAMETER(87) - // ERROR_BAD_PATHNAME(161) - // ERROR_DISK_FULL(112) - // ERROR_NO_SUCH_PRIVILEGE(1313) - int retryCount = 4; - ULONG status = CaptureStatus::OK; - - while (--retryCount >= 0) - { - status = StartTrace(&traceSessionHandle, KERNEL_LOGGER_NAME, traceProperties); - - switch (status) - { - case ERROR_NO_SUCH_PRIVILEGE: - AdjustPrivileges(); - break; - - case ERROR_ALREADY_EXISTS: - ControlTrace(0, KERNEL_LOGGER_NAME, traceProperties, EVENT_TRACE_CONTROL_STOP); - break; - - case ERROR_ACCESS_DENIED: - return CaptureStatus::ERR_TRACER_ACCESS_DENIED; - - case ERROR_SUCCESS: - retryCount = 0; - break; - - default: - return CaptureStatus::ERR_TRACER_FAILED; - } - } - - if (status != ERROR_SUCCESS) - { - return CaptureStatus::ERR_TRACER_FAILED; - } - - CLASSIC_EVENT_ID callstackSamples[4]; - int callstackCountSamplesCount = 0; - - if (mode & Mode::AUTOSAMPLING) - { - callstackSamples[callstackCountSamplesCount].EventGuid = SampledProfileGuid; - callstackSamples[callstackCountSamplesCount].Type = SampledProfile::OPCODE; - ++callstackCountSamplesCount; - } - - if (mode & Mode::SYS_CALLS) - { - callstackSamples[callstackCountSamplesCount].EventGuid = SampledProfileGuid; - callstackSamples[callstackCountSamplesCount].Type = SysCallEnter::OPCODE; - ++callstackCountSamplesCount; - } - - /* - callstackSamples[callstackCountSamplesCount].EventGuid = CSwitchProfileGuid; - callstackSamples[callstackCountSamplesCount].Type = CSwitch::OPCODE; - ++callstackCountSamplesCount; - */ - - - /* - https://msdn.microsoft.com/en-us/library/windows/desktop/dd392328%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 - Typically, on 64-bit computers, you cannot capture the kernel stack in certain contexts when page faults are not allowed. To enable walking the kernel stack on x64, set - the DisablePagingExecutive Memory Management registry value to 1. The DisablePagingExecutive registry value is located under the following registry key: - HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management - */ - if (callstackCountSamplesCount > 0) - { - status = TraceSetInformation(traceSessionHandle, TraceStackTracingInfo, &callstackSamples[0], sizeof(CLASSIC_EVENT_ID) * callstackCountSamplesCount); - if (status != ERROR_SUCCESS) - { - OPTICK_FAILED("TraceSetInformation - failed"); - return CaptureStatus::ERR_TRACER_FAILED; - } - } - - if (mode & Mode::AUTOSAMPLING) - { - TRACE_PROFILE_INTERVAL itnerval = { 0 }; - memset(&itnerval, 0, sizeof(TRACE_PROFILE_INTERVAL)); - int step = 10000 * 1000 / frequency; // 1ms = 10000 steps - itnerval.Interval = step; // std::max(1221, std::min(step, 10000)); - // The SessionHandle is irrelevant for this information class and must be zero, else the function returns ERROR_INVALID_PARAMETER. - status = TraceSetInformation(0, TraceSampledProfileIntervalInfo, &itnerval, sizeof(TRACE_PROFILE_INTERVAL)); - OPTICK_ASSERT(status == ERROR_SUCCESS, "TraceSetInformation - failed"); - } - - ZeroMemory(&logFile, sizeof(EVENT_TRACE_LOGFILE)); - logFile.LoggerName = KERNEL_LOGGER_NAME; - logFile.ProcessTraceMode = (PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP); - logFile.EventRecordCallback = OnRecordEvent; - logFile.BufferCallback = OnBufferRecord; - openedHandle = OpenTrace(&logFile); - if (openedHandle == INVALID_TRACEHANDLE) - { - OPTICK_FAILED("OpenTrace - failed"); - return CaptureStatus::ERR_TRACER_FAILED; - } - - DWORD threadID; - processThreadHandle = CreateThread(0, 0, RunProcessTraceThreadFunction, this, 0, &threadID); - - isActive = true; - } - - return CaptureStatus::OK; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool ETW::Stop() -{ - if (!isActive) - { - return false; - } - - ULONG controlTraceResult = ControlTrace(openedHandle, KERNEL_LOGGER_NAME, traceProperties, EVENT_TRACE_CONTROL_STOP); - - // ERROR_CTX_CLOSE_PENDING(7007L): The call was successful. The ProcessTrace function will stop after it has processed all real-time events in its buffers (it will not receive any new events). - // ERROR_BUSY(170L): Prior to Windows Vista, you cannot close the trace until the ProcessTrace function completes. - // ERROR_INVALID_HANDLE(6L): One of the following is true: TraceHandle is NULL. TraceHandle is INVALID_HANDLE_VALUE. - ULONG closeTraceStatus = CloseTrace(openedHandle); - - // Wait for ProcessThread to finish - WaitForSingleObject(processThreadHandle, INFINITE); - BOOL wasThreadClosed = CloseHandle(processThreadHandle); - - isActive = false; - - //VS TODO: Disabling resolving of the syscalls - we can't use then as EventDescriptions at the moment - //ResolveSysCalls(); - - activeThreadsIDs.clear(); - - return wasThreadClosed && (closeTraceStatus == ERROR_SUCCESS) && (controlTraceResult == ERROR_SUCCESS); -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -ETW::~ETW() -{ - Stop(); - Memory::Free(traceProperties); - traceProperties = nullptr; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -Trace* Platform::GetTrace() -{ - return &g_ETW; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Symbol Resolving -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define USE_DBG_HELP (OPTICK_PC) - -#if USE_DBG_HELP -#include <DbgHelp.h> -#pragma comment( lib, "DbgHelp.Lib" ) -#endif - -#include "optick_serialization.h" - -#if OPTICK_PC -#include <psapi.h> -#else -// Forward declare kernel functions -#pragma pack(push,8) -typedef struct _MODULEINFO { - LPVOID lpBaseOfDll; - DWORD SizeOfImage; - LPVOID EntryPoint; -} MODULEINFO, *LPMODULEINFO; -#pragma pack(pop) -#ifndef EnumProcessModulesEx -#define EnumProcessModulesEx K32EnumProcessModulesEx -EXTERN_C DWORD WINAPI K32EnumProcessModulesEx(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded, DWORD dwFilterFlag); -#endif -#ifndef GetModuleInformation -#define GetModuleInformation K32GetModuleInformation -EXTERN_C DWORD WINAPI K32GetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb); -#endif - -#ifndef GetModuleFileNameExA -#define GetModuleFileNameExA K32GetModuleFileNameExA -EXTERN_C DWORD WINAPI K32GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize); -#endif -#endif - -namespace Optick -{ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//void ReportLastError() -//{ -// LPVOID lpMsgBuf; -// DWORD dw = GetLastError(); -// -// FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, -// NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), -// (LPTSTR)&lpMsgBuf, 0, NULL); -// -// MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error"), MB_OK); -// LocalFree(lpMsgBuf); -//} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -typedef array<uintptr_t, 512> CallStackBuffer; -typedef unordered_map<uint64, Symbol> SymbolCache; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -class WinSymbolEngine : public SymbolEngine -{ - HANDLE hProcess; - - bool isInitialized; - - bool needRestorePreviousSettings; - uint32 previousOptions; - static const size_t MAX_SEARCH_PATH_LENGTH = 2048; - char previousSearchPath[MAX_SEARCH_PATH_LENGTH]; - - SymbolCache cache; - vector<Module> modules; - - void InitSystemModules(); - void InitApplicationModules(); -public: - WinSymbolEngine(); - ~WinSymbolEngine(); - - void Init(); - void Close(); - - // Get Symbol from PDB file - virtual const Symbol * GetSymbol(uint64 dwAddress) override; - virtual const vector<Module>& GetModules() override; -}; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -WinSymbolEngine::WinSymbolEngine() : isInitialized(false), hProcess(GetCurrentProcess()), needRestorePreviousSettings(false), previousOptions(0) -{ -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -WinSymbolEngine::~WinSymbolEngine() -{ - Close(); -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const Symbol* WinSymbolEngine::GetSymbol(uint64 address) -{ - if (address == 0) - return nullptr; - - Init(); - - Symbol& symbol = cache[address]; - - if (symbol.address != 0) - return &symbol; - - if (!isInitialized) - return nullptr; - - symbol.address = address; - -#if USE_DBG_HELP - DWORD64 dwAddress = static_cast<DWORD64>(address); - - // FileName and Line - IMAGEHLP_LINEW64 lineInfo; - memset(&lineInfo, 0, sizeof(IMAGEHLP_LINEW64)); - lineInfo.SizeOfStruct = sizeof(lineInfo); - DWORD dwDisp; - if (SymGetLineFromAddrW64(hProcess, dwAddress, &dwDisp, &lineInfo)) - { - symbol.file = lineInfo.FileName; - symbol.line = lineInfo.LineNumber; - } - - const size_t length = (sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(WCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64) + 1; - - // Function Name - ULONG64 buffer[length]; - PSYMBOL_INFOW dbgSymbol = (PSYMBOL_INFOW)buffer; - memset(dbgSymbol, 0, sizeof(buffer)); - dbgSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW); - dbgSymbol->MaxNameLen = MAX_SYM_NAME; - - DWORD64 offset = 0; - if (SymFromAddrW(hProcess, dwAddress, &offset, dbgSymbol)) - { - symbol.function.resize(dbgSymbol->NameLen); - memcpy(&symbol.function[0], &dbgSymbol->Name[0], sizeof(WCHAR) * dbgSymbol->NameLen); - } - - symbol.offset = static_cast<uintptr_t>(offset); -#endif - - return &symbol; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -const vector<Module>& WinSymbolEngine::GetModules() -{ - if (modules.empty()) - { - InitSystemModules(); - InitApplicationModules(); - } - return modules; -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// const char* USER_SYMBOL_SEARCH_PATH = "http://msdl.microsoft.com/download/symbols"; -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void WinSymbolEngine::Init() -{ - if (!isInitialized) - { -#if USE_DBG_HELP - previousOptions = SymGetOptions(); - - memset(previousSearchPath, 0, MAX_SEARCH_PATH_LENGTH); - SymGetSearchPath(hProcess, previousSearchPath, MAX_SEARCH_PATH_LENGTH); - - SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_LOAD_ANYTHING); - if (!SymInitialize(hProcess, NULL, TRUE)) - { - needRestorePreviousSettings = true; - SymCleanup(hProcess); - - if (SymInitialize(hProcess, NULL, TRUE)) - isInitialized = true; - } - else - { - isInitialized = true; - } - - const vector<Module>& loadedModules = GetModules(); - for (size_t i = 0; i < loadedModules.size(); ++i) - { - const Module& module = loadedModules[i]; - SymLoadModule64(hProcess, NULL, module.path.c_str(), NULL, (DWORD64)module.address, (DWORD)module.size); - } - -#else - isInitialized = true; -#endif - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -typedef DWORD(__stdcall *pZwQuerySystemInformation)(DWORD, LPVOID, DWORD, DWORD*); -#define SystemModuleInformation 11 // SYSTEMINFOCLASS -#define MAXIMUM_FILENAME_LENGTH 256 - -struct SYSTEM_MODULE_INFORMATION -{ - DWORD reserved1; - DWORD reserved2; - PVOID mappedBase; - PVOID imageBase; - DWORD imageSize; - DWORD flags; - WORD loadOrderIndex; - WORD initOrderIndex; - WORD loadCount; - WORD moduleNameOffset; - CHAR imageName[MAXIMUM_FILENAME_LENGTH]; -}; - -#pragma warning (push) -#pragma warning(disable : 4200) -struct MODULE_LIST -{ - DWORD dwModules; - SYSTEM_MODULE_INFORMATION pModulesInfo[]; -}; -#pragma warning (pop) - -void WinSymbolEngine::InitSystemModules() -{ - ULONG returnLength = 0; - ULONG systemInformationLength = 0; - MODULE_LIST* pModuleList = nullptr; - -#pragma warning (push) -#pragma warning(disable : 4191) - pZwQuerySystemInformation ZwQuerySystemInformation = (pZwQuerySystemInformation)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "ZwQuerySystemInformation"); -#pragma warning (pop) - - ZwQuerySystemInformation(SystemModuleInformation, pModuleList, systemInformationLength, &returnLength); - systemInformationLength = returnLength; - pModuleList = (MODULE_LIST*)Memory::Alloc(systemInformationLength); - DWORD status = ZwQuerySystemInformation(SystemModuleInformation, pModuleList, systemInformationLength, &returnLength); - if (status == ERROR_SUCCESS) - { - char systemRootPath[MAXIMUM_FILENAME_LENGTH] = { 0 }; -#if OPTICK_PC - ExpandEnvironmentStringsA("%SystemRoot%", systemRootPath, MAXIMUM_FILENAME_LENGTH); -#else - strcpy_s(systemRootPath, "C:\\Windows"); -#endif - - const char* systemRootPattern = "\\SystemRoot"; - - modules.reserve(modules.size() + pModuleList->dwModules); - - for (uint32_t i = 0; i < pModuleList->dwModules; ++i) - { - SYSTEM_MODULE_INFORMATION& module = pModuleList->pModulesInfo[i]; - - char path[MAXIMUM_FILENAME_LENGTH] = { 0 }; - - if (strstr(module.imageName, systemRootPattern) == module.imageName) - { - strcpy_s(path, systemRootPath); - strcat_s(path, module.imageName + strlen(systemRootPattern)); - } - else - { - strcpy_s(path, module.imageName); - } - - modules.push_back(Module(path, (void*)module.imageBase, module.imageSize)); - } - } - else - { - OPTICK_FAILED("Can't query System Module Information!"); - } - - if (pModuleList) - { - Memory::Free(pModuleList); - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void WinSymbolEngine::InitApplicationModules() -{ - HANDLE processHandle = GetCurrentProcess(); - HMODULE hModules[256]; - DWORD modulesSize = 0; - EnumProcessModulesEx(processHandle, hModules, sizeof(hModules), &modulesSize, 0); - - int moduleCount = modulesSize / sizeof(HMODULE); - - modules.reserve(modules.size() + moduleCount); - - for (int i = 0; i < moduleCount; ++i) - { - MODULEINFO info = { 0 }; - if (GetModuleInformation(processHandle, hModules[i], &info, sizeof(MODULEINFO))) - { - char name[MAX_PATH] = "UnknownModule"; - GetModuleFileNameExA(processHandle, hModules[i], name, MAX_PATH); - - modules.push_back(Module(name, info.lpBaseOfDll, info.SizeOfImage)); - } - } -} -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void WinSymbolEngine::Close() -{ - if (isInitialized) - { -#if USE_DBG_HELP - SymCleanup(hProcess); - if (needRestorePreviousSettings) - { - HANDLE currentProcess = GetCurrentProcess(); - - SymSetOptions(previousOptions); - SymSetSearchPath(currentProcess, previousSearchPath); - SymInitialize(currentProcess, NULL, TRUE); - - needRestorePreviousSettings = false; - } -#endif - modules.clear(); - isInitialized = false; - } -} -////////////////////////////////////////////////////////////////////////// -SymbolEngine* Platform::GetSymbolEngine() -{ - static WinSymbolEngine pdbSymbolEngine; - return &pdbSymbolEngine; -} -////////////////////////////////////////////////////////////////////////// -} -#endif //OPTICK_ENABLE_TRACING -#endif //USE_OPTICK -#endif //_MSC_VER
\ No newline at end of file |