зеркало из 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
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26020.0
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28803.202
|
||||
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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Debug|x64.Build.0 = Debug|x64
|
||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Release|x64.ActiveCfg = Release|x64
|
||||
{628BB6D0-1469-4652-9DF9-B7FEC89F0548}.Release|x64.Build.0 = Release|x64
|
||||
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7CEF2038-7FBC-4C06-880E-C2B64FF17D8D}.Debug|x64.Build.0 = Debug|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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8E75CC9E-19C0-4956-B5AA-9430652BA3D6}
|
||||
EndGlobalSection
|
||||
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"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<?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>
|
||||
|
@ -11,21 +11,24 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<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>
|
||||
<RootNamespace>BPerfCPUSamplesCollector</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
|
@ -38,40 +41,47 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>version.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>tdh.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<ControlFlowGuard>false</ControlFlowGuard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>version.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>tdh.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="JittedCodeResolutionSupportCode.cpp" />
|
||||
<ClCompile Include="KernelTraceControlSupportCode.cpp" />
|
||||
<ClCompile Include="Program.cpp" />
|
||||
<ClCompile Include="TraceEventCallback.cpp" />
|
||||
<ClCompile Include="exe.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="TraceEventCallback.h" />
|
||||
<ProjectReference Include="..\lib\lib.vcxproj">
|
||||
<Project>{4cc1c899-4372-4ff0-92b2-c841c332f17c}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</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>
|
Загрузка…
Ссылка в новой задаче