-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add helper script to start profiling on windows
The script uses invokes XPerf (elevating via Windows UAC dialogs if necessary) and support sample based profiling for regular timing events, as well es PMC events. Additionally, it introduces a new event provider and event to attach information about the target process that is being profiled to the ETL file.
- Loading branch information
1 parent
eef85ef
commit 5788d2b
Showing
8 changed files
with
310 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<instrumentationManifest | ||
xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" | ||
xmlns="http://schemas.microsoft.com/win/2004/08/events" | ||
xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:xs="http://www.w3.org/2001/XMLSchema" | ||
xmlns:trace="http://schemas.microsoft.com/win/2004/08/events/trace"> | ||
<instrumentation> | ||
<events> | ||
<provider name="Snail-Profiler" | ||
guid="{460B83B6-FC11-481B-B7AA-4038CA4C4C48}" symbol="SnailProfiler" | ||
resourceFileName="." messageFileName="."> | ||
<events> | ||
<event symbol="ProfilingTarget" value="1" version="0" | ||
level="win:Informational" template="ProfilingTargetTemplate" | ||
message="$(string.Snail-Profiler.event.1.message)"> | ||
</event> | ||
</events> | ||
<levels> | ||
</levels> | ||
<templates> | ||
<template tid="ProfilingTargetTemplate"> | ||
<data name="ProcessId" inType="win:UInt32" outType="xs:unsignedInt"> | ||
</data> | ||
</template> | ||
</templates> | ||
</provider> | ||
</events> | ||
</instrumentation> | ||
<localization> | ||
<resources culture="en-US"> | ||
<stringTable> | ||
<string id="level.Informational" value="Information"> | ||
</string> | ||
<string id="Snail-Profiler.event.1.message" | ||
value="Profiling target (%1)."> | ||
</string> | ||
</stringTable> | ||
</resources> | ||
</localization> | ||
</instrumentationManifest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
function Start-Profiling { | ||
param ( | ||
[Parameter()] | ||
[ValidateSet('Low', 'Medium', 'High')] | ||
[string]$SamplingRate = 'Medium', | ||
|
||
[Parameter()] | ||
[string]$OutputName = 'profile', | ||
|
||
[Parameter()] | ||
[string[]]$Pmc = @(), | ||
|
||
[Parameter(Position = 0, ValueFromRemainingArguments)] | ||
[string[]]$Command | ||
) | ||
|
||
Set-Variable secondTo100Nanoseconds -Option Constant -Value 10000000 | ||
Set-Variable refTimerSamplesPerSecond -Option Constant -Value 1000 | ||
Set-Variable refCounterInterval -Option Constant -Value 65536 | ||
|
||
switch ($SamplingRate) { | ||
{ $_ -eq 'Low' } { | ||
$samplesPerSecond = 100 | ||
} | ||
{ $_ -eq 'Medium' } { | ||
$samplesPerSecond = $refTimerSamplesPerSecond | ||
} | ||
{ $_ -eq 'High' } { | ||
$samplesPerSecond = 4000 | ||
} | ||
default { | ||
$samplesPerSecond = $refTimerSamplesPerSecond | ||
} | ||
} | ||
$timerInterval = [math]::Round(1 / $samplesPerSecond * $secondTo100Nanoseconds) | ||
$counterInterval = [math]::Round($refTimerSamplesPerSecond / $samplesPerSecond * $refCounterInterval) | ||
|
||
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) | ||
$isElevated = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | ||
|
||
$kernelEvents = @( | ||
'PROC_THREAD', | ||
'LOADER', | ||
'PROFILE' | ||
) | ||
|
||
$pmcArgs = @() | ||
if ($Pmc.Count -gt 0) { | ||
$kernelEvents += 'PMC_PROFILE' | ||
$pmcArgs += '-PmcProfile' | ||
$pmcArgs += $Pmc -join ',' | ||
foreach ($counterName in $Pmc) { | ||
$pmcArgs += '-SetProfInt' | ||
$pmcArgs += $counterName | ||
$pmcArgs += $counterInterval | ||
} | ||
# $kernelEvents += 'CSWITCH' | ||
# $pmcArgs += '-Pmc' | ||
# $pmcArgs += $Pmc -join ',' | ||
# $pmcArgs += 'CSWITCH' | ||
# $pmcArgs += 'strict' | ||
} | ||
|
||
$kernelEventsArg = $kernelEvents -join '+' | ||
|
||
$snailProviderGuid = [System.Guid]'{460B83B6-FC11-481B-B7AA-4038CA4C4C48}' | ||
|
||
$xperfStartArgs = @( | ||
'-start', 'SnailProfiling', | ||
'-on', $snailProviderGuid.ToString(), | ||
'-f', "`"${OutputName}_user.etl`"" | ||
'-start', '"NT Kernel Logger"', | ||
'-on', $kernelEventsArg, | ||
'-SetProfInt', 'Timer', $timerInterval, | ||
'-stackwalk', 'Profile', | ||
'-f', "`"${OutputName}_kernel.etl`"" | ||
) | ||
$xperfStartArgs += $pmcArgs | ||
|
||
Write-Host $xperfStartArgs | ||
|
||
$commandExecutable = $Command[0] | ||
$commandArguments = $Command | Select-Object -Skip 1 | ||
|
||
$eventProvider = New-Object -TypeName System.Diagnostics.Eventing.EventProvider -ArgumentList ($snailProviderGuid) | ||
try { | ||
$eventDescriptor = New-Object -TypeName System.Diagnostics.Eventing.EventDescriptor -ArgumentList (0x1, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0); | ||
|
||
if ($isElevated) { | ||
$xperfProcess = Start-Process -FilePath xperf -ArgumentList $xperfStartArgs -PassThru -Wait -NoNewWindow | ||
} | ||
else { | ||
$xperfProcess = Start-Process -FilePath xperf -ArgumentList $xperfStartArgs -PassThru -Wait -Verb RunAs | ||
} | ||
if ($xperfProcess.ExitCode -ne 0) { return; } | ||
|
||
try { | ||
$process = Start-Process -FilePath $commandExecutable -ArgumentList $commandArguments -PassThru -NoNewWindow | ||
$eventProvider.WriteEvent([ref] $eventDescriptor, $process.Id) | Out-Null | ||
$process.WaitForExit() | ||
$process.Dispose() | ||
} | ||
finally { | ||
xperf -stop SnailProfiling | ||
|
||
if ($isElevated) { | ||
Start-Process -FilePath xperf -ArgumentList '-stop' -Wait -NoNewWindow | ||
} | ||
else { | ||
Start-Process -FilePath xperf -ArgumentList '-stop' -Wait -Verb RunAs | ||
} | ||
} | ||
|
||
xperf -merge "${OutputName}_user.etl" "${OutputName}_kernel.etl" "${OutputName}.etl" #-suppresspii | ||
if ($LASTEXITCODE -eq 0) { | ||
Remove-Item "${OutputName}_user.etl", "${OutputName}_kernel.etl" | ||
} | ||
} | ||
finally { | ||
$eventProvider.Dispose() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
|
||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
#include <array> | ||
#include <optional> | ||
#include <string> | ||
|
||
#include <snail/common/guid.hpp> | ||
|
||
#include <snail/etl/parser/extract.hpp> | ||
#include <snail/etl/parser/records/identifier.hpp> | ||
#include <snail/etl/parser/utility.hpp> | ||
|
||
namespace snail::etl::parser { | ||
|
||
constexpr inline auto snail_profiler_guid = common::guid{ | ||
0x460b'83b6, 0xfc11, 0x481b, {0xb7, 0xaa, 0x40, 0x38, 0xca, 0x4c, 0x4c, 0x48} | ||
}; | ||
|
||
struct snail_profiler_profile_target_event_view : private extract_view_dynamic_base | ||
{ | ||
static inline constexpr std::string_view event_name = "SnailProf-ProfTarget"; | ||
static inline constexpr std::uint16_t event_version = 0; | ||
static inline constexpr auto event_types = std::array{ | ||
event_identifier_guid{snail_profiler_guid, 1, "ProfTarget"} | ||
}; | ||
|
||
using extract_view_dynamic_base::buffer; | ||
using extract_view_dynamic_base::extract_view_dynamic_base; | ||
|
||
inline auto process_id() const { return extract<std::uint32_t>(dynamic_offset(0, 0)); } | ||
|
||
static inline constexpr std::size_t static_size = 4; | ||
|
||
inline std::size_t dynamic_size() const { return static_size; } | ||
}; | ||
|
||
} // namespace snail::etl::parser |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.