зеркало из https://github.com/microsoft/BPerf.git
Integrate from internal VSTS to GitHub
This commit is contained in:
Родитель
39ca5dcf4d
Коммит
db5e96532f
|
@ -1,248 +0,0 @@
|
||||||
#include <thread>
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <Evntprov.h>
|
|
||||||
#include <Evntcons.h>
|
|
||||||
#include <Evntrace.h>
|
|
||||||
#include <strsafe.h>
|
|
||||||
|
|
||||||
#define USAGE L"Usage: BPerfSymbolDataCollector LogsDirectory [ProcesNameFilters]\n"
|
|
||||||
#define EXAMPLE L"Example: BPerfSymbolDataCollector D:\\Data\\BPerfSymbols w3wp.exe\n"
|
|
||||||
#define EXAMPLE2 L"Example: BPerfSymbolDataCollector D:\\Data\\BPerfSymbols w3wp.exe;sql.exe\n"
|
|
||||||
|
|
||||||
#define CTRLCHANDLDED L"Ctrl+C handled, stopping session.\n"
|
|
||||||
#define LOGSESSION_NAME L"BPerfSymbols"
|
|
||||||
#define SYMBOLS_FILE_NAME L"Symbols.bin"
|
|
||||||
#define MAX_EVENT_SIZE 65536
|
|
||||||
#define UCHAR_SIZE 1
|
|
||||||
#define USHORT_SIZE 2
|
|
||||||
#define ULONG_SIZE 4
|
|
||||||
#define LARGE_INTEGER_SIZE 8
|
|
||||||
#define ULONGLONGSIZE 8
|
|
||||||
#define GUID_SIZE 16
|
|
||||||
#define CLRJITANDLOADERKEYWORD 0x00000018
|
|
||||||
|
|
||||||
constexpr GUID ClrRundownProviderGuid = {0xA669021C, 0xC450, 0x4609, {0xA0, 0x35, 0x5A, 0xF5, 0x9A, 0xF4, 0xDF, 0x18}}; // {A669021C-C450-4609-A035-5AF59AF4DF18}
|
|
||||||
constexpr GUID ClrProviderGuid = {0xE13C0D23, 0xCCBC, 0x4E12, {0x93, 0x1B, 0xD9, 0xCC, 0x2E, 0xEE, 0x27, 0xE4}}; // {E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4}
|
|
||||||
constexpr GUID CoreClrProviderGuid = {0x319DC449, 0xADA5, 0x50F7, {0x42, 0x8E, 0x95, 0x7D, 0xB6, 0x79, 0x16, 0x68}}; // {319DC449-ADA5-50F7-428E-957DB6791668}
|
|
||||||
|
|
||||||
constexpr USHORT DCStopComplete = 146;
|
|
||||||
|
|
||||||
/* Begin Global Data */
|
|
||||||
|
|
||||||
TRACEHANDLE sessionHandle;
|
|
||||||
HANDLE outputFile;
|
|
||||||
BYTE writeBuffer[MAX_EVENT_SIZE];
|
|
||||||
bool ctrlCTriggered = false;
|
|
||||||
|
|
||||||
/* End Global Data */
|
|
||||||
|
|
||||||
BOOL WINAPI ConsoleControlHandler(DWORD ctrlType)
|
|
||||||
{
|
|
||||||
switch (ctrlType)
|
|
||||||
{
|
|
||||||
case CTRL_C_EVENT:
|
|
||||||
case CTRL_BREAK_EVENT:
|
|
||||||
wprintf(CTRLCHANDLDED);
|
|
||||||
ctrlCTriggered = true;
|
|
||||||
EVENT_TRACE_PROPERTIES properties;
|
|
||||||
ZeroMemory(&properties, sizeof(EVENT_TRACE_PROPERTIES));
|
|
||||||
properties.Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES);
|
|
||||||
ControlTrace(0, LOGSESSION_NAME, &properties, EVENT_TRACE_CONTROL_STOP);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG WINAPI BufferCallback(_In_ PEVENT_TRACE_LOGFILEW callBack)
|
|
||||||
{
|
|
||||||
UNREFERENCED_PARAMETER(callBack);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID WINAPI EventCallback(_In_ PEVENT_RECORD eventRecord)
|
|
||||||
{
|
|
||||||
CopyMemory(writeBuffer, &eventRecord->EventHeader.TimeStamp, LARGE_INTEGER_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE, &eventRecord->EventHeader.ProcessId, ULONG_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE, &eventRecord->EventHeader.ThreadId, ULONG_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE, &eventRecord->EventHeader.ProviderId, GUID_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE, &eventRecord->EventHeader.EventDescriptor.Id, USHORT_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE, &eventRecord->EventHeader.EventDescriptor.Version, UCHAR_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE, &eventRecord->EventHeader.EventDescriptor.Level, UCHAR_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE, &eventRecord->EventHeader.EventDescriptor.Channel, UCHAR_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE, &eventRecord->EventHeader.EventDescriptor.Opcode, UCHAR_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE, &eventRecord->EventHeader.EventDescriptor.Task, USHORT_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + USHORT_SIZE, &eventRecord->EventHeader.EventDescriptor.Keyword, ULONGLONGSIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + USHORT_SIZE + ULONGLONGSIZE, &eventRecord->UserDataLength, USHORT_SIZE);
|
|
||||||
CopyMemory(writeBuffer + LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + USHORT_SIZE + ULONGLONGSIZE + USHORT_SIZE, eventRecord->UserData, eventRecord->UserDataLength);
|
|
||||||
|
|
||||||
DWORD numbBytesToWrite = LARGE_INTEGER_SIZE + ULONG_SIZE + ULONG_SIZE + GUID_SIZE + USHORT_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + UCHAR_SIZE + USHORT_SIZE + ULONGLONGSIZE + USHORT_SIZE + eventRecord->UserDataLength, offset = 0;
|
|
||||||
DWORD numberOfBytesWritten = 0;
|
|
||||||
|
|
||||||
while (WriteFile(outputFile, writeBuffer + offset, numbBytesToWrite, &numberOfBytesWritten, nullptr))
|
|
||||||
{
|
|
||||||
if (numberOfBytesWritten == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += numberOfBytesWritten;
|
|
||||||
numbBytesToWrite -= numberOfBytesWritten;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == ClrRundownProviderGuid && eventRecord->EventHeader.EventDescriptor.Id == DCStopComplete)
|
|
||||||
{
|
|
||||||
EnableTraceEx2(sessionHandle, &ClrRundownProviderGuid, EVENT_CONTROL_CODE_DISABLE_PROVIDER, TRACE_LEVEL_VERBOSE, 0, 0, 0, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT StartSymbolicDataSession(_In_ LPWSTR sessionName, _In_ LPCWSTR outputFileName, _In_opt_ LPCWSTR exeNamesFilter)
|
|
||||||
{
|
|
||||||
auto sessionNameSizeInBytes = (wcslen(sessionName) + 1) * sizeof(WCHAR);
|
|
||||||
auto bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sessionNameSizeInBytes + sizeof(WCHAR); // for '\0'
|
|
||||||
auto sessionProperties = static_cast<PEVENT_TRACE_PROPERTIES>(malloc(bufferSize));
|
|
||||||
|
|
||||||
if (sessionProperties == nullptr)
|
|
||||||
{
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZeroMemory(sessionProperties, bufferSize);
|
|
||||||
|
|
||||||
sessionProperties->Wnode.BufferSize = static_cast<ULONG>(bufferSize);
|
|
||||||
sessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|
||||||
sessionProperties->Wnode.ClientContext = 1;
|
|
||||||
|
|
||||||
sessionProperties->MinimumBuffers = max(64, std::thread::hardware_concurrency() * 2);
|
|
||||||
sessionProperties->MaximumBuffers = sessionProperties->MinimumBuffers * 2;
|
|
||||||
|
|
||||||
sessionProperties->BufferSize = 1024; // 1MB
|
|
||||||
sessionProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_INDEPENDENT_SESSION_MODE;
|
|
||||||
sessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
|
||||||
sessionProperties->LogFileNameOffset = 0; // real time session has no file name
|
|
||||||
sessionProperties->FlushTimer = 1; // 1 second
|
|
||||||
|
|
||||||
StringCbCopy(reinterpret_cast<LPWSTR>(reinterpret_cast<char *>(sessionProperties) + sessionProperties->LoggerNameOffset), sessionNameSizeInBytes, sessionName);
|
|
||||||
|
|
||||||
HRESULT hr;
|
|
||||||
auto retryCount = 1;
|
|
||||||
|
|
||||||
while (retryCount < 10)
|
|
||||||
{
|
|
||||||
hr = StartTrace(&sessionHandle, sessionName, sessionProperties);
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
if (hr == ERROR_ALREADY_EXISTS || hr == ERROR_INVALID_PARAMETER)
|
|
||||||
{
|
|
||||||
hr = ControlTrace(sessionHandle, sessionName, sessionProperties, EVENT_TRACE_CONTROL_STOP);
|
|
||||||
if (hr == ERROR_WMI_INSTANCE_NOT_FOUND || hr == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
Sleep(100 * retryCount); // sleep for 100-milliseconds to let it propogate.
|
|
||||||
retryCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputFile = CreateFile(outputFileName, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
if (outputFile == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
return HRESULT_FROM_WIN32(::GetLastError());
|
|
||||||
}
|
|
||||||
|
|
||||||
EVENT_TRACE_LOGFILE logFile;
|
|
||||||
ZeroMemory(&logFile, sizeof(EVENT_TRACE_LOGFILE));
|
|
||||||
logFile.LogFileName = nullptr;
|
|
||||||
logFile.LoggerName = sessionName;
|
|
||||||
logFile.LogFileMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
|
|
||||||
logFile.BufferCallback = BufferCallback;
|
|
||||||
logFile.EventRecordCallback = EventCallback;
|
|
||||||
|
|
||||||
TRACEHANDLE traceHandle = OpenTrace(&logFile);
|
|
||||||
|
|
||||||
if (traceHandle == reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE))
|
|
||||||
{
|
|
||||||
return HRESULT_FROM_WIN32(::GetLastError());
|
|
||||||
}
|
|
||||||
|
|
||||||
ENABLE_TRACE_PARAMETERS enableParameters;
|
|
||||||
ZeroMemory(&enableParameters, sizeof(ENABLE_TRACE_PARAMETERS));
|
|
||||||
enableParameters.FilterDescCount = 0;
|
|
||||||
enableParameters.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
|
|
||||||
|
|
||||||
EVENT_FILTER_DESCRIPTOR descriptor[1];
|
|
||||||
|
|
||||||
if (exeNamesFilter != nullptr)
|
|
||||||
{
|
|
||||||
descriptor[0].Ptr = ULONGLONG(exeNamesFilter);
|
|
||||||
descriptor[0].Size = static_cast<ULONG>((wcslen(exeNamesFilter) + 1) * sizeof(WCHAR));
|
|
||||||
descriptor[0].Type = EVENT_FILTER_TYPE_EXECUTABLE_NAME;
|
|
||||||
|
|
||||||
enableParameters.EnableFilterDesc = descriptor;
|
|
||||||
enableParameters.FilterDescCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = EnableTraceEx2(sessionHandle, &ClrProviderGuid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_VERBOSE, CLRJITANDLOADERKEYWORD, 0, 0, &enableParameters);
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = EnableTraceEx2(sessionHandle, &CoreClrProviderGuid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_VERBOSE, CLRJITANDLOADERKEYWORD, 0, 0, &enableParameters);
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = EnableTraceEx2(sessionHandle, &ClrRundownProviderGuid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_VERBOSE, 0x00020118, 0, 0, &enableParameters);
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessTrace(&traceHandle, 1, nullptr, nullptr);
|
|
||||||
CloseHandle(outputFile);
|
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wmain(_In_ int argc, _In_ PWSTR *argv)
|
|
||||||
{
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
wprintf(USAGE);
|
|
||||||
wprintf(EXAMPLE);
|
|
||||||
wprintf(EXAMPLE2);
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto flushThread = std::thread([] {
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
||||||
FlushFileBuffers(outputFile);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
SetConsoleCtrlHandler(ConsoleControlHandler, true);
|
|
||||||
SetCurrentDirectory(argv[1]);
|
|
||||||
|
|
||||||
wprintf(L"\n BPerfSymbolDataCollector is running ...\n");
|
|
||||||
wprintf(L" ETW Session Name: ");
|
|
||||||
wprintf(LOGSESSION_NAME);
|
|
||||||
wprintf(L"\n Symbol File: ");
|
|
||||||
wprintf(argv[1]);
|
|
||||||
wprintf(L"\\");
|
|
||||||
wprintf(SYMBOLS_FILE_NAME);
|
|
||||||
wprintf(L"\n\n ** Provide this file location when starting up BPerfCPUSampleCollector **\n");
|
|
||||||
|
|
||||||
StartSymbolicDataSession(LOGSESSION_NAME, SYMBOLS_FILE_NAME, argc == 3 ? argv[2] : nullptr);
|
|
||||||
|
|
||||||
flushThread.detach(); // let process tear down take care of this
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 15
|
|
||||||
VisualStudioVersion = 15.0.26020.0
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BPerfSymbolDataCollector", "BPerfSymbolDataCollector.vcxproj", "{41DC00DB-09FE-4938-AE08-DE478CF5BC88}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Debug|x86 = Debug|x86
|
|
||||||
Release|x64 = Release|x64
|
|
||||||
Release|x86 = Release|x86
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Debug|x86.ActiveCfg = Debug|Win32
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Debug|x86.Build.0 = Debug|Win32
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Release|x64.Build.0 = Release|x64
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Release|x86.ActiveCfg = Release|Win32
|
|
||||||
{41DC00DB-09FE-4938-AE08-DE478CF5BC88}.Release|x86.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
|
@ -1,122 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|x64">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>x64</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>{41DC00DB-09FE-4938-AE08-DE478CF5BC88}</ProjectGuid>
|
|
||||||
<Keyword>Win32Proj</Keyword>
|
|
||||||
<RootNamespace>BPerfSymbolDataCollector</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<LinkIncremental>true</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<LinkIncremental>false</LinkIncremental>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Console</SubSystem>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Console</SubSystem>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Console</SubSystem>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
|
||||||
<ClCompile>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<SubSystem>Console</SubSystem>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="BPerfSymbolDataCollector.cpp" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
|
||||||
</Project>
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="Source Files">
|
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files">
|
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="BPerfSymbolDataCollector.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
|
@ -0,0 +1,326 @@
|
||||||
|
syntax: glob
|
||||||
|
|
||||||
|
[Bb]inaries/
|
||||||
|
|
||||||
|
# Build tools related files
|
||||||
|
/[Tt]ools/
|
||||||
|
|
||||||
|
### VisualStudio ###
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
build/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
msbuild.log
|
||||||
|
|
||||||
|
# add back architecture directories ignored in 'Build results'
|
||||||
|
!tests/x86
|
||||||
|
!src/mscorlib/src/System/Runtime/Intrinsics/X86
|
||||||
|
!tests/src/JIT/HardwareIntrinsics/X86
|
||||||
|
|
||||||
|
# Visual Studio 2015
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Visual Studio 2015 Pre-CTP6
|
||||||
|
*.sln.ide
|
||||||
|
*.ide/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
#NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.html
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding addin-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
*.nuget.g.props
|
||||||
|
*.nuget.g.targets
|
||||||
|
*.nuget.cache
|
||||||
|
**/packages/*
|
||||||
|
*.nuget.dgspec.json
|
||||||
|
project.lock.json
|
||||||
|
project.assets.json
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
sql/
|
||||||
|
*.Cache
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
*.metaproj
|
||||||
|
*.metaproj.tmp
|
||||||
|
.atom-build.json
|
||||||
|
tags
|
||||||
|
TAGS
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# C/C++ extension for Visual Studio Code
|
||||||
|
browse.VC.db
|
||||||
|
|
||||||
|
# Local settings folder for Visual Studio Code
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### MonoDevelop ###
|
||||||
|
|
||||||
|
*.pidb
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# Common binary extensions on Windows
|
||||||
|
*.exe
|
||||||
|
*.exe.stackdump
|
||||||
|
*.dll
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
|
||||||
|
*~
|
||||||
|
\#*\#
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
### OSX ###
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear on external disk
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# We have some checked in prebuilt generated files
|
||||||
|
!src/pal/prebuilt/idl/*_i.c
|
||||||
|
|
||||||
|
# Valid 'debug' folder, that contains CLR debugging code
|
||||||
|
!src/debug
|
||||||
|
|
||||||
|
# Ignore folders created by the test build
|
||||||
|
TestWrappers_x64_[d|D]ebug
|
||||||
|
TestWrappers_x64_[c|C]hecked
|
||||||
|
TestWrappers_x64_[r|R]elease
|
||||||
|
TestWrappers_x86_[d|D]ebug
|
||||||
|
TestWrappers_x86_[c|C]hecked
|
||||||
|
TestWrappers_x86_[r|R]elease
|
||||||
|
TestWrappers_arm_[d|D]ebug
|
||||||
|
TestWrappers_arm_[c|C]hecked
|
||||||
|
TestWrappers_arm_[r|R]elease
|
||||||
|
TestWrappers_arm64_[d|D]ebug
|
||||||
|
TestWrappers_arm64_[c|C]hecked
|
||||||
|
TestWrappers_arm64_[r|R]elease
|
||||||
|
tests/src/common/test_runtime/project.json
|
||||||
|
|
||||||
|
Vagrantfile
|
||||||
|
.vagrant
|
||||||
|
|
||||||
|
# CMake files
|
||||||
|
CMakeFiles/
|
||||||
|
cmake_install.cmake
|
||||||
|
CMakeCache.txt
|
||||||
|
Makefile
|
||||||
|
|
||||||
|
# Cross compilation
|
||||||
|
cross/rootfs/*
|
||||||
|
cross/android-rootfs/*
|
||||||
|
# add x86 as it is ignored in 'Build results'
|
||||||
|
!cross/x86
|
||||||
|
|
||||||
|
#python import files
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# JIT32 files
|
||||||
|
src/jit32
|
||||||
|
|
||||||
|
# performance testing sandbox
|
||||||
|
sandbox
|
||||||
|
|
||||||
|
#IL linker for testing
|
||||||
|
linker
|
||||||
|
|
||||||
|
# Arcade files
|
||||||
|
/artifacts/toolset
|
||||||
|
/.packages
|
||||||
|
/.dotnet
|
|
@ -0,0 +1,183 @@
|
||||||
|
[ETWSession]
|
||||||
|
Name=BPerfProfiles
|
||||||
|
FileNamePrefix=BPerfProfiles.
|
||||||
|
LogRotationIntervalInSeconds=900
|
||||||
|
DataDirectory=%DATADIR%\BPerfLogs\Profiles
|
||||||
|
BufferSizeInKB=1024
|
||||||
|
CPUSamplingRateInMS=1
|
||||||
|
; EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_IMAGE_LOAD | EVENT_TRACE_FLAG_THREAD | EVENT_TRACE_FLAG_PROFILE;
|
||||||
|
KernelEnableFlags=16777223
|
||||||
|
EnableEmbeddingEventMetadata=1
|
||||||
|
EnableEmbeddingSymbolServerKeyInfo=1
|
||||||
|
EnableMetadataSideStream=1
|
||||||
|
OnDiskFormat=1
|
||||||
|
Providers=PerfInfo,Thread,Process,PageFault,ImageLoad,.NET Common Language Runtime,DotNet,System.Threading.Tasks.TplEventSource,Microsoft-Windows-ASPNET,Microsoft-Windows-TCPIP,Microsoft-Windows-Kernel-Process,Microsoft-Windows-Kernel-Processor-Power,HTTP Service Trace,Microsoft-Windows-DNS-Client,System.Diagnostics.Eventing.FrameworkEventSource,Microsoft-JScript,Microsoft-AspNetCore-Server-Kestrel,Microsoft-AspNetCore-Hosting,IIS: WWW Server,ASP.NET Events,BPerfStampingEventSource,BPerfInfoEventSource,PipelineInfoEventSource,MonitoredScopeEventSource,TcpHttpCorrelationEventSource,AutopilotLoggerEventSource,QuickInjectEventSource,MDMEventSource,SmartBuildEventSource,MiniStampEventSource,BufferManagerEventSource,FederationEventSource,ChunkDiagnosticsEventSource,ImageEmbeddingEventSource
|
||||||
|
ClassicEventIdsStack=PerfInfoStack,ImageLoadStack
|
||||||
|
|
||||||
|
[PerfInfoStack]
|
||||||
|
Guid={CE1DBFB4-137E-4DA6-87B0-3F59AA102CBC}
|
||||||
|
; SampledProfile
|
||||||
|
Type=46
|
||||||
|
|
||||||
|
[ImageLoadStack]
|
||||||
|
Guid={2CB15D1D-5FC1-11D2-ABE1-00A0C911F518}
|
||||||
|
Type=10
|
||||||
|
|
||||||
|
; Important Kernel Events
|
||||||
|
|
||||||
|
[PerfInfo] ; Timer (for CPU Profiling)
|
||||||
|
Guid={CE1DBFB4-137E-4DA6-87B0-3F59AA102CBC}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Thread] ; Thread Start/Stop
|
||||||
|
Guid={3D6FA8D1-FE05-11D0-9DDA-00C04FD7BA7C}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Process] ; Process Start/Stop
|
||||||
|
Guid={3D6FA8D0-FE05-11D0-9DDA-00C04FD7BA7C}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[PageFault] ; PageFaults
|
||||||
|
Guid={3D6FA8D3-FE05-11D0-9DDA-00C04FD7BA7C}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[ImageLoad] ; Image Load/Unloads
|
||||||
|
Guid={2CB15D1D-5FC1-11D2-ABE1-00A0C911F518}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
; Important OS Components
|
||||||
|
|
||||||
|
[.NET Common Language Runtime]
|
||||||
|
Guid={E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4}
|
||||||
|
MatchAnyKeyword=2147581969
|
||||||
|
; Allocation Tick, GC Triggered, LoadVerbose, Exception Start, Catch, Finally
|
||||||
|
StackEventIdsFilter=10,35,80,143,250,252
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[DotNet]
|
||||||
|
Guid={319DC449-ADA5-50F7-428E-957DB6791668}
|
||||||
|
MatchAnyKeyword=2147581969
|
||||||
|
; Allocation Tick, GC Triggered, LoadVerbose, Exception Start, Catch, Finally
|
||||||
|
StackEventIdsFilter=10,35,80,143,250,252
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[System.Threading.Tasks.TplEventSource]
|
||||||
|
Guid={2E5DBA47-A3D2-4D16-8EE0-6671FFDCD7B5}
|
||||||
|
Level=5
|
||||||
|
MatchAnyKeyword=66
|
||||||
|
; System.Threading.Tasks.TplEventSource/TaskScheduled/Send, System.Threading.Tasks.TplEventSource/TaskWait/Send, System.Threading.Tasks.TplEventSource/AwaitTaskContinuationScheduled/Send
|
||||||
|
StackEventIdsFilter=7,10,12
|
||||||
|
|
||||||
|
[Microsoft-Windows-ASPNET]
|
||||||
|
Guid={EE799F41-CFA5-550B-BF2C-344747C1C668}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Microsoft-Windows-TCPIP]
|
||||||
|
Guid={2F07E2EE-15DB-40F1-90EF-9D7BA282188A}
|
||||||
|
Level=5
|
||||||
|
; TcpCreateEndpoint
|
||||||
|
StackEventIdsFilter=1013
|
||||||
|
; TcpTcbStopTimer, TcpipDeliveryIndicated, TcpipReceiveSlowPath, TcpipSendSlowPath, TcpTcbStartTimer, TcpDataTransferReceive, TcpReleaseIndication, Unknown, Unknown
|
||||||
|
ExcludeEventIdsFilter=1065,1157,1205,1206,1064,1074,1090,1319,1320
|
||||||
|
|
||||||
|
[Microsoft-Windows-Kernel-Process]
|
||||||
|
Guid={22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Microsoft-Windows-Kernel-Processor-Power]
|
||||||
|
Guid={0F67E49F-FE51-4E9F-B490-6F2948CC6027}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[HTTP Service Trace]
|
||||||
|
Guid={DD5EF90A-6398-47A4-AD34-4DCECDEF795F}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Microsoft-Windows-DNS-Client]
|
||||||
|
Guid={1C95126E-7EEA-49A9-A3FE-A378B03DDB4D}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[System.Diagnostics.Eventing.FrameworkEventSource]
|
||||||
|
Guid={8E9F5090-2D75-4D03-8A81-E5AFBF85DAF1}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Microsoft-JScript]
|
||||||
|
Guid={57277741-3638-4A4B-BDBA-0AC6E45DA56C}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Microsoft-AspNetCore-Server-Kestrel]
|
||||||
|
Guid={BDEB4676-A36E-5442-DB99-4764E2326C7D}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[Microsoft-AspNetCore-Hosting]
|
||||||
|
Guid={9E620D2A-55D4-5ADE-DEB7-C26046D245A8}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[IIS: WWW Server]
|
||||||
|
Guid={3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[ASP.NET Events]
|
||||||
|
Guid={AFF081FE-0247-4275-9C4E-021F3DC1DA35}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
; BPerf Critical
|
||||||
|
|
||||||
|
[BPerfStampingEventSource] ; Used for stamping request entry points / thread migrations
|
||||||
|
Guid={D46E5565-D624-4C4D-89CC-7A82887D3627}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[BPerfInfoEventSource] ; Used for Stack Viewer
|
||||||
|
Guid={79430003-51BF-5F05-ED34-99CF32652C26}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[PipelineInfoEventSource] ; Used for detecting end of request early termination
|
||||||
|
Guid={F929009C-E2CF-4408-873E-20D60DAE6B55}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
; Bing SNR Specific
|
||||||
|
|
||||||
|
[MonitoredScopeEventSource]
|
||||||
|
Guid={2E185D98-344D-5EF7-0630-AFE322F01B98}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[TcpHttpCorrelationEventSource]
|
||||||
|
Guid={B51B554F-10F4-59D9-8C75-4273142D39C9}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[AutopilotLoggerEventSource]
|
||||||
|
Guid={20DC2E75-5A26-5799-AFE1-11D887F18932}
|
||||||
|
Level=5
|
||||||
|
|
||||||
|
[QuickInjectEventSource]
|
||||||
|
Guid={5BF45913-60EB-5DD5-78FA-0C46DE21A2FB}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[MDMEventSource]
|
||||||
|
Guid={EDC24920-E004-40F6-A8E1-0E6E48F39D84}
|
||||||
|
Level=4
|
||||||
|
; ULongMetricEvent, ExternallyAggregatedULongMetricEvent, ExternallyAggregatedDoubleMetricEvent, DoubleMetricEvent
|
||||||
|
StackEventIdsFilter=50,53,54,55
|
||||||
|
|
||||||
|
[SmartBuildEventSource]
|
||||||
|
Guid={1AB5F7B3-A330-50EE-3F97-9B55CD5CA518}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[MiniStampEventSource]
|
||||||
|
Guid={E5F0384D-6D0C-5390-086C-7789F2311078}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[BufferManagerEventSource]
|
||||||
|
Guid={B4397DF7-B17C-49BE-A199-262BE5A0F1A3}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[FederationEventSource]
|
||||||
|
Guid={FDEC008F-293F-4B6F-9B38-13274105856D}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[ChunkDiagnosticsEventSource]
|
||||||
|
Guid={7B4915F6-10B0-5AE4-3F3A-1065A44ADFE0}
|
||||||
|
Level=4
|
||||||
|
|
||||||
|
[ImageEmbeddingEventSource]
|
||||||
|
Guid={B9C54873-2E41-5D15-9637-50CAA653A1E9}
|
||||||
|
Level=4
|
|
@ -1,22 +1,55 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 15.0.26020.0
|
VisualStudioVersion = 16.0.28803.202
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BPerfCPUSamplesCollector", "BPerfCPUSamplesCollector.vcxproj", "{628BB6D0-1469-4652-9DF9-B7FEC89F0548}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dll", "dll\dll.vcxproj", "{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exe", "exe\exe.vcxproj", "{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib", "lib\lib.vcxproj", "{4CC1C899-4372-4FF0-92B2-C841C332F17C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.BPerf.DataCollector", "mgd\Microsoft.BPerf.DataCollector.csproj", "{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|x64 = Release|x64
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Debug|x64.ActiveCfg = Debug|x64
|
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Debug|x64.Build.0 = Debug|x64
|
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Release|x64.ActiveCfg = Release|x64
|
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Debug|x64.Build.0 = Debug|x64
|
||||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Release|x64.Build.0 = Release|x64
|
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
|
{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}.Release|x64.Build.0 = Release|x64
|
||||||
|
{4CC1C899-4372-4FF0-92B2-C841C332F17C}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
|
{4CC1C899-4372-4FF0-92B2-C841C332F17C}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{4CC1C899-4372-4FF0-92B2-C841C332F17C}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{4CC1C899-4372-4FF0-92B2-C841C332F17C}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
|
{4CC1C899-4372-4FF0-92B2-C841C332F17C}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{4CC1C899-4372-4FF0-92B2-C841C332F17C}.Release|x64.Build.0 = Release|x64
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B3D838-12CF-43EB-829A-644A5E4E8C1A}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {8E75CC9E-19C0-4956-B5AA-9430652BA3D6}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="Source Files">
|
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files">
|
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="JittedCodeResolutionSupportCode.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="KernelTraceControlSupportCode.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Program.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="TraceEventCallback.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="TraceEventCallback.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
|
@ -1,276 +0,0 @@
|
||||||
#include <relogger.h>
|
|
||||||
|
|
||||||
#define MAX_EVENT_SIZE 65536
|
|
||||||
#define ULONG_SIZE 4
|
|
||||||
#define LARGE_INTEGER_SIZE 8
|
|
||||||
#define ULONGLONGSIZE 8
|
|
||||||
#define USHORT_SIZE 2
|
|
||||||
#define GUID_SIZE 16
|
|
||||||
#define UCHAR_SIZE 1
|
|
||||||
|
|
||||||
BYTE userData[MAX_EVENT_SIZE];
|
|
||||||
|
|
||||||
bool Read(PBYTE buf, LARGE_INTEGER &retVal, DWORD &bytesAvailable)
|
|
||||||
{
|
|
||||||
if (bytesAvailable >= LARGE_INTEGER_SIZE)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
retVal.LowPart = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
|
|
||||||
retVal.HighPart = buf[7] << 24 | buf[6] << 16 | buf[5] << 8 | buf[4];
|
|
||||||
bytesAvailable -= LARGE_INTEGER_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Read(PBYTE buf, ULONGLONG &retVal, DWORD &bytesAvailable)
|
|
||||||
{
|
|
||||||
if (bytesAvailable >= ULONGLONGSIZE)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
retVal = static_cast<ULONGLONG>(buf[0]) | static_cast<ULONGLONG>(buf[1]) << 8 | static_cast<ULONGLONG>(buf[2]) << 16 | static_cast<ULONGLONG>(buf[3]) << 24 | static_cast<ULONGLONG>(buf[4]) << 32 | static_cast<ULONGLONG>(buf[5]) << 40 | static_cast<ULONGLONG>(buf[6]) << 48 | static_cast<ULONGLONG>(buf[7]) << 56;
|
|
||||||
bytesAvailable -= ULONGLONGSIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Read(PBYTE buf, ULONG &retVal, DWORD &bytesAvailable)
|
|
||||||
{
|
|
||||||
if (bytesAvailable >= ULONG_SIZE)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
retVal = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
|
|
||||||
bytesAvailable -= ULONG_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Read(PBYTE buf, USHORT &retVal, DWORD &bytesAvailable)
|
|
||||||
{
|
|
||||||
if (bytesAvailable >= USHORT_SIZE)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
retVal = buf[1] << 8 | buf[0];
|
|
||||||
bytesAvailable -= USHORT_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Read(PBYTE buf, UCHAR &retVal, DWORD &bytesAvailable)
|
|
||||||
{
|
|
||||||
if (bytesAvailable >= UCHAR_SIZE)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
retVal = buf[0];
|
|
||||||
bytesAvailable -= UCHAR_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Read(PBYTE buf, GUID &retVal, DWORD &bytesAvailable)
|
|
||||||
{
|
|
||||||
if (bytesAvailable >= GUID_SIZE)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
retVal.Data1 = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
|
|
||||||
retVal.Data2 = buf[5] << 8 | buf[4];
|
|
||||||
retVal.Data3 = buf[7] << 8 | buf[6];
|
|
||||||
retVal.Data4[0] = buf[8];
|
|
||||||
retVal.Data4[1] = buf[9];
|
|
||||||
retVal.Data4[2] = buf[10];
|
|
||||||
retVal.Data4[3] = buf[11];
|
|
||||||
retVal.Data4[4] = buf[12];
|
|
||||||
retVal.Data4[5] = buf[13];
|
|
||||||
retVal.Data4[6] = buf[14];
|
|
||||||
retVal.Data4[7] = buf[15];
|
|
||||||
|
|
||||||
bytesAvailable -= GUID_SIZE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
bool ReadAndRelogEvent(ITraceRelogger *relogger, PBYTE buf, DWORD bytesAvailable, DWORD &bytesProcessed)
|
|
||||||
{
|
|
||||||
bytesProcessed = 0;
|
|
||||||
DWORD bytesAvailableABeginningOfFunction = bytesAvailable;
|
|
||||||
buf += bytesAvailableABeginningOfFunction;
|
|
||||||
|
|
||||||
LARGE_INTEGER timestamp;
|
|
||||||
ULONG processId;
|
|
||||||
ULONG threadId;
|
|
||||||
GUID providerId;
|
|
||||||
|
|
||||||
USHORT eventId;
|
|
||||||
UCHAR version;
|
|
||||||
UCHAR level;
|
|
||||||
UCHAR channel;
|
|
||||||
UCHAR opcode;
|
|
||||||
USHORT task;
|
|
||||||
ULONGLONG keyword;
|
|
||||||
|
|
||||||
USHORT userDataLength;
|
|
||||||
|
|
||||||
if (!Read(buf, timestamp, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, processId, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, threadId, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, providerId, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, eventId, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, version, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, level, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, channel, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, opcode, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, task, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, keyword, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Read(buf, userDataLength, bytesAvailable))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytesAvailable >= userDataLength)
|
|
||||||
{
|
|
||||||
buf -= bytesAvailable;
|
|
||||||
CopyMemory(userData, buf, userDataLength);
|
|
||||||
bytesAvailable -= userDataLength;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ITraceEvent *evt;
|
|
||||||
relogger->CreateEventInstance(0, 0, &evt);
|
|
||||||
|
|
||||||
EVENT_DESCRIPTOR eventDescriptor;
|
|
||||||
eventDescriptor.Id = eventId;
|
|
||||||
eventDescriptor.Version = version;
|
|
||||||
eventDescriptor.Level = level;
|
|
||||||
eventDescriptor.Channel = channel;
|
|
||||||
eventDescriptor.Opcode = opcode;
|
|
||||||
eventDescriptor.Task = task;
|
|
||||||
eventDescriptor.Keyword = keyword;
|
|
||||||
|
|
||||||
evt->SetProviderId(&providerId);
|
|
||||||
evt->SetTimeStamp(×tamp);
|
|
||||||
evt->SetProcessId(processId);
|
|
||||||
evt->SetThreadId(threadId);
|
|
||||||
evt->SetEventDescriptor(&eventDescriptor);
|
|
||||||
evt->SetPayload(userData, userDataLength);
|
|
||||||
|
|
||||||
relogger->Inject(evt);
|
|
||||||
|
|
||||||
evt->Release();
|
|
||||||
|
|
||||||
bytesProcessed = bytesAvailableABeginningOfFunction - bytesAvailable;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogJittedCodeSymbolicData(HANDLE hFile, ITraceRelogger *relogger)
|
|
||||||
{
|
|
||||||
LARGE_INTEGER fileSize;
|
|
||||||
auto disk_buffer = static_cast<PBYTE>(malloc(MAX_EVENT_SIZE));
|
|
||||||
auto memory_buffer = static_cast<PBYTE>(malloc(MAX_EVENT_SIZE));
|
|
||||||
|
|
||||||
if (GetFileSizeEx(hFile, &fileSize) == FALSE)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LONGLONG remainingFileSize = fileSize.QuadPart;
|
|
||||||
|
|
||||||
while (remainingFileSize > 0)
|
|
||||||
{
|
|
||||||
DWORD bytesToRead = static_cast<DWORD>(min(remainingFileSize, MAX_EVENT_SIZE));
|
|
||||||
bool shouldExitAfterRetry = bytesToRead < MAX_EVENT_SIZE;
|
|
||||||
|
|
||||||
{
|
|
||||||
DWORD bytesRead = 0, offset = 0;
|
|
||||||
while (ReadFile(hFile, disk_buffer, bytesToRead - offset, &bytesRead, nullptr))
|
|
||||||
{
|
|
||||||
if (bytesRead == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CopyMemory(memory_buffer + offset, disk_buffer, bytesRead);
|
|
||||||
offset += bytesRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remainingFileSize -= bytesToRead;
|
|
||||||
|
|
||||||
{
|
|
||||||
DWORD bytesAvailableToProcess = bytesToRead, bytesProcessed = 0, offsetIntoBuffer = 0;
|
|
||||||
while (ReadAndRelogEvent(relogger, memory_buffer + offsetIntoBuffer, bytesAvailableToProcess, bytesProcessed))
|
|
||||||
{
|
|
||||||
bytesAvailableToProcess -= bytesProcessed;
|
|
||||||
offsetIntoBuffer += bytesProcessed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!shouldExitAfterRetry)
|
|
||||||
{
|
|
||||||
SetFilePointer(hFile, 0 - bytesAvailableToProcess, nullptr, FILE_CURRENT);
|
|
||||||
remainingFileSize += bytesAvailableToProcess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(disk_buffer);
|
|
||||||
free(memory_buffer);
|
|
||||||
}
|
|
|
@ -1,367 +0,0 @@
|
||||||
#include <windows.h>
|
|
||||||
#include <evntcons.h>
|
|
||||||
#include <dbghelp.h>
|
|
||||||
#include "TraceEventCallback.h"
|
|
||||||
|
|
||||||
#define SystemRoot L"\\SystemRoot"
|
|
||||||
#define GlobalRoot L"\\\\?\\GLOBALROOT"
|
|
||||||
|
|
||||||
std::wstring InitWindowsDir()
|
|
||||||
{
|
|
||||||
auto dest = static_cast<PWCHAR>(malloc((MAX_PATH + 1) * 2));
|
|
||||||
GetWindowsDirectory(dest, MAX_PATH);
|
|
||||||
std::wstring windowsDirectory(dest);
|
|
||||||
free(dest);
|
|
||||||
return windowsDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::wstring &&windowsDirectory = InitWindowsDir();
|
|
||||||
|
|
||||||
auto ReadInt32(PBYTE &data)
|
|
||||||
{
|
|
||||||
uint32_t retVal;
|
|
||||||
char *p = reinterpret_cast<char *>(&retVal);
|
|
||||||
|
|
||||||
p[0] = data[0];
|
|
||||||
p[1] = data[1];
|
|
||||||
p[2] = data[2];
|
|
||||||
p[3] = data[3];
|
|
||||||
|
|
||||||
data += 4;
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ReadInt64(PBYTE &data)
|
|
||||||
{
|
|
||||||
uint64_t retVal;
|
|
||||||
char *p = reinterpret_cast<char *>(&retVal);
|
|
||||||
|
|
||||||
p[0] = data[0];
|
|
||||||
p[1] = data[1];
|
|
||||||
p[2] = data[2];
|
|
||||||
p[3] = data[3];
|
|
||||||
p[4] = data[4];
|
|
||||||
p[5] = data[5];
|
|
||||||
p[6] = data[6];
|
|
||||||
p[7] = data[7];
|
|
||||||
|
|
||||||
data += 8;
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T ReadPointer(PBYTE &data)
|
|
||||||
{
|
|
||||||
UNREFERENCED_PARAMETER(data);
|
|
||||||
throw std::logic_error("T must be uint64_t or uint32_t");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
uint64_t ReadPointer<uint64_t>(PBYTE &data)
|
|
||||||
{
|
|
||||||
return ReadInt64(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
uint32_t ReadPointer<uint32_t>(PBYTE &data)
|
|
||||||
{
|
|
||||||
return ReadInt32(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class PtrSizeType>
|
|
||||||
class ImageLoad
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PtrSizeType ImageBase;
|
|
||||||
PtrSizeType ImageSize;
|
|
||||||
uint32_t ProcessId;
|
|
||||||
uint32_t ImageChecksum;
|
|
||||||
uint32_t TimeDateStamp;
|
|
||||||
uint32_t Reserved0;
|
|
||||||
PtrSizeType DefaultBase;
|
|
||||||
uint32_t Reserved1;
|
|
||||||
uint32_t Reserved2;
|
|
||||||
uint32_t Reserved3;
|
|
||||||
uint32_t Reserved4;
|
|
||||||
std::wstring FileName;
|
|
||||||
|
|
||||||
ImageLoad(PBYTE data)
|
|
||||||
{
|
|
||||||
this->ImageBase = ReadPointer<PtrSizeType>(data);
|
|
||||||
this->ImageSize = ReadPointer<PtrSizeType>(data);
|
|
||||||
this->ProcessId = ReadInt32(data);
|
|
||||||
this->ImageChecksum = ReadInt32(data);
|
|
||||||
this->TimeDateStamp = ReadInt32(data);
|
|
||||||
this->Reserved0 = ReadInt32(data);
|
|
||||||
this->DefaultBase = ReadPointer<PtrSizeType>(data);
|
|
||||||
this->Reserved1 = ReadInt32(data);
|
|
||||||
this->Reserved2 = ReadInt32(data);
|
|
||||||
this->Reserved3 = ReadInt32(data);
|
|
||||||
this->Reserved4 = ReadInt32(data);
|
|
||||||
this->FileName = wstring(reinterpret_cast<const wchar_t *>(data));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _CV_INFO_PDB70
|
|
||||||
{
|
|
||||||
DWORD CvSignature;
|
|
||||||
GUID Signature;
|
|
||||||
DWORD Age;
|
|
||||||
char PdbFileName[1];
|
|
||||||
} CV_INFO_PDB70, *PCV_INFO_PDB70;
|
|
||||||
|
|
||||||
constexpr GUID KernelTraceControlGuid = {0xB3E675D7, 0x2554, 0x4F18, {0x83, 0x0B, 0x27, 0x62, 0x73, 0x25, 0x60, 0xDE}};
|
|
||||||
|
|
||||||
template <typename T, size_t N>
|
|
||||||
constexpr size_t count_of(T (&)[N])
|
|
||||||
{
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, size_t N>
|
|
||||||
constexpr size_t size_of(T (&)[N])
|
|
||||||
{
|
|
||||||
return N * sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, size_t N>
|
|
||||||
constexpr size_t length_of(T (&)[N])
|
|
||||||
{
|
|
||||||
return N - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InjectDbgIdEvent(ITraceRelogger *relogger, PEVENT_RECORD eventRecord, PCV_INFO_PDB70 data, int eventPointerSize, int flags, DWORD processId)
|
|
||||||
{
|
|
||||||
ITraceEvent *duplicateEvent;
|
|
||||||
relogger->CreateEventInstance(0, flags, &duplicateEvent);
|
|
||||||
|
|
||||||
EVENT_DESCRIPTOR eventDescriptor;
|
|
||||||
eventDescriptor.Id = -1;
|
|
||||||
eventDescriptor.Version = 2;
|
|
||||||
eventDescriptor.Channel = 0;
|
|
||||||
eventDescriptor.Level = 1;
|
|
||||||
eventDescriptor.Opcode = 36;
|
|
||||||
eventDescriptor.Task = 0;
|
|
||||||
eventDescriptor.Keyword = 0;
|
|
||||||
|
|
||||||
duplicateEvent->SetEventDescriptor(&eventDescriptor);
|
|
||||||
|
|
||||||
duplicateEvent->SetTimeStamp(&eventRecord->EventHeader.TimeStamp);
|
|
||||||
duplicateEvent->SetProcessorIndex(GetEventProcessorIndex(eventRecord));
|
|
||||||
duplicateEvent->SetProviderId(&KernelTraceControlGuid);
|
|
||||||
duplicateEvent->SetProcessId(processId);
|
|
||||||
duplicateEvent->SetThreadId(eventRecord->EventHeader.ThreadId);
|
|
||||||
|
|
||||||
auto pdbFileNameBufferLength = static_cast<int>(strlen(data->PdbFileName)) + 1;
|
|
||||||
auto payloadSize = eventPointerSize + pdbFileNameBufferLength + 2 * sizeof(int) + sizeof(GUID);
|
|
||||||
auto ptr = static_cast<PBYTE>(malloc(payloadSize));
|
|
||||||
auto payload = ptr;
|
|
||||||
|
|
||||||
CopyMemory(ptr, eventRecord->UserData, eventPointerSize);
|
|
||||||
ptr += eventPointerSize;
|
|
||||||
CopyMemory(ptr, &eventRecord->EventHeader.ProcessId, sizeof(int));
|
|
||||||
ptr += sizeof(int);
|
|
||||||
CopyMemory(ptr, &data->Signature, sizeof(GUID));
|
|
||||||
ptr += sizeof(GUID);
|
|
||||||
CopyMemory(ptr, &data->Age, sizeof(int));
|
|
||||||
ptr += sizeof(int);
|
|
||||||
CopyMemory(ptr, data->PdbFileName, pdbFileNameBufferLength);
|
|
||||||
|
|
||||||
duplicateEvent->SetPayload(payload, static_cast<ULONG>(payloadSize));
|
|
||||||
relogger->Inject(duplicateEvent);
|
|
||||||
duplicateEvent->Release();
|
|
||||||
free(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InjectImgIdEvent(ITraceRelogger *relogger, PEVENT_RECORD eventRecord, PCWCHAR originalFileName, DWORD imageSize, DWORD timestamp, int eventPointerSize, int flags, DWORD processId)
|
|
||||||
{
|
|
||||||
ITraceEvent *duplicateEvent;
|
|
||||||
relogger->CreateEventInstance(0, flags, &duplicateEvent);
|
|
||||||
|
|
||||||
EVENT_DESCRIPTOR eventDescriptor;
|
|
||||||
eventDescriptor.Id = -1;
|
|
||||||
eventDescriptor.Version = 2;
|
|
||||||
eventDescriptor.Channel = 0;
|
|
||||||
eventDescriptor.Level = 1;
|
|
||||||
eventDescriptor.Opcode = 0;
|
|
||||||
eventDescriptor.Task = 0;
|
|
||||||
eventDescriptor.Keyword = 0;
|
|
||||||
|
|
||||||
duplicateEvent->SetEventDescriptor(&eventDescriptor);
|
|
||||||
|
|
||||||
duplicateEvent->SetTimeStamp(&eventRecord->EventHeader.TimeStamp);
|
|
||||||
duplicateEvent->SetProcessorIndex(GetEventProcessorIndex(eventRecord));
|
|
||||||
duplicateEvent->SetProviderId(&KernelTraceControlGuid);
|
|
||||||
duplicateEvent->SetProcessId(processId);
|
|
||||||
duplicateEvent->SetThreadId(eventRecord->EventHeader.ThreadId);
|
|
||||||
|
|
||||||
auto originalFileNameBufferLength = (wcslen(originalFileName) + 1) * 2;
|
|
||||||
auto payloadSize = eventPointerSize + originalFileNameBufferLength + 4 * sizeof(int);
|
|
||||||
auto ptr = static_cast<PBYTE>(malloc(payloadSize));
|
|
||||||
auto payload = ptr;
|
|
||||||
|
|
||||||
DWORD *zeroAddr = nullptr;
|
|
||||||
CopyMemory(ptr, eventRecord->UserData, eventPointerSize);
|
|
||||||
ptr += eventPointerSize;
|
|
||||||
CopyMemory(ptr, &imageSize, sizeof(int));
|
|
||||||
ptr += sizeof(int);
|
|
||||||
CopyMemory(ptr, &zeroAddr, sizeof(int));
|
|
||||||
ptr += sizeof(int);
|
|
||||||
CopyMemory(ptr, &eventRecord->EventHeader.ProcessId, sizeof(int));
|
|
||||||
ptr += sizeof(int);
|
|
||||||
CopyMemory(ptr, ×tamp, sizeof(int));
|
|
||||||
ptr += sizeof(int);
|
|
||||||
CopyMemory(ptr, originalFileName, originalFileNameBufferLength);
|
|
||||||
|
|
||||||
duplicateEvent->SetPayload(payload, static_cast<ULONG>(payloadSize));
|
|
||||||
relogger->Inject(duplicateEvent);
|
|
||||||
duplicateEvent->Release();
|
|
||||||
free(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT InjectKernelTraceControlEventsInner(PCWCHAR peFileName, PCWCHAR originalFileName, ITraceRelogger *relogger, PEVENT_RECORD eventRecord, DWORD processId)
|
|
||||||
{
|
|
||||||
auto file = CreateFile(peFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
if (file == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
return ERROR_INVALID_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mapFile = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
|
||||||
if (mapFile == nullptr)
|
|
||||||
{
|
|
||||||
CloseHandle(file);
|
|
||||||
return ERROR_INVALID_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto imageBase = reinterpret_cast<PBYTE>(MapViewOfFile(mapFile, FILE_MAP_READ, 0, 0, 0));
|
|
||||||
auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(imageBase);
|
|
||||||
auto ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(imageBase + dosHeader->e_lfanew);
|
|
||||||
auto header = &ntHeader->OptionalHeader;
|
|
||||||
|
|
||||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE || ntHeader->Signature != IMAGE_NT_SIGNATURE)
|
|
||||||
{
|
|
||||||
CloseHandle(mapFile);
|
|
||||||
CloseHandle(file);
|
|
||||||
return ERROR_BAD_ARGUMENTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto flags = EVENT_HEADER_FLAG_CLASSIC_HEADER;
|
|
||||||
int eventPointerSize;
|
|
||||||
if ((eventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_64_BIT_HEADER) != 0)
|
|
||||||
{
|
|
||||||
eventPointerSize = 8;
|
|
||||||
flags |= EVENT_HEADER_FLAG_64_BIT_HEADER;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
eventPointerSize = 4;
|
|
||||||
flags |= EVENT_HEADER_FLAG_32_BIT_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectImgIdEvent(relogger, eventRecord, originalFileName, header->SizeOfImage, ntHeader->FileHeader.TimeDateStamp, eventPointerSize, flags, processId);
|
|
||||||
|
|
||||||
ULONG numberOfDebugDirectories;
|
|
||||||
auto debugDirectories = static_cast<PIMAGE_DEBUG_DIRECTORY>(ImageDirectoryEntryToData(imageBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &numberOfDebugDirectories));
|
|
||||||
numberOfDebugDirectories /= sizeof(*debugDirectories);
|
|
||||||
|
|
||||||
PIMAGE_DEBUG_DIRECTORY current;
|
|
||||||
for (current = debugDirectories; numberOfDebugDirectories != 0; --numberOfDebugDirectories, ++current)
|
|
||||||
{
|
|
||||||
if (current->Type == IMAGE_DEBUG_TYPE_CODEVIEW)
|
|
||||||
{
|
|
||||||
auto data = reinterpret_cast<PCV_INFO_PDB70>(imageBase + current->PointerToRawData);
|
|
||||||
|
|
||||||
if (data->CvSignature == 0x53445352) // RSDS in ASCII
|
|
||||||
{
|
|
||||||
InjectDbgIdEvent(relogger, eventRecord, data, eventPointerSize, flags, processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(mapFile);
|
|
||||||
CloseHandle(file);
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
wstring PEFileNameAndProcessIdFromEvent(PEVENT_RECORD eventRecord, DWORD *processId)
|
|
||||||
{
|
|
||||||
ImageLoad<T> imgLoadEvent(static_cast<PBYTE>(eventRecord->UserData));
|
|
||||||
*processId = imgLoadEvent.ProcessId;
|
|
||||||
wstring peFileName(imgLoadEvent.FileName.compare(0, length_of(SystemRoot), SystemRoot) == 0 ? windowsDirectory + imgLoadEvent.FileName.substr(length_of(SystemRoot)) : GlobalRoot + imgLoadEvent.FileName);
|
|
||||||
return peFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(noinline) HRESULT InjectKernelTraceControlEvents(PEVENT_RECORD eventRecord, ITraceRelogger *relogger)
|
|
||||||
{
|
|
||||||
if (eventRecord->EventHeader.EventDescriptor.Opcode != DCStopOpCode)
|
|
||||||
{
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD processId = 0;
|
|
||||||
wstring peFileName((eventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_64_BIT_HEADER) != 0 ? PEFileNameAndProcessIdFromEvent<uint64_t>(eventRecord, &processId) : PEFileNameAndProcessIdFromEvent<uint32_t>(eventRecord, &processId));
|
|
||||||
auto peFileNamePtr = peFileName.c_str();
|
|
||||||
|
|
||||||
DWORD handle;
|
|
||||||
DWORD versionSize = GetFileVersionInfoSize(peFileNamePtr, &handle);
|
|
||||||
if (versionSize > 0)
|
|
||||||
{
|
|
||||||
auto buffer = malloc(versionSize);
|
|
||||||
|
|
||||||
if (GetFileVersionInfo(peFileNamePtr, handle, versionSize, buffer) != 0)
|
|
||||||
{
|
|
||||||
struct LANGANDCODEPAGE
|
|
||||||
{
|
|
||||||
WORD wLanguage;
|
|
||||||
WORD wCodePage;
|
|
||||||
} * lpTranslate;
|
|
||||||
|
|
||||||
UINT cbTranslate;
|
|
||||||
|
|
||||||
VerQueryValue(buffer, TEXT("\\VarFileInfo\\Translation"), reinterpret_cast<LPVOID *>(&lpTranslate), &cbTranslate);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < cbTranslate / sizeof(LANGANDCODEPAGE); ++i)
|
|
||||||
{
|
|
||||||
WCHAR dest[MAX_PATH + 1];
|
|
||||||
PWCHAR lpBuffer;
|
|
||||||
UINT dwBytes;
|
|
||||||
|
|
||||||
StringCchPrintf(dest, MAX_PATH, TEXT("\\StringFileInfo\\%04x%04x\\OriginalFilename"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
|
|
||||||
VerQueryValue(buffer, dest, reinterpret_cast<LPVOID *>(&lpBuffer), &dwBytes);
|
|
||||||
|
|
||||||
if (dwBytes == 0)
|
|
||||||
{
|
|
||||||
StringCchPrintf(dest, MAX_PATH, TEXT("\\StringFileInfo\\%04x%04x\\InternalName"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
|
|
||||||
VerQueryValue(buffer, dest, reinterpret_cast<LPVOID *>(&lpBuffer), &dwBytes);
|
|
||||||
|
|
||||||
if (dwBytes == 0)
|
|
||||||
{
|
|
||||||
lpBuffer = (PWCHAR)peFileNamePtr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const LPWSTR lastDot = wcsrchr(lpBuffer, L'.');
|
|
||||||
if (lastDot && !_wcsicmp(lastDot, L".MUI"))
|
|
||||||
{
|
|
||||||
*lastDot = UNICODE_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectKernelTraceControlEventsInner(peFileNamePtr, lpBuffer, relogger, eventRecord, processId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InjectKernelTraceControlEventsInner(peFileNamePtr, peFileNamePtr, relogger, eventRecord, processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
|
@ -1,436 +0,0 @@
|
||||||
#include <string>
|
|
||||||
#include <chrono>
|
|
||||||
#include <ctime>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include <relogger.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <strsafe.h>
|
|
||||||
#include "TraceEventCallback.h"
|
|
||||||
#include <evntprov.h>
|
|
||||||
|
|
||||||
#define LOGFILE_PATH L""
|
|
||||||
#define LOGSESSION_NAME L"BPerfProfiles"
|
|
||||||
#define LOGFILE_NAME L"Relogger.etl"
|
|
||||||
|
|
||||||
typedef struct _STACK_TRACING_EVENT_ID
|
|
||||||
{
|
|
||||||
GUID EventGuid;
|
|
||||||
UCHAR Type;
|
|
||||||
UCHAR Reserved[7];
|
|
||||||
} STACK_TRACING_EVENT_ID, *PSTACK_TRACING_EVENT_ID;
|
|
||||||
|
|
||||||
enum EVENT_TRACE_INFORMATION_CLASS
|
|
||||||
{
|
|
||||||
EventTraceTimeProfileInformation = 3,
|
|
||||||
EventTraceStackCachingInformation = 16
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SYSTEM_INFORMATION_CLASS
|
|
||||||
{
|
|
||||||
SystemPerformanceTraceInformation = 31
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _EVENT_TRACE_TIME_PROFILE_INFORMATION
|
|
||||||
{
|
|
||||||
EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;
|
|
||||||
ULONG ProfileInterval;
|
|
||||||
} EVENT_TRACE_TIME_PROFILE_INFORMATION;
|
|
||||||
|
|
||||||
bool ctrlCTriggered = false;
|
|
||||||
typedef int(__stdcall *NtSetSystemInformation)(int SystemInformationClass, void *SystemInformation, int SystemInformationLength);
|
|
||||||
auto ntdll = LoadLibrary(L"ntdll.dll");
|
|
||||||
auto addr = NtSetSystemInformation(GetProcAddress(ntdll, "NtSetSystemInformation"));
|
|
||||||
|
|
||||||
ULONG EnableTraceEx2Shim(_In_ TRACEHANDLE traceHandle, _In_ LPCGUID guid, _In_ BYTE level, _In_ ULONG matchAnyKeyword, _In_ ULONG matchAllKeyword, _In_ ULONG timeout, _In_opt_ LPCWSTR exeNamesFilter, _In_opt_ const USHORT *stackEventIdsFilter, _In_ USHORT stackEventIdsCount)
|
|
||||||
{
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
EVENT_FILTER_DESCRIPTOR descriptor[2];
|
|
||||||
ENABLE_TRACE_PARAMETERS enableParameters;
|
|
||||||
ZeroMemory(&enableParameters, sizeof(ENABLE_TRACE_PARAMETERS));
|
|
||||||
enableParameters.FilterDescCount = 0;
|
|
||||||
enableParameters.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
|
|
||||||
enableParameters.EnableFilterDesc = descriptor;
|
|
||||||
|
|
||||||
auto eventIdsBufferSize = ((stackEventIdsCount - 1) * 2) + sizeof(EVENT_FILTER_EVENT_ID);
|
|
||||||
PEVENT_FILTER_EVENT_ID eventIdsBuffer;
|
|
||||||
|
|
||||||
eventIdsBuffer = (PEVENT_FILTER_EVENT_ID)malloc(eventIdsBufferSize);
|
|
||||||
ZeroMemory(eventIdsBuffer, eventIdsBufferSize);
|
|
||||||
|
|
||||||
eventIdsBuffer->FilterIn = TRUE;
|
|
||||||
eventIdsBuffer->Reserved = 0;
|
|
||||||
eventIdsBuffer->Count = stackEventIdsCount;
|
|
||||||
|
|
||||||
auto eventIdsPtr = &eventIdsBuffer->Events[0];
|
|
||||||
for (int i = 0; i < stackEventIdsCount; ++i)
|
|
||||||
{
|
|
||||||
*eventIdsPtr++ = stackEventIdsFilter[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exeNamesFilter != nullptr)
|
|
||||||
{
|
|
||||||
descriptor[index].Ptr = (ULONGLONG)exeNamesFilter;
|
|
||||||
descriptor[index].Size = static_cast<ULONG>((wcslen(exeNamesFilter) + 1) * sizeof(WCHAR));
|
|
||||||
descriptor[index].Type = EVENT_FILTER_TYPE_EXECUTABLE_NAME;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stackEventIdsCount > 0)
|
|
||||||
{
|
|
||||||
descriptor[index].Ptr = (ULONGLONG)eventIdsBuffer;
|
|
||||||
descriptor[index].Size = static_cast<ULONG>(eventIdsBufferSize);
|
|
||||||
descriptor[index].Type = EVENT_FILTER_TYPE_STACKWALK;
|
|
||||||
index++;
|
|
||||||
|
|
||||||
enableParameters.EnableProperty = EVENT_ENABLE_PROPERTY_STACK_TRACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
enableParameters.FilterDescCount = index; // set the right size
|
|
||||||
|
|
||||||
auto retVal = EnableTraceEx2(traceHandle, guid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, level, matchAnyKeyword, matchAllKeyword, timeout, &enableParameters);
|
|
||||||
|
|
||||||
free(eventIdsBuffer);
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FillEventProperties(PEVENT_TRACE_PROPERTIES sessionProperties, ULONG bufferSize)
|
|
||||||
{
|
|
||||||
ZeroMemory(sessionProperties, bufferSize);
|
|
||||||
|
|
||||||
sessionProperties->Wnode.BufferSize = bufferSize;
|
|
||||||
sessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
|
||||||
sessionProperties->Wnode.ClientContext = 1;
|
|
||||||
|
|
||||||
sessionProperties->MinimumBuffers = max(64, std::thread::hardware_concurrency() * 2);
|
|
||||||
sessionProperties->MaximumBuffers = sessionProperties->MinimumBuffers * 2;
|
|
||||||
|
|
||||||
sessionProperties->BufferSize = 1024;
|
|
||||||
sessionProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_SYSTEM_LOGGER_MODE | EVENT_TRACE_INDEPENDENT_SESSION_MODE;
|
|
||||||
sessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
|
|
||||||
sessionProperties->LogFileNameOffset = 0;
|
|
||||||
sessionProperties->FlushTimer = 1;
|
|
||||||
|
|
||||||
StringCbCopy(reinterpret_cast<LPWSTR>(reinterpret_cast<char *>(sessionProperties) + sessionProperties->LoggerNameOffset), (wcslen(LOGSESSION_NAME) + 1) * 2, LOGSESSION_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT StartSession(PTRACEHANDLE sessionHandle, PEVENT_TRACE_PROPERTIES sessionProperties)
|
|
||||||
{
|
|
||||||
HRESULT hr = ERROR_SUCCESS;
|
|
||||||
int retryCount = 1;
|
|
||||||
while (retryCount < 10)
|
|
||||||
{
|
|
||||||
hr = StartTrace(static_cast<PTRACEHANDLE>(sessionHandle), LOGSESSION_NAME, sessionProperties);
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
if (hr == ERROR_ALREADY_EXISTS)
|
|
||||||
{
|
|
||||||
hr = ControlTrace(*sessionHandle, LOGSESSION_NAME, sessionProperties, EVENT_TRACE_CONTROL_STOP);
|
|
||||||
if (hr == ERROR_WMI_INSTANCE_NOT_FOUND || hr == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
Sleep(100 * retryCount); // sleep for 100-milliseconds to let it propogate.
|
|
||||||
retryCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AcquireProfilePrivileges()
|
|
||||||
{
|
|
||||||
bool privileged = false;
|
|
||||||
|
|
||||||
HANDLE tokenHandle;
|
|
||||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &tokenHandle))
|
|
||||||
{
|
|
||||||
TOKEN_PRIVILEGES privileges;
|
|
||||||
|
|
||||||
privileges.PrivilegeCount = 1;
|
|
||||||
privileges.Privileges->Luid.LowPart = 11;
|
|
||||||
privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
|
|
||||||
|
|
||||||
if (AdjustTokenPrivileges(tokenHandle, false, &privileges, 0, nullptr, nullptr))
|
|
||||||
{
|
|
||||||
privileged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(tokenHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return privileged;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT RelogTraceFile(TRACEHANDLE sessionHandle, PWSTR outputFileName, int rollOverTimeMSec, PWSTR jittedCodeSymbolicDataFile)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
ITraceRelogger *relogger = nullptr;
|
|
||||||
TraceEventCallback *callback = nullptr;
|
|
||||||
|
|
||||||
hr = CoCreateInstance(CLSID_TraceRelogger, nullptr, CLSCTX_INPROC_SERVER, __uuidof(ITraceRelogger), reinterpret_cast<LPVOID *>(&relogger));
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to instantiate ITraceRelogger object: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
relogger->SetOutputFilename(outputFileName);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to set output log file: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACEHANDLE traceHandle;
|
|
||||||
|
|
||||||
hr = relogger->AddRealtimeTraceStream(LOGSESSION_NAME, nullptr, &traceHandle);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to set log file input stream: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback = new TraceEventCallback(sessionHandle, relogger, rollOverTimeMSec, jittedCodeSymbolicDataFile);
|
|
||||||
|
|
||||||
if (callback == nullptr)
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to allocate callback: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = relogger->RegisterCallback(callback);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to register callback: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
DoStartRundown(sessionHandle);
|
|
||||||
|
|
||||||
hr = relogger->ProcessTrace();
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to process trace: 0x%08x.\n", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
|
|
||||||
if (relogger != nullptr)
|
|
||||||
{
|
|
||||||
relogger->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback != nullptr)
|
|
||||||
{
|
|
||||||
callback->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring FormatProfileSting()
|
|
||||||
{
|
|
||||||
auto in_time_t = chrono::system_clock::to_time_t(chrono::system_clock::now());
|
|
||||||
tm nt;
|
|
||||||
localtime_s(&nt, &in_time_t);
|
|
||||||
|
|
||||||
wstringstream ss;
|
|
||||||
ss << put_time(&nt, L"%Y-%m-%d-%H-%M-%S");
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL WINAPI ConsoleControlHandler(DWORD ctrlType)
|
|
||||||
{
|
|
||||||
switch (ctrlType)
|
|
||||||
{
|
|
||||||
case CTRL_C_EVENT:
|
|
||||||
case CTRL_BREAK_EVENT:
|
|
||||||
wprintf(L"Ctrl+C handled, stopping session.\n");
|
|
||||||
ctrlCTriggered = true;
|
|
||||||
EVENT_TRACE_PROPERTIES properties;
|
|
||||||
ZeroMemory(&properties, sizeof(EVENT_TRACE_PROPERTIES));
|
|
||||||
properties.Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES);
|
|
||||||
ControlTrace(0, LOGSESSION_NAME, &properties, EVENT_TRACE_CONTROL_STOP);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wmain(const int argc, PWSTR *argv)
|
|
||||||
{
|
|
||||||
if (argc < 4)
|
|
||||||
{
|
|
||||||
printf("Usage: BPerfCPUSamplesCollector CpuTimerInMilliSeconds FileRolloverPeriodSec ProfileLogsDirectory [JittedCodeSymbolicDataFile] [ProcessNameFilters]\n");
|
|
||||||
printf("Example 1: BPerfCPUSamplesCollector 10 900 D:\\Data\\BPerfLogs D:\\Data\\BPerfSymbols\\Symbols.bin\n");
|
|
||||||
printf("Example 2: BPerfCPUSamplesCollector 10 900 D:\\Data\\BPerfLogs D:\\Data\\BPerfSymbols\\Symbols.bin w3wp.exe\n");
|
|
||||||
printf("Example 3: BPerfCPUSamplesCollector 10 900 D:\\Data\\BPerfLogs D:\\Data\\BPerfSymbols\\Symbols.bin w3wp.exe;sql.exe\n");
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetConsoleCtrlHandler(ConsoleControlHandler, true);
|
|
||||||
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to initialize COM: 0x%08x\n", hr);
|
|
||||||
return HRESULT_CODE(hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set working dir */
|
|
||||||
SetCurrentDirectory(argv[3]);
|
|
||||||
|
|
||||||
auto cpuSampleMSec = _wtoi(argv[1]);
|
|
||||||
auto rolloverTimeMSec = _wtoi(argv[2]) * 1000;
|
|
||||||
|
|
||||||
if (!AcquireProfilePrivileges())
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to acquire profiling privileges. Are you running as admin?\n");
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
|
|
||||||
auto sessionProperties = static_cast<PEVENT_TRACE_PROPERTIES>(malloc(bufferSize));
|
|
||||||
|
|
||||||
if (sessionProperties == nullptr)
|
|
||||||
{
|
|
||||||
wprintf(L"Unable to allocate %d bytes for properties structure.\n", bufferSize);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
FillEventProperties(sessionProperties, bufferSize);
|
|
||||||
|
|
||||||
TRACEHANDLE sessionHandle;
|
|
||||||
|
|
||||||
hr = StartSession(&sessionHandle, sessionProperties);
|
|
||||||
if (FAILED(HRESULT(hr)))
|
|
||||||
{
|
|
||||||
wprintf(L"StartTrace() failed with %lu\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG data = EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_IMAGE_LOAD | EVENT_TRACE_FLAG_THREAD | EVENT_TRACE_FLAG_PROFILE;
|
|
||||||
hr = TraceSetInformation(sessionHandle, TraceSystemTraceEnableFlagsInfo, &data, sizeof(ULONG));
|
|
||||||
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to set trace information: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto exeNamesFilter = argc == 6 ? argv[5] : nullptr;
|
|
||||||
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &AspNetEventSource, TRACE_LEVEL_INFORMATION, 0, 0, 0, exeNamesFilter, nullptr, 0);
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &TplEventSource, TRACE_LEVEL_INFORMATION, 0x42, 0, 0, exeNamesFilter, nullptr, 0);
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &BPerfStampingGuid, TRACE_LEVEL_INFORMATION, 0, 0, 0, exeNamesFilter, nullptr, 0);
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &MonitoredScopeEventSource, TRACE_LEVEL_INFORMATION, 0, 0, 0, exeNamesFilter, nullptr, 0);
|
|
||||||
|
|
||||||
USHORT stacksForTcpIp[1] = {1013}; // Tcp Create Endpoint
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &TcpIpProviderGuid, TRACE_LEVEL_INFORMATION, 0x1, 0, 0, exeNamesFilter, stacksForTcpIp, 1);
|
|
||||||
|
|
||||||
USHORT stacksForClr[3] = {80, 250, 252}; // Exception Start, Catch, Finally
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &ClrGuid, TRACE_LEVEL_INFORMATION, 0x18011, 0, 0, exeNamesFilter, stacksForClr, 3);
|
|
||||||
EnableTraceEx2Shim(sessionHandle, &CoreClrGuid, TRACE_LEVEL_INFORMATION, 0x18011, 0, 0, exeNamesFilter, stacksForClr, 3);
|
|
||||||
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to enable bperf stamping guid: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
STACK_TRACING_EVENT_ID stacks;
|
|
||||||
stacks.EventGuid = {0xce1dbfb4, 0x137e, 0x4da6, {0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc}};
|
|
||||||
stacks.Type = 0x2e;
|
|
||||||
hr = TraceSetInformation(sessionHandle, TraceStackTracingInfo, &stacks, sizeof(STACK_TRACING_EVENT_ID));
|
|
||||||
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to set stack trace information: 0x%08x.\n", hr);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVENT_TRACE_TIME_PROFILE_INFORMATION timeInfo;
|
|
||||||
timeInfo.EventTraceInformationClass = EventTraceTimeProfileInformation;
|
|
||||||
timeInfo.ProfileInterval = static_cast<int>(cpuSampleMSec * 10000.0 + .5);
|
|
||||||
hr = addr(SystemPerformanceTraceInformation, &timeInfo, sizeof(EVENT_TRACE_TIME_PROFILE_INFORMATION)); // set interval to 10ms
|
|
||||||
if (hr != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
wprintf(L"Failed to set profile timer info\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
wprintf(L"\n BPerfCPUSamplesCollector is running ...\n");
|
|
||||||
|
|
||||||
wprintf(L" Profiling Timer Speed : %dms\n", cpuSampleMSec);
|
|
||||||
wprintf(L" File Rotation Period : %ds\n", rolloverTimeMSec / 1000);
|
|
||||||
wprintf(L" ETW Session Name: %s\n", LOGSESSION_NAME);
|
|
||||||
wprintf(L" Profiles Directory Location: %s\n", argv[3]);
|
|
||||||
|
|
||||||
if (argc >= 5)
|
|
||||||
{
|
|
||||||
wprintf(L" Using Symbol Data File: %s\n", argv[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc == 6)
|
|
||||||
{
|
|
||||||
wprintf(L" Process Name Filters: %s\n", argv[5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
wprintf(L"\n *** NOTE *** -> Profile file names start with ''BPerfProfiles'' followed by timestamp\n\n");
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (ctrlCTriggered)
|
|
||||||
{
|
|
||||||
wprintf(L"BPerf exiting in response to Ctrl+C.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto begin = FormatProfileSting();
|
|
||||||
|
|
||||||
hr = RelogTraceFile(sessionHandle, LOGFILE_NAME, rolloverTimeMSec, argc >= 5 ? argv[4] : nullptr);
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
{
|
|
||||||
wprintf(L"Exiting because Relogging failed.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end = FormatProfileSting();
|
|
||||||
|
|
||||||
auto destWString = (L"BPerfProfiles." + begin + L"_" + end + L".etl");
|
|
||||||
auto dest = destWString.c_str();
|
|
||||||
wprintf(L" Writing '%s' ...", dest);
|
|
||||||
MoveFileW(LOGFILE_NAME, dest);
|
|
||||||
wprintf(L" Done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
timeInfo.ProfileInterval = static_cast<int>(10000.0 + .5); // set back to 1ms
|
|
||||||
addr(SystemPerformanceTraceInformation, &timeInfo, sizeof(EVENT_TRACE_TIME_PROFILE_INFORMATION));
|
|
||||||
|
|
||||||
EVENT_TRACE_PROPERTIES properties;
|
|
||||||
ZeroMemory(&properties, sizeof(EVENT_TRACE_PROPERTIES));
|
|
||||||
properties.Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES);
|
|
||||||
ControlTrace(0, LOGSESSION_NAME, &properties, EVENT_TRACE_CONTROL_STOP);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (sessionProperties != nullptr)
|
|
||||||
{
|
|
||||||
free(sessionProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
CoUninitialize();
|
|
||||||
return HRESULT_CODE(hr);
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
#include "TraceEventCallback.h"
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
unordered_set<ULONG> threadingTrackingTable;
|
|
||||||
unordered_set<ULONG> taskTrackingTable;
|
|
||||||
|
|
||||||
__declspec(noinline) void HandleRundowCompletion(PEVENT_RECORD eventRecord, ITraceRelogger *relogger, bool isCancelled)
|
|
||||||
{
|
|
||||||
if (eventRecord->EventHeader.EventDescriptor.Opcode == RundownComplete && isCancelled)
|
|
||||||
{
|
|
||||||
relogger->Cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(noinline) void HandleBPerfStampingEvents(PEVENT_RECORD eventRecord)
|
|
||||||
{
|
|
||||||
switch (eventRecord->EventHeader.EventDescriptor.Id)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
threadingTrackingTable.insert(eventRecord->EventHeader.ThreadId);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
threadingTrackingTable.erase(eventRecord->EventHeader.ThreadId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(noinline) void HandleTplEvents(PEVENT_RECORD eventRecord)
|
|
||||||
{
|
|
||||||
switch (eventRecord->EventHeader.EventDescriptor.Id)
|
|
||||||
{
|
|
||||||
case TaskScheduled:
|
|
||||||
{
|
|
||||||
if (threadingTrackingTable.find(eventRecord->EventHeader.ThreadId) != threadingTrackingTable.end())
|
|
||||||
{
|
|
||||||
auto taskId = *reinterpret_cast<ULONG *>(static_cast<PBYTE>(eventRecord->UserData) + 8);
|
|
||||||
taskTrackingTable.insert(taskId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TaskStart:
|
|
||||||
{
|
|
||||||
auto taskId = *reinterpret_cast<ULONG *>(static_cast<PBYTE>(eventRecord->UserData) + 8);
|
|
||||||
if (taskTrackingTable.find(taskId) != taskTrackingTable.end())
|
|
||||||
{
|
|
||||||
// if yes, then we should track this thread also
|
|
||||||
threadingTrackingTable.insert(eventRecord->EventHeader.ThreadId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TaskStop:
|
|
||||||
{
|
|
||||||
auto taskId = *reinterpret_cast<ULONG *>(static_cast<PBYTE>(eventRecord->UserData) + 8);
|
|
||||||
taskTrackingTable.erase(taskId);
|
|
||||||
threadingTrackingTable.erase(eventRecord->EventHeader.ThreadId);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(noinline) void ResetThreadState(PEVENT_RECORD eventRecord)
|
|
||||||
{
|
|
||||||
if (eventRecord->EventHeader.ProviderId == ThreadGuid ||
|
|
||||||
eventRecord->EventHeader.ProviderId == ClrGuid &&
|
|
||||||
(eventRecord->EventHeader.EventDescriptor.Id == ThreadPoolWorkerThreadStartOpCode ||
|
|
||||||
eventRecord->EventHeader.EventDescriptor.Id == ThreadPoolWorkerThreadStopOpCode))
|
|
||||||
{
|
|
||||||
threadingTrackingTable.erase(eventRecord->EventHeader.ThreadId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE TraceEventCallback::OnEvent(ITraceEvent *traceEvent, ITraceRelogger *relogger)
|
|
||||||
{
|
|
||||||
PEVENT_RECORD eventRecord;
|
|
||||||
traceEvent->GetEventRecord(&eventRecord);
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == ThreadGuid && eventRecord->EventHeader.EventDescriptor.Opcode == CSwitchOpCode)
|
|
||||||
{
|
|
||||||
auto oldThreadId = *reinterpret_cast<ULONG *>(static_cast<PBYTE>(eventRecord->UserData) + 4);
|
|
||||||
if (threadingTrackingTable.find(oldThreadId) != threadingTrackingTable.end())
|
|
||||||
{
|
|
||||||
relogger->Inject(traceEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == TplEventSource)
|
|
||||||
{
|
|
||||||
HandleTplEvents(eventRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == BPerfStampingGuid)
|
|
||||||
{
|
|
||||||
HandleBPerfStampingEvents(eventRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == ThreadGuid || eventRecord->EventHeader.ProviderId == ClrGuid)
|
|
||||||
{
|
|
||||||
ResetThreadState(eventRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == ImageLoadGuid)
|
|
||||||
{
|
|
||||||
InjectKernelTraceControlEvents(eventRecord, relogger);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventRecord->EventHeader.ProviderId == RundownGuid)
|
|
||||||
{
|
|
||||||
HandleRundowCompletion(eventRecord, relogger, this->isCancelled);
|
|
||||||
}
|
|
||||||
|
|
||||||
return relogger->Inject(traceEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE TraceEventCallback::OnBeginProcessTrace(ITraceEvent *header, ITraceRelogger *relogger)
|
|
||||||
{
|
|
||||||
UNREFERENCED_PARAMETER(relogger);
|
|
||||||
UNREFERENCED_PARAMETER(header);
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE TraceEventCallback::OnFinalizeProcessTrace(ITraceRelogger *relogger)
|
|
||||||
{
|
|
||||||
if (this->jittedCodeSymbolicDataFile != nullptr)
|
|
||||||
{
|
|
||||||
HANDLE hFile = CreateFileW(this->jittedCodeSymbolicDataFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
if (hFile != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
LogJittedCodeSymbolicData(hFile, relogger);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
|
@ -1,164 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <objbase.h>
|
|
||||||
#include <relogger.h>
|
|
||||||
#include <atomic>
|
|
||||||
#include <agents.h>
|
|
||||||
#include <ppltasks.h>
|
|
||||||
#include <evntrace.h>
|
|
||||||
#include <strsafe.h>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <evntcons.h>
|
|
||||||
|
|
||||||
constexpr GUID PerfInfoGuid = {0xce1dbfb4, 0x137e, 0x4da6, {0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc}};
|
|
||||||
constexpr GUID BPerfStampingGuid = {0xD46E5565, 0xD624, 0x4C4D, {0x89, 0xCC, 0x7A, 0x82, 0x88, 0x7D, 0x36, 0x27}};
|
|
||||||
constexpr GUID ThreadGuid = {0x3d6fa8d1, 0xfe05, 0x11d0, {0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}};
|
|
||||||
constexpr GUID ProcessGuid = {0x3d6fa8d0, 0xfe05, 0x11d0, {0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c}};
|
|
||||||
constexpr GUID RundownGuid = {0x68fdd900, 0x4a3e, 0x11d1, {0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3}};
|
|
||||||
constexpr GUID ImageLoadGuid = {0x2cb15d1d, 0x5fc1, 0x11d2, {0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18}};
|
|
||||||
constexpr GUID ClrGuid = {0xE13C0D23, 0xCCBC, 0x4E12, {0x93, 0x1B, 0xD9, 0xCC, 0x2E, 0xEE, 0x27, 0xE4}};
|
|
||||||
constexpr GUID CoreClrGuid = {0x319DC449, 0xADA5, 0x50F7, {0x42, 0x8E, 0x95, 0x7D, 0xB6, 0x79, 0x16, 0x68}};
|
|
||||||
constexpr GUID TplEventSource = {0x2e5dba47, 0xa3d2, 0x4d16, {0x8e, 0xe0, 0x66, 0x71, 0xff, 0xdc, 0xd7, 0xb5}};
|
|
||||||
constexpr GUID AspNetEventSource = {0xee799f41, 0xcfa5, 0x550b, {0xbf, 0x2c, 0x34, 0x47, 0x47, 0xc1, 0xc6, 0x68}};
|
|
||||||
constexpr GUID TcpIpProviderGuid = {0x2f07e2ee, 0x15db, 0x40f1, {0x90, 0xef, 0x9d, 0x7b, 0xa2, 0x82, 0x18, 0x8a}};
|
|
||||||
constexpr GUID KernelProcessGuid = {0x22fb2cd6, 0x0e7b, 0x422b, {0xa0, 0xc7, 0x2f, 0xad, 0x1f, 0xd0, 0xe7, 0x16}};
|
|
||||||
constexpr GUID MonitoredScopeEventSource = {0x2e185d98, 0x344d, 0x5ef7, {0x06, 0x30, 0xaf, 0xe3, 0x22, 0xf0, 0x1b, 0x98}};
|
|
||||||
|
|
||||||
constexpr UCHAR CSwitchOpCode = 36;
|
|
||||||
constexpr UCHAR StackWalkOpCode = 32;
|
|
||||||
constexpr UCHAR DCStopOpCode = 4;
|
|
||||||
constexpr UCHAR ThreadPoolWorkerThreadStartOpCode = 50;
|
|
||||||
constexpr UCHAR ThreadPoolWorkerThreadStopOpCode = 51;
|
|
||||||
|
|
||||||
constexpr USHORT TaskScheduled = 7;
|
|
||||||
constexpr USHORT TaskStart = 8;
|
|
||||||
constexpr USHORT TaskStop = 9;
|
|
||||||
|
|
||||||
constexpr USHORT RundownComplete = 8;
|
|
||||||
|
|
||||||
__declspec(noinline) HRESULT InjectKernelTraceControlEvents(PEVENT_RECORD eventRecord, ITraceRelogger *relogger);
|
|
||||||
void LogJittedCodeSymbolicData(HANDLE hFile, ITraceRelogger *relogger);
|
|
||||||
|
|
||||||
using namespace concurrency;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
inline void DoRundown(TRACEHANDLE tracehandle, ULONG type)
|
|
||||||
{
|
|
||||||
EVENT_FILTER_DESCRIPTOR descriptor[1];
|
|
||||||
descriptor[0].Type = EVENT_FILTER_TYPE_TRACEHANDLE;
|
|
||||||
descriptor[0].Ptr = reinterpret_cast<ULONGLONG>(&tracehandle);
|
|
||||||
descriptor[0].Size = sizeof(TRACEHANDLE);
|
|
||||||
|
|
||||||
ENABLE_TRACE_PARAMETERS enableParameters;
|
|
||||||
ZeroMemory(&enableParameters, sizeof(ENABLE_TRACE_PARAMETERS));
|
|
||||||
enableParameters.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
|
|
||||||
enableParameters.EnableFilterDesc = descriptor;
|
|
||||||
enableParameters.FilterDescCount = 1;
|
|
||||||
|
|
||||||
EnableTraceEx2(tracehandle, &AspNetEventSource, EVENT_CONTROL_CODE_CAPTURE_STATE, 0, 0, 0, 0, &enableParameters);
|
|
||||||
EnableTraceEx2(tracehandle, &TplEventSource, EVENT_CONTROL_CODE_CAPTURE_STATE, 0, 0, 0, 0, &enableParameters);
|
|
||||||
EnableTraceEx2(tracehandle, &MonitoredScopeEventSource, EVENT_CONTROL_CODE_CAPTURE_STATE, 0, 0, 0, 0, &enableParameters);
|
|
||||||
|
|
||||||
GUID systemGuid = {0x9e814aad, 0x3204, 0x11d2, {0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39}};
|
|
||||||
EnableTraceEx2(tracehandle, &systemGuid, EVENT_CONTROL_CODE_CAPTURE_STATE, 0, type, 0, INFINITE, &enableParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void DoStartRundown(TRACEHANDLE tracehandle)
|
|
||||||
{
|
|
||||||
DoRundown(tracehandle, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void DoStopRundown(TRACEHANDLE tracehandle)
|
|
||||||
{
|
|
||||||
DoRundown(tracehandle, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a task that completes after the specified delay.
|
|
||||||
inline task<void> complete_after(unsigned int timeout)
|
|
||||||
{
|
|
||||||
// A task completion event that is set when a timer fires.
|
|
||||||
task_completion_event<void> tce;
|
|
||||||
|
|
||||||
// Create a non-repeating timer.
|
|
||||||
auto fire_once = new timer<int>(timeout, 0, nullptr, false);
|
|
||||||
// Create a call object that sets the completion event after the timer fires.
|
|
||||||
auto callback = new call<int>([tce](int) {
|
|
||||||
tce.set();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Connect the timer to the callback and start the timer.
|
|
||||||
fire_once->link_target(callback);
|
|
||||||
fire_once->start();
|
|
||||||
|
|
||||||
// Create a task that completes after the completion event is set.
|
|
||||||
task<void> event_set(tce);
|
|
||||||
|
|
||||||
// Create a continuation task that cleans up resources and
|
|
||||||
// and return that continuation task.
|
|
||||||
return event_set.then([callback, fire_once]() {
|
|
||||||
delete callback;
|
|
||||||
delete fire_once;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class TraceEventCallback : public ITraceEventCallback
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HRESULT STDMETHODCALLTYPE OnEvent(ITraceEvent *traceEvent, ITraceRelogger *relogger) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnBeginProcessTrace(ITraceEvent *header, ITraceRelogger *relogger) override;
|
|
||||||
HRESULT STDMETHODCALLTYPE OnFinalizeProcessTrace(ITraceRelogger *relogger) override;
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppObj) override
|
|
||||||
{
|
|
||||||
if (riid == __uuidof(IUnknown) || riid == __uuidof(ITraceEventCallback))
|
|
||||||
{
|
|
||||||
*ppObj = this;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*ppObj = nullptr;
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->AddRef();
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG STDMETHODCALLTYPE AddRef() override
|
|
||||||
{
|
|
||||||
return atomic_fetch_add(&this->refCount, 1) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG STDMETHODCALLTYPE Release() override
|
|
||||||
{
|
|
||||||
int count = atomic_fetch_sub(&this->refCount, 1) - 1;
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
TraceEventCallback(TRACEHANDLE tracehandle, ITraceRelogger *relogger, int rollOverTimeMSec, PWSTR jittedCodeSymbolicDataFile)
|
|
||||||
{
|
|
||||||
this->isCancelled = false;
|
|
||||||
this->refCount = 0;
|
|
||||||
this->jittedCodeSymbolicDataFile = jittedCodeSymbolicDataFile;
|
|
||||||
this->reloggerCancellationTask = complete_after(rollOverTimeMSec).then([this, relogger, tracehandle] {
|
|
||||||
this->isCancelled = true;
|
|
||||||
DoStopRundown(tracehandle);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~TraceEventCallback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool isCancelled;
|
|
||||||
atomic<int> refCount;
|
|
||||||
task<void> reloggerCancellationTask;
|
|
||||||
PWSTR jittedCodeSymbolicDataFile;
|
|
||||||
};
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#define BPERFDLLIMPORT
|
||||||
|
|
||||||
|
#include "../lib/Program.h"
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(hModule);
|
||||||
|
UNREFERENCED_PARAMETER(ul_reason_for_call);
|
||||||
|
UNREFERENCED_PARAMETER(lpReserved);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) int StartBPerf(int argc, PWSTR* argv, bool setCtrlCHandler, void(*fileMovedCallback)(const int length, const wchar_t *))
|
||||||
|
{
|
||||||
|
return InvokeBPerfStart(argc, argv, setCtrlCHandler, fileMovedCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) void StopBPerf()
|
||||||
|
{
|
||||||
|
InvokeBPerfStop();
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<TargetName>BPerfCPUSamplesCollectorLibrary</TargetName>
|
||||||
|
<ProjectGuid>{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>BPerfCPUSamplesCollectorLibrary</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>tdh.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<ExceptionHandling>false</ExceptionHandling>
|
||||||
|
<ControlFlowGuard>false</ControlFlowGuard>
|
||||||
|
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>tdh.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dll.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\lib\lib.vcxproj">
|
||||||
|
<Project>{4cc1c899-4372-4ff0-92b2-c841c332f17c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "../lib/Program.h"
|
||||||
|
|
||||||
|
int wmain(int argc, PWSTR *argv)
|
||||||
|
{
|
||||||
|
return InvokeBPerfStart(argc, argv, true, nullptr);
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
|
@ -11,21 +11,24 @@
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{628BB6D0-1469-4652-9DF9-B7FEC89F0548}</ProjectGuid>
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<TargetName>BPerfCPUSamplesCollector</TargetName>
|
||||||
|
<ProjectGuid>{8849F8A2-C5DC-4B8A-AE85-6BBD5C065171}</ProjectGuid>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>BPerfCPUSamplesCollector</RootNamespace>
|
<RootNamespace>BPerfCPUSamplesCollector</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v141</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -38,40 +41,47 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<AdditionalDependencies>version.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>tdh.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level4</WarningLevel>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<ExceptionHandling>false</ExceptionHandling>
|
||||||
|
<ControlFlowGuard>false</ControlFlowGuard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalDependencies>version.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>tdh.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="JittedCodeResolutionSupportCode.cpp" />
|
<ClCompile Include="exe.cpp" />
|
||||||
<ClCompile Include="KernelTraceControlSupportCode.cpp" />
|
|
||||||
<ClCompile Include="Program.cpp" />
|
|
||||||
<ClCompile Include="TraceEventCallback.cpp" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="TraceEventCallback.h" />
|
<ProjectReference Include="..\lib\lib.vcxproj">
|
||||||
|
<Project>{4cc1c899-4372-4ff0-92b2-c841c332f17c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,509 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <evntcons.h>
|
||||||
|
#include <string>
|
||||||
|
#include <relogger.h>
|
||||||
|
#include <evntrace.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
#include <tdh.h>
|
||||||
|
|
||||||
|
static DWORD RVAToFileOffset(PIMAGE_NT_HEADERS32 ntHeader, DWORD rva)
|
||||||
|
{
|
||||||
|
PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(ntHeader);
|
||||||
|
DWORD numberOfSections = ntHeader->FileHeader.NumberOfSections;
|
||||||
|
|
||||||
|
for (DWORD i = 0; i < numberOfSections; ++i)
|
||||||
|
{
|
||||||
|
if (sections[i].VirtualAddress <= rva && rva < sections[i].VirtualAddress + sections[i].Misc.VirtualSize)
|
||||||
|
{
|
||||||
|
return sections[i].PointerToRawData + (rva - sections[i].VirtualAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr UCHAR DCStartOpCode = 3;
|
||||||
|
constexpr UCHAR DCStopOpCode = 4;
|
||||||
|
|
||||||
|
#define SystemRoot L"\\SystemRoot"
|
||||||
|
#define GlobalRoot L"\\\\?\\GLOBALROOT"
|
||||||
|
|
||||||
|
#define MAX_EVENT_SIZE 65536
|
||||||
|
#define HALF_EVENT_SIZE 32768
|
||||||
|
|
||||||
|
#define addr(x) &x[0]
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
constexpr size_t countOf(T const (&)[N]) noexcept
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ReadInt32(PBYTE &data)
|
||||||
|
{
|
||||||
|
uint32_t retVal;
|
||||||
|
char *p = reinterpret_cast<char *>(&retVal);
|
||||||
|
|
||||||
|
p[0] = data[0];
|
||||||
|
p[1] = data[1];
|
||||||
|
p[2] = data[2];
|
||||||
|
p[3] = data[3];
|
||||||
|
|
||||||
|
data += 4;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ReadInt64(PBYTE &data)
|
||||||
|
{
|
||||||
|
uint64_t retVal;
|
||||||
|
char *p = reinterpret_cast<char *>(&retVal);
|
||||||
|
|
||||||
|
p[0] = data[0];
|
||||||
|
p[1] = data[1];
|
||||||
|
p[2] = data[2];
|
||||||
|
p[3] = data[3];
|
||||||
|
p[4] = data[4];
|
||||||
|
p[5] = data[5];
|
||||||
|
p[6] = data[6];
|
||||||
|
p[7] = data[7];
|
||||||
|
|
||||||
|
data += 8;
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T ReadPointer(PBYTE &data)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(data);
|
||||||
|
throw std::logic_error("T must be uint64_t or uint32_t");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
uint64_t ReadPointer<uint64_t>(PBYTE &data)
|
||||||
|
{
|
||||||
|
return ReadInt64(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
uint32_t ReadPointer<uint32_t>(PBYTE &data)
|
||||||
|
{
|
||||||
|
return ReadInt32(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class PtrSizeType>
|
||||||
|
class ImageLoad
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PtrSizeType ImageBase;
|
||||||
|
PtrSizeType ImageSize;
|
||||||
|
uint32_t ProcessId;
|
||||||
|
uint32_t ImageChecksum;
|
||||||
|
uint32_t TimeDateStamp;
|
||||||
|
uint32_t Reserved0;
|
||||||
|
PtrSizeType DefaultBase;
|
||||||
|
uint32_t Reserved1;
|
||||||
|
uint32_t Reserved2;
|
||||||
|
uint32_t Reserved3;
|
||||||
|
uint32_t Reserved4;
|
||||||
|
wchar_t* FileName;
|
||||||
|
|
||||||
|
ImageLoad(PBYTE data)
|
||||||
|
{
|
||||||
|
this->ImageBase = ReadPointer<PtrSizeType>(data);
|
||||||
|
this->ImageSize = ReadPointer<PtrSizeType>(data);
|
||||||
|
this->ProcessId = ReadInt32(data);
|
||||||
|
this->ImageChecksum = ReadInt32(data);
|
||||||
|
this->TimeDateStamp = ReadInt32(data);
|
||||||
|
this->Reserved0 = ReadInt32(data);
|
||||||
|
this->DefaultBase = ReadPointer<PtrSizeType>(data);
|
||||||
|
this->Reserved1 = ReadInt32(data);
|
||||||
|
this->Reserved2 = ReadInt32(data);
|
||||||
|
this->Reserved3 = ReadInt32(data);
|
||||||
|
this->Reserved4 = ReadInt32(data);
|
||||||
|
this->FileName = reinterpret_cast<wchar_t *>(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _CV_INFO_PDB70
|
||||||
|
{
|
||||||
|
DWORD CvSignature;
|
||||||
|
GUID Signature;
|
||||||
|
DWORD Age;
|
||||||
|
char PdbFileName[1];
|
||||||
|
} CV_INFO_PDB70, *PCV_INFO_PDB70;
|
||||||
|
|
||||||
|
constexpr GUID KernelTraceControlGuid = {0xB3E675D7, 0x2554, 0x4F18, {0x83, 0x0B, 0x27, 0x62, 0x73, 0x25, 0x60, 0xDE}};
|
||||||
|
constexpr GUID EventMetadataGuid = {0xbbccf6c1, 0x6cd1, 0x48c4, {0x80, 0xff, 0x83, 0x94, 0x82, 0xe3, 0x76, 0x71}};
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
constexpr size_t count_of(T (&)[N])
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
constexpr size_t size_of(T (&)[N])
|
||||||
|
{
|
||||||
|
return N * sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N>
|
||||||
|
constexpr size_t length_of(T (&)[N])
|
||||||
|
{
|
||||||
|
return N - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InjectDbgIdEvent(ITraceRelogger *relogger, PEVENT_RECORD eventRecord, PCV_INFO_PDB70 data, int eventPointerSize, int flags, DWORD processId)
|
||||||
|
{
|
||||||
|
BYTE payload[MAX_EVENT_SIZE];
|
||||||
|
|
||||||
|
ITraceEvent *duplicateEvent;
|
||||||
|
relogger->CreateEventInstance(0, flags, &duplicateEvent);
|
||||||
|
|
||||||
|
EVENT_DESCRIPTOR eventDescriptor;
|
||||||
|
eventDescriptor.Id = 0xFFFF;
|
||||||
|
eventDescriptor.Version = 2;
|
||||||
|
eventDescriptor.Channel = 0;
|
||||||
|
eventDescriptor.Level = 1;
|
||||||
|
eventDescriptor.Opcode = 36;
|
||||||
|
eventDescriptor.Task = 0;
|
||||||
|
eventDescriptor.Keyword = 0;
|
||||||
|
|
||||||
|
duplicateEvent->SetEventDescriptor(&eventDescriptor);
|
||||||
|
|
||||||
|
duplicateEvent->SetTimeStamp(&eventRecord->EventHeader.TimeStamp);
|
||||||
|
duplicateEvent->SetProcessorIndex(GetEventProcessorIndex(eventRecord));
|
||||||
|
duplicateEvent->SetProviderId(&KernelTraceControlGuid);
|
||||||
|
duplicateEvent->SetProcessId(processId);
|
||||||
|
duplicateEvent->SetThreadId(eventRecord->EventHeader.ThreadId);
|
||||||
|
|
||||||
|
auto pdbFileNameBufferLength = static_cast<int>(strlen(data->PdbFileName)) + 1;
|
||||||
|
const auto payloadSize = eventPointerSize + pdbFileNameBufferLength + 2 * sizeof(int) + sizeof(GUID);
|
||||||
|
auto ptr = addr(payload);
|
||||||
|
|
||||||
|
CopyMemory(ptr, eventRecord->UserData, eventPointerSize);
|
||||||
|
ptr += eventPointerSize;
|
||||||
|
CopyMemory(ptr, &processId, sizeof(int));
|
||||||
|
ptr += sizeof(int);
|
||||||
|
CopyMemory(ptr, &data->Signature, sizeof(GUID));
|
||||||
|
ptr += sizeof(GUID);
|
||||||
|
CopyMemory(ptr, &data->Age, sizeof(int));
|
||||||
|
ptr += sizeof(int);
|
||||||
|
CopyMemory(ptr, data->PdbFileName, pdbFileNameBufferLength);
|
||||||
|
|
||||||
|
duplicateEvent->SetPayload(addr(payload), static_cast<ULONG>(payloadSize));
|
||||||
|
relogger->Inject(duplicateEvent);
|
||||||
|
duplicateEvent->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InjectImgIdEvent(ITraceRelogger *relogger, PEVENT_RECORD eventRecord, PCWCHAR originalFileName, DWORD imageSize, DWORD timestamp, int eventPointerSize, int flags, DWORD processId)
|
||||||
|
{
|
||||||
|
BYTE payload[MAX_EVENT_SIZE];
|
||||||
|
|
||||||
|
ITraceEvent *duplicateEvent;
|
||||||
|
relogger->CreateEventInstance(0, flags, &duplicateEvent);
|
||||||
|
|
||||||
|
EVENT_DESCRIPTOR eventDescriptor;
|
||||||
|
eventDescriptor.Id = 0xFFFF;
|
||||||
|
eventDescriptor.Version = 2;
|
||||||
|
eventDescriptor.Channel = 0;
|
||||||
|
eventDescriptor.Level = 1;
|
||||||
|
eventDescriptor.Opcode = 0;
|
||||||
|
eventDescriptor.Task = 0;
|
||||||
|
eventDescriptor.Keyword = 0;
|
||||||
|
|
||||||
|
duplicateEvent->SetEventDescriptor(&eventDescriptor);
|
||||||
|
|
||||||
|
duplicateEvent->SetTimeStamp(&eventRecord->EventHeader.TimeStamp);
|
||||||
|
duplicateEvent->SetProcessorIndex(GetEventProcessorIndex(eventRecord));
|
||||||
|
duplicateEvent->SetProviderId(&KernelTraceControlGuid);
|
||||||
|
duplicateEvent->SetProcessId(processId);
|
||||||
|
duplicateEvent->SetThreadId(eventRecord->EventHeader.ThreadId);
|
||||||
|
|
||||||
|
auto originalFileNameBufferLength = (wcslen(originalFileName) + 1) * 2;
|
||||||
|
const auto payloadSize = eventPointerSize + originalFileNameBufferLength + 4 * sizeof(int);
|
||||||
|
auto ptr = addr(payload);
|
||||||
|
|
||||||
|
DWORD *zeroAddr = nullptr;
|
||||||
|
CopyMemory(ptr, eventRecord->UserData, eventPointerSize);
|
||||||
|
ptr += eventPointerSize;
|
||||||
|
CopyMemory(ptr, &imageSize, sizeof(int));
|
||||||
|
ptr += sizeof(int);
|
||||||
|
CopyMemory(ptr, &zeroAddr, sizeof(int));
|
||||||
|
ptr += sizeof(int);
|
||||||
|
CopyMemory(ptr, &processId, sizeof(int));
|
||||||
|
ptr += sizeof(int);
|
||||||
|
CopyMemory(ptr, ×tamp, sizeof(int));
|
||||||
|
ptr += sizeof(int);
|
||||||
|
CopyMemory(ptr, originalFileName, originalFileNameBufferLength);
|
||||||
|
|
||||||
|
duplicateEvent->SetPayload(addr(payload), static_cast<ULONG>(payloadSize));
|
||||||
|
relogger->Inject(duplicateEvent);
|
||||||
|
duplicateEvent->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT InjectKernelTraceControlEventsInner(PCWCHAR peFileName, PCWCHAR originalFileName, ITraceRelogger *relogger, PEVENT_RECORD eventRecord, DWORD processId)
|
||||||
|
{
|
||||||
|
const auto file = CreateFile(peFileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (file == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return ERROR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto mapFile = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||||
|
if (mapFile == nullptr)
|
||||||
|
{
|
||||||
|
CloseHandle(file);
|
||||||
|
return ERROR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto imageBase = reinterpret_cast<PBYTE>(MapViewOfFile(mapFile, FILE_MAP_READ, 0, 0, 0));
|
||||||
|
const auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(imageBase);
|
||||||
|
auto ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS32>(imageBase + dosHeader->e_lfanew);
|
||||||
|
|
||||||
|
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE || ntHeader->Signature != IMAGE_NT_SIGNATURE)
|
||||||
|
{
|
||||||
|
UnmapViewOfFile(imageBase);
|
||||||
|
CloseHandle(mapFile);
|
||||||
|
CloseHandle(file);
|
||||||
|
return ERROR_BAD_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto flags = EVENT_HEADER_FLAG_CLASSIC_HEADER;
|
||||||
|
int eventPointerSize;
|
||||||
|
DWORD sizeOfImage;
|
||||||
|
IMAGE_DATA_DIRECTORY debugDescriptorDirectory;
|
||||||
|
if ((eventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_64_BIT_HEADER) != 0)
|
||||||
|
{
|
||||||
|
auto ntHeader64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(imageBase + dosHeader->e_lfanew);
|
||||||
|
sizeOfImage = ntHeader64->OptionalHeader.SizeOfImage;
|
||||||
|
debugDescriptorDirectory = ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
|
||||||
|
eventPointerSize = 8;
|
||||||
|
flags |= EVENT_HEADER_FLAG_64_BIT_HEADER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sizeOfImage = ntHeader->OptionalHeader.SizeOfImage;
|
||||||
|
debugDescriptorDirectory = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
|
||||||
|
eventPointerSize = 4;
|
||||||
|
flags |= EVENT_HEADER_FLAG_32_BIT_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectImgIdEvent(relogger, eventRecord, originalFileName, sizeOfImage, ntHeader->FileHeader.TimeDateStamp, eventPointerSize, flags, processId);
|
||||||
|
|
||||||
|
if (debugDescriptorDirectory.VirtualAddress != 0)
|
||||||
|
{
|
||||||
|
auto debugDirectories = (PIMAGE_DEBUG_DIRECTORY)(imageBase + RVAToFileOffset(ntHeader, debugDescriptorDirectory.VirtualAddress));
|
||||||
|
ULONG numberOfDebugDirectories = debugDescriptorDirectory.Size / sizeof(IMAGE_DEBUG_DIRECTORY);
|
||||||
|
|
||||||
|
for (PIMAGE_DEBUG_DIRECTORY current = debugDirectories; numberOfDebugDirectories != 0; --numberOfDebugDirectories, ++current)
|
||||||
|
{
|
||||||
|
if (current->Type == IMAGE_DEBUG_TYPE_CODEVIEW)
|
||||||
|
{
|
||||||
|
const auto data = reinterpret_cast<PCV_INFO_PDB70>(imageBase + current->PointerToRawData);
|
||||||
|
|
||||||
|
if (data->CvSignature == 0x53445352) // RSDS in ASCII
|
||||||
|
{
|
||||||
|
InjectDbgIdEvent(relogger, eventRecord, data, eventPointerSize, flags, processId);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnmapViewOfFile(imageBase);
|
||||||
|
CloseHandle(mapFile);
|
||||||
|
CloseHandle(file);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void PEFileNameAndProcessIdFromEvent(PEVENT_RECORD eventRecord, DWORD *processId, wchar_t* ptr, size_t size)
|
||||||
|
{
|
||||||
|
ImageLoad<T> imgLoadEvent(static_cast<PBYTE>(eventRecord->UserData));
|
||||||
|
*processId = imgLoadEvent.ProcessId;
|
||||||
|
|
||||||
|
if (_wcsnicmp(imgLoadEvent.FileName, SystemRoot, length_of(SystemRoot)) == 0)
|
||||||
|
{
|
||||||
|
WCHAR windowsDirectory[(MAX_PATH + 1) * 2];
|
||||||
|
GetWindowsDirectory(addr(windowsDirectory), MAX_PATH);
|
||||||
|
|
||||||
|
StringCbPrintfW(ptr, size, L"%s%s", addr(windowsDirectory), imgLoadEvent.FileName + length_of(SystemRoot));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StringCbPrintfW(ptr, size, L"%s%s", GlobalRoot, imgLoadEvent.FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(noinline) HRESULT InjectKernelTraceControlEvents(PEVENT_RECORD eventRecord, ITraceRelogger *relogger)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
WCHAR peFileNamePtr[HALF_EVENT_SIZE];
|
||||||
|
BYTE buffer[HALF_EVENT_SIZE];
|
||||||
|
|
||||||
|
DWORD processId = 0;
|
||||||
|
if ((eventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_64_BIT_HEADER) != 0)
|
||||||
|
{
|
||||||
|
PEFileNameAndProcessIdFromEvent<uint64_t>(eventRecord, &processId, addr(peFileNamePtr), size_of(peFileNamePtr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PEFileNameAndProcessIdFromEvent<uint32_t>(eventRecord, &processId, addr(peFileNamePtr), size_of(peFileNamePtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD handle;
|
||||||
|
const DWORD versionSize = GetFileVersionInfoSize(peFileNamePtr, &handle);
|
||||||
|
if (versionSize > 0)
|
||||||
|
{
|
||||||
|
if (GetFileVersionInfo(peFileNamePtr, handle, versionSize, addr(buffer)) != 0)
|
||||||
|
{
|
||||||
|
struct LANGANDCODEPAGE
|
||||||
|
{
|
||||||
|
WORD wLanguage;
|
||||||
|
WORD wCodePage;
|
||||||
|
} * lpTranslate;
|
||||||
|
|
||||||
|
UINT cbTranslate;
|
||||||
|
|
||||||
|
VerQueryValue(addr(buffer), TEXT("\\VarFileInfo\\Translation"), reinterpret_cast<LPVOID *>(&lpTranslate), &cbTranslate);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < cbTranslate / sizeof(LANGANDCODEPAGE); ++i)
|
||||||
|
{
|
||||||
|
WCHAR dest[MAX_PATH + 1];
|
||||||
|
PWCHAR lpBuffer;
|
||||||
|
UINT dwBytes;
|
||||||
|
|
||||||
|
StringCchPrintf(dest, MAX_PATH, TEXT("\\StringFileInfo\\%04x%04x\\OriginalFilename"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
|
||||||
|
VerQueryValue(addr(buffer), dest, reinterpret_cast<LPVOID *>(&lpBuffer), &dwBytes);
|
||||||
|
|
||||||
|
if (dwBytes == 0)
|
||||||
|
{
|
||||||
|
StringCchPrintf(dest, MAX_PATH, TEXT("\\StringFileInfo\\%04x%04x\\InternalName"), lpTranslate[i].wLanguage, lpTranslate[i].wCodePage);
|
||||||
|
VerQueryValue(addr(buffer), dest, reinterpret_cast<LPVOID *>(&lpBuffer), &dwBytes);
|
||||||
|
|
||||||
|
if (dwBytes == 0)
|
||||||
|
{
|
||||||
|
lpBuffer = const_cast<PWCHAR>(peFileNamePtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LPWSTR lastDot = wcsrchr(lpBuffer, L'.');
|
||||||
|
|
||||||
|
if (lastDot == nullptr)
|
||||||
|
{
|
||||||
|
auto lpBuffer2 = lpBuffer + wcslen(lpBuffer);
|
||||||
|
lpBuffer2[0] = L'.';
|
||||||
|
lpBuffer2[1] = L'd';
|
||||||
|
lpBuffer2[2] = L'l';
|
||||||
|
lpBuffer2[3] = L'l';
|
||||||
|
lpBuffer2[4] = L'\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lastDot && !_wcsicmp(lastDot, L".MUI"))
|
||||||
|
{
|
||||||
|
*lastDot = UNICODE_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto strippedPeFile = wcsrchr(lpBuffer, '\\');
|
||||||
|
if (strippedPeFile == nullptr)
|
||||||
|
{
|
||||||
|
strippedPeFile = lpBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strippedPeFile += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectKernelTraceControlEventsInner(peFileNamePtr, strippedPeFile, relogger, eventRecord, processId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto strippedPeFile = wcsrchr(peFileNamePtr, '\\');
|
||||||
|
if (strippedPeFile == nullptr)
|
||||||
|
{
|
||||||
|
strippedPeFile = peFileNamePtr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strippedPeFile += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectKernelTraceControlEventsInner(peFileNamePtr, strippedPeFile, relogger, eventRecord, processId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(noinline) HRESULT InjectTraceEventInfoEvent(PEVENT_RECORD eventRecord, ITraceRelogger *relogger)
|
||||||
|
{
|
||||||
|
ULONG bufferSize = 0;
|
||||||
|
TDHSTATUS status;
|
||||||
|
BYTE buffer[MAX_EVENT_SIZE];
|
||||||
|
|
||||||
|
if ((eventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_CLASSIC_HEADER) != 0)
|
||||||
|
{
|
||||||
|
status = TdhGetEventInformation(eventRecord, 0, nullptr, nullptr, &bufferSize);
|
||||||
|
|
||||||
|
if (status == ERROR_INSUFFICIENT_BUFFER && bufferSize > 0)
|
||||||
|
{
|
||||||
|
status = TdhGetEventInformation(eventRecord, 0, nullptr, (PTRACE_EVENT_INFO)addr(buffer), &bufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = TdhGetManifestEventInformation(&eventRecord->EventHeader.ProviderId, &eventRecord->EventHeader.EventDescriptor, nullptr, &bufferSize);
|
||||||
|
|
||||||
|
if (status == ERROR_INSUFFICIENT_BUFFER && bufferSize > 0)
|
||||||
|
{
|
||||||
|
status = TdhGetManifestEventInformation(&eventRecord->EventHeader.ProviderId, &eventRecord->EventHeader.EventDescriptor, (PTRACE_EVENT_INFO)addr(buffer), &bufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
auto flags = EVENT_HEADER_FLAG_CLASSIC_HEADER;
|
||||||
|
if ((eventRecord->EventHeader.Flags & EVENT_HEADER_FLAG_64_BIT_HEADER) != 0)
|
||||||
|
{
|
||||||
|
flags |= EVENT_HEADER_FLAG_64_BIT_HEADER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags |= EVENT_HEADER_FLAG_32_BIT_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITraceEvent *duplicateEvent;
|
||||||
|
relogger->CreateEventInstance(0, flags, &duplicateEvent);
|
||||||
|
|
||||||
|
EVENT_DESCRIPTOR eventDescriptor;
|
||||||
|
eventDescriptor.Id = 0xFFFF;
|
||||||
|
eventDescriptor.Version = 0;
|
||||||
|
eventDescriptor.Channel = 0;
|
||||||
|
eventDescriptor.Level = 0;
|
||||||
|
eventDescriptor.Opcode = 32;
|
||||||
|
eventDescriptor.Task = 0;
|
||||||
|
eventDescriptor.Keyword = 0;
|
||||||
|
|
||||||
|
duplicateEvent->SetEventDescriptor(&eventDescriptor);
|
||||||
|
|
||||||
|
duplicateEvent->SetProcessorIndex(GetEventProcessorIndex(eventRecord));
|
||||||
|
duplicateEvent->SetProviderId(&EventMetadataGuid);
|
||||||
|
duplicateEvent->SetTimeStamp(&eventRecord->EventHeader.TimeStamp);
|
||||||
|
duplicateEvent->SetProcessId(eventRecord->EventHeader.ProcessId);
|
||||||
|
duplicateEvent->SetThreadId(eventRecord->EventHeader.ThreadId);
|
||||||
|
|
||||||
|
duplicateEvent->SetPayload(addr(buffer), static_cast<ULONG>(bufferSize));
|
||||||
|
relogger->Inject(duplicateEvent);
|
||||||
|
duplicateEvent->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
constexpr GUID ImageLoadGuid = { 0x2cb15d1d, 0x5fc1, 0x11d2, {0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18} };
|
||||||
|
constexpr GUID ClrProviderGuid = { 0xE13C0D23, 0xCCBC, 0x4E12, {0x93, 0x1B, 0xD9, 0xCC, 0x2E, 0xEE, 0x27, 0xE4} };
|
||||||
|
constexpr GUID KernelProcessGuid = { 0x22fb2cd6, 0x0e7b, 0x422b, { 0xa0, 0xc7, 0x2f, 0xad, 0x1f, 0xd0, 0xe7, 0x16 } };
|
||||||
|
|
||||||
|
constexpr USHORT MethodLoadEvent = 143;
|
||||||
|
constexpr USHORT MethodUnloadEvent = 144;
|
||||||
|
constexpr USHORT ModuleLoadEvent = 152;
|
||||||
|
constexpr USHORT ModuleUnloadEvent = 153;
|
||||||
|
constexpr USHORT ILToNativeMapEvent = 190;
|
||||||
|
|
||||||
|
struct SafeFileHandle
|
||||||
|
{
|
||||||
|
SafeFileHandle(HANDLE handle)
|
||||||
|
{
|
||||||
|
this->h = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFileHandle(SafeFileHandle &&movedFrom) noexcept
|
||||||
|
{
|
||||||
|
this->h = movedFrom.h;
|
||||||
|
movedFrom.h = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFileHandle(const SafeFileHandle& that)
|
||||||
|
{
|
||||||
|
this->h = that.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeFileHandle& operator=(const SafeFileHandle& that)
|
||||||
|
{
|
||||||
|
this->h = that.h;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SafeFileHandle()
|
||||||
|
{
|
||||||
|
if (this->h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(this->h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const HANDLE Get() const
|
||||||
|
{
|
||||||
|
return this->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HANDLE h;
|
||||||
|
};
|
||||||
|
|
||||||
|
int InvokeBPerfStart(const int argc, PWSTR *argv, bool setCtrlCHandler, void (*fileMovedCallback)(const int length, const wchar_t *));
|
||||||
|
void InvokeBPerfStop();
|
|
@ -0,0 +1,389 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <objbase.h>
|
||||||
|
#include <relogger.h>
|
||||||
|
#include <evntrace.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
#include <evntcons.h>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
struct EventKey
|
||||||
|
{
|
||||||
|
GUID ProviderGuid;
|
||||||
|
USHORT EventId;
|
||||||
|
UCHAR Version;
|
||||||
|
|
||||||
|
EventKey(const GUID &providerId, USHORT eventId, UCHAR version) : ProviderGuid(providerId), EventId(eventId), Version(version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const EventKey &other) const noexcept
|
||||||
|
{
|
||||||
|
return InlineIsEqualGUID(this->ProviderGuid, other.ProviderGuid) && this->EventId == other.EventId && this->Version == other.Version;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EventKeyHasher
|
||||||
|
{
|
||||||
|
size_t operator()(const EventKey &k) const noexcept
|
||||||
|
{
|
||||||
|
using std::size_t;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
const uint64_t *p = reinterpret_cast<const uint64_t *>(&k.ProviderGuid);
|
||||||
|
const std::hash<uint64_t> hash;
|
||||||
|
|
||||||
|
return hash(p[0]) ^ hash(p[1]) ^ k.EventId ^ k.Version;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ContextInfo
|
||||||
|
{
|
||||||
|
ContextInfo(PBYTE buffer, PBYTE compressionBuffer, PBYTE workspace, HANDLE dataFile, HANDLE indexFile, HANDLE metadataFile, ITraceRelogger *relogger, BOOL enableMetadata, BOOL enableSymbolServerInfo, const std::unordered_map<std::wstring, std::wstring> * volumeMap)
|
||||||
|
{
|
||||||
|
this->Buffer = buffer;
|
||||||
|
this->CompressionBuffer = compressionBuffer;
|
||||||
|
this->Workspace = workspace;
|
||||||
|
this->DataFile = dataFile;
|
||||||
|
this->IndexFile = indexFile;
|
||||||
|
this->MetadataFile = metadataFile;
|
||||||
|
|
||||||
|
this->Offset = 0;
|
||||||
|
this->LastEventIndexedTimeStamp = 0;
|
||||||
|
this->PerfFreq = 0;
|
||||||
|
this->Relogger = relogger;
|
||||||
|
this->EnableMetadata = enableMetadata;
|
||||||
|
this->EnableSymbolServerInfo = enableSymbolServerInfo;
|
||||||
|
this->VolumeMap = volumeMap;
|
||||||
|
#ifdef DEBUG
|
||||||
|
this->TotalEvents = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<EventKey, EventKeyHasher> EventMetadataWrittenMap;
|
||||||
|
PBYTE Buffer;
|
||||||
|
DWORD Offset;
|
||||||
|
LONGLONG LastEventIndexedTimeStamp;
|
||||||
|
LONGLONG PerfFreq;
|
||||||
|
|
||||||
|
HANDLE DataFile;
|
||||||
|
HANDLE IndexFile;
|
||||||
|
HANDLE MetadataFile;
|
||||||
|
|
||||||
|
PBYTE CompressionBuffer;
|
||||||
|
PBYTE Workspace;
|
||||||
|
|
||||||
|
ITraceRelogger *Relogger;
|
||||||
|
BOOL EnableMetadata;
|
||||||
|
BOOL EnableSymbolServerInfo;
|
||||||
|
const std::unordered_map<std::wstring, std::wstring> * VolumeMap;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
ULONG TotalEvents;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ContextInfo2
|
||||||
|
{
|
||||||
|
ContextInfo2(FILETIME startTime, LARGE_INTEGER startQPC, const wchar_t * dataDirectory, const std::unordered_set<std::wstring> * clrProcessNamesSet, const std::unordered_map<std::wstring, std::wstring> * volumeMap)
|
||||||
|
{
|
||||||
|
this->StartTime = startTime;
|
||||||
|
this->StartQPC = startQPC;
|
||||||
|
this->DataDirectory = dataDirectory;
|
||||||
|
this->CLRProcessNamesSet = clrProcessNamesSet;
|
||||||
|
this->VolumeMap = volumeMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unordered_set<std::wstring> * CLRProcessNamesSet;
|
||||||
|
|
||||||
|
FILETIME StartTime;
|
||||||
|
LARGE_INTEGER StartQPC;
|
||||||
|
const wchar_t * DataDirectory;
|
||||||
|
const std::unordered_map<std::wstring, std::wstring> * VolumeMap;
|
||||||
|
|
||||||
|
std::unordered_map<ULONG, SafeFileHandle> ManagedMethodMapFile;
|
||||||
|
std::unordered_map<ULONG, SafeFileHandle> ManagedILToNativeMapFile;
|
||||||
|
std::unordered_map<ULONG, SafeFileHandle> ManagedModuleMapFile;
|
||||||
|
std::unordered_map<ULONG, SafeFileHandle> NativeModuleMapFile;
|
||||||
|
std::unordered_map<ULONG, SafeFileHandle> DataFile;
|
||||||
|
std::unordered_map<ULONG, LONG> OffsetIntoDataFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
__declspec(noinline) HRESULT InjectKernelTraceControlEvents(PEVENT_RECORD eventRecord, ITraceRelogger *relogger);
|
||||||
|
__declspec(noinline) HRESULT InjectTraceEventInfoEvent(PEVENT_RECORD eventRecord, ITraceRelogger *relogger);
|
||||||
|
|
||||||
|
class TraceEventCallback : public ITraceEventCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HRESULT STDMETHODCALLTYPE OnEvent(ITraceEvent *traceEvent, ITraceRelogger *relogger) override;
|
||||||
|
HRESULT STDMETHODCALLTYPE OnBeginProcessTrace(ITraceEvent *header, ITraceRelogger *relogger) override;
|
||||||
|
HRESULT STDMETHODCALLTYPE OnFinalizeProcessTrace(ITraceRelogger *relogger) override;
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppObj) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(riid);
|
||||||
|
UNREFERENCED_PARAMETER(ppObj);
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef() override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE Release() override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceEventCallback(BOOL enableMetadata, BOOL enableSymbolServerInfo, const std::unordered_map<std::wstring, std::wstring>* volumeMap)
|
||||||
|
{
|
||||||
|
this->enableMetadata = enableMetadata;
|
||||||
|
this->enableSymbolServerInfo = enableSymbolServerInfo;
|
||||||
|
this->volumeMap = volumeMap;
|
||||||
|
this->qpc = { 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TraceEventCallback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BOOL enableMetadata;
|
||||||
|
BOOL enableSymbolServerInfo;
|
||||||
|
std::unordered_set<EventKey, EventKeyHasher> eventMetadataLogged;
|
||||||
|
LARGE_INTEGER qpc;
|
||||||
|
const std::unordered_map<std::wstring, std::wstring>* volumeMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FakeTraceEvent : public ITraceEvent
|
||||||
|
{
|
||||||
|
HRESULT STDMETHODCALLTYPE Clone(ITraceEvent **NewEvent) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(NewEvent);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetUserContext(void **UserContext) override
|
||||||
|
{
|
||||||
|
*UserContext = &this->eventRecord.UserContext;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE GetEventRecord(PEVENT_RECORD *EventRecord) override
|
||||||
|
{
|
||||||
|
*EventRecord = &this->eventRecord;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetPayload(BYTE *Payload, ULONG PayloadSize) override
|
||||||
|
{
|
||||||
|
this->eventRecord.UserData = Payload;
|
||||||
|
this->eventRecord.UserDataLength = (USHORT)PayloadSize;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetEventDescriptor(PCEVENT_DESCRIPTOR EventDescriptor) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.EventDescriptor = *EventDescriptor;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetProcessId(ULONG ProcessId) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.ProcessId = ProcessId;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetProcessorIndex(ULONG ProcessorIndex) override
|
||||||
|
{
|
||||||
|
this->eventRecord.BufferContext.ProcessorIndex = (USHORT)ProcessorIndex;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetThreadId(ULONG ThreadId) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.ThreadId = ThreadId;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetThreadTimes(ULONG KernelTime, ULONG UserTime) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.KernelTime = KernelTime;
|
||||||
|
this->eventRecord.EventHeader.UserTime = UserTime;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetActivityId(LPCGUID ActivityId) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.ActivityId = *ActivityId;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetTimeStamp(LARGE_INTEGER *TimeStamp) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.TimeStamp = *TimeStamp;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetProviderId(LPCGUID ProviderId) override
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.ProviderId = *ProviderId;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppObj) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(riid);
|
||||||
|
UNREFERENCED_PARAMETER(ppObj);
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef() override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE Release() override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
EVENT_RECORD eventRecord;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FakeTraceEvent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(USHORT flags)
|
||||||
|
{
|
||||||
|
this->eventRecord = { 0 };
|
||||||
|
|
||||||
|
this->eventRecord.EventHeader.Flags = flags;
|
||||||
|
|
||||||
|
if ((flags & EVENT_HEADER_FLAG_CLASSIC_HEADER) != 0)
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.EventProperty = EVENT_HEADER_PROPERTY_LEGACY_EVENTLOG;
|
||||||
|
this->eventRecord.EventHeader.HeaderType = 0;
|
||||||
|
this->eventRecord.EventHeader.Size = (USHORT)sizeof(EVENT_HEADER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->eventRecord.EventHeader.EventProperty = EVENT_HEADER_PROPERTY_XML;
|
||||||
|
this->eventRecord.EventHeader.HeaderType = 1;
|
||||||
|
this->eventRecord.EventHeader.Size = (USHORT)sizeof(EVENT_HEADER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FakeTraceRelogger : public ITraceRelogger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HRESULT SetUserContext(ContextInfo *context)
|
||||||
|
{
|
||||||
|
this->userContext = context;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE AddLogfileTraceStream(BSTR LogfileName, void *UserContext, TRACEHANDLE *TraceHandle) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(LogfileName);
|
||||||
|
UNREFERENCED_PARAMETER(UserContext);
|
||||||
|
UNREFERENCED_PARAMETER(TraceHandle);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE AddRealtimeTraceStream(BSTR LoggerName, void *UserContext, TRACEHANDLE *TraceHandle) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(LoggerName);
|
||||||
|
UNREFERENCED_PARAMETER(UserContext);
|
||||||
|
UNREFERENCED_PARAMETER(TraceHandle);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE RegisterCallback(ITraceEventCallback *Callback) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(Callback);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE Inject(ITraceEvent *Event) override
|
||||||
|
{
|
||||||
|
PEVENT_RECORD eventRecord;
|
||||||
|
Event->GetEventRecord(&eventRecord);
|
||||||
|
eventRecord->UserContext = this->userContext;
|
||||||
|
|
||||||
|
BOOL enableMetadata = this->userContext->EnableMetadata;
|
||||||
|
BOOL enableSymbolServerInfo = this->userContext->EnableSymbolServerInfo;
|
||||||
|
|
||||||
|
this->userContext->EnableMetadata = FALSE;
|
||||||
|
this->userContext->EnableSymbolServerInfo = FALSE;
|
||||||
|
|
||||||
|
this->callback(eventRecord);
|
||||||
|
|
||||||
|
this->userContext->EnableMetadata = enableMetadata;
|
||||||
|
this->userContext->EnableSymbolServerInfo = enableSymbolServerInfo;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE CreateEventInstance(TRACEHANDLE TraceHandle, ULONG Flags, ITraceEvent **Event) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(TraceHandle);
|
||||||
|
this->fakeTraceEvent.Initialize((USHORT)Flags);
|
||||||
|
*Event = &this->fakeTraceEvent; // NOTE: This is valid because all calls to CreateEventInstance are within the lifetime of this Relogger, and there is no recursion.
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE ProcessTrace(void) override
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetOutputFilename(BSTR LogfileName) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(LogfileName);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE SetCompressionMode(BOOLEAN CompressionMode) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(CompressionMode);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE Cancel(void) override
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppObj) override
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(riid);
|
||||||
|
UNREFERENCED_PARAMETER(ppObj);
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE AddRef() override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE Release() override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PEVENT_RECORD_CALLBACK callback;
|
||||||
|
ContextInfo *userContext;
|
||||||
|
FakeTraceEvent fakeTraceEvent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FakeTraceRelogger(PEVENT_RECORD_CALLBACK callback)
|
||||||
|
{
|
||||||
|
this->callback = callback;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<TargetName>BPerfCPUSamplesCollector</TargetName>
|
||||||
|
<ProjectGuid>{4CC1C899-4372-4FF0-92B2-C841C332F17C}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>BPerfCPUSamplesCollector</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>tdh.lib;version.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level4</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<ExceptionHandling>false</ExceptionHandling>
|
||||||
|
<ControlFlowGuard>false</ControlFlowGuard>
|
||||||
|
<OmitFramePointers>true</OmitFramePointers>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>tdh.lib;version.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="KernelTraceControlSupportCode.cpp" />
|
||||||
|
<ClCompile Include="Program.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Program.h" />
|
||||||
|
<ClInclude Include="TraceEventCallback.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,59 @@
|
||||||
|
namespace Microsoft.BPerf
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
public delegate void FileMoveNotifyCallback(string fileName);
|
||||||
|
|
||||||
|
internal delegate void FileMoveCallbackInternal(int length, IntPtr fileName);
|
||||||
|
|
||||||
|
public static class DataCollector
|
||||||
|
{
|
||||||
|
private static FileMoveNotifyCallback fileMoveNotifyCallback;
|
||||||
|
|
||||||
|
public static void Start(string fullDirectoryPath, int rollOverTimeSeconds, FileMoveNotifyCallback callback)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(fullDirectoryPath))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(fullDirectoryPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] argvs = { "unused", "1", rollOverTimeSeconds.ToString(), fullDirectoryPath };
|
||||||
|
IntPtr[] arr = new IntPtr[argvs.Length];
|
||||||
|
|
||||||
|
for (var i = 0; i < argvs.Length; ++i)
|
||||||
|
{
|
||||||
|
arr[i] = Marshal.StringToHGlobalUni(argvs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileMoveCallbackInternal c = FileMoveInternal;
|
||||||
|
|
||||||
|
fileMoveNotifyCallback = callback;
|
||||||
|
StartBPerf(argvs.Length, arr, false, Marshal.GetFunctionPointerForDelegate(c));
|
||||||
|
|
||||||
|
GC.KeepAlive(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stop()
|
||||||
|
{
|
||||||
|
StopBPerf();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FileMoveInternal(int length, IntPtr fileNamePtr)
|
||||||
|
{
|
||||||
|
string fileName = Marshal.PtrToStringUni(fileNamePtr, length);
|
||||||
|
fileMoveNotifyCallback(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(@"BPerfCPUSamplesCollectorLibrary.dll")]
|
||||||
|
private static extern int StartBPerf(int argc, IntPtr[] argv, bool setCtrlCHandler, IntPtr fileMoveCallback);
|
||||||
|
|
||||||
|
[DllImport(@"BPerfCPUSamplesCollectorLibrary.dll")]
|
||||||
|
private static extern void StopBPerf();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
Загрузка…
Ссылка в новой задаче