Skip to content

Commit 373f72a

Browse files
authored
Merge pull request #415 from GameTechDev/feature/console-hybrid-present-tracking
Adding hybrid present tracking to PresentMon console application
2 parents 8a23354 + fc9e317 commit 373f72a

13 files changed

+111
-18
lines changed

IntelPresentMon/Streamer/Streamer.cpp

+1-6
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,7 @@ void Streamer::ProcessPresentEvent(
153153
gpu_telemetry_cap_bits,
154154
std::bitset<static_cast<size_t>(CpuTelemetryCapBits::cpu_telemetry_count)>
155155
cpu_telemetry_cap_bits) {
156-
uint32_t process_id;
157-
if (stream_mode_ == StreamMode::kOfflineEtl) {
158-
process_id = static_cast<uint32_t>(StreamPidOverride::kEtlPid);
159-
} else {
160-
process_id = present_event->ProcessId;
161-
}
156+
uint32_t process_id = present_event->ProcessId;
162157

163158
// Lock the nsm mutex as stop streaming calls can occur at any time
164159
// and destroy the named shared memory during writing of frame data.

PresentData/Debug.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ void VerboseTraceEventImpl(PMTraceConsumer* pmConsumer, EVENT_RECORD* eventRecor
415415
case Present_Stop::Id: PrintEventHeader(hdr, "DXGIPresent_Stop"); break;
416416
case PresentMultiplaneOverlay_Stop::Id: PrintEventHeader(hdr, "DXGIPresentMPO_Stop"); break;
417417
}
418+
if (pmConsumer->mTrackHybridPresent) {
419+
if (hdr.EventDescriptor.Id == ResizeBuffers_Start::Id) { PrintEventHeader(hdr, "DXGIResizeBuffers_Start"); }
420+
if (hdr.EventDescriptor.Id == SwapChain_Start::Id) { PrintEventHeader(hdr, "DXGISwapChain_Start"); }
421+
}
418422
return;
419423
}
420424

PresentData/ETW/Microsoft_Windows_DXGI.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// This file originally generated by etw_list
55
// version: public 1b19f39ddb669f7a700a5d0c16cf079943e996d5
6-
// parameters: --no_event_structs --event=Present::Start --event=Present::Stop --event=PresentMultiplaneOverlay::Start --event=PresentMultiplaneOverlay::Stop --provider=Microsoft-Windows-DXGI
6+
// parameters: --no_event_structs --event=Present::Start --event=Present::Stop --event=PresentMultiplaneOverlay::Start --event=PresentMultiplaneOverlay::Stop --event=SwapChain::Start --event=ResizeBuffers::Start --provider=Microsoft-Windows-DXGI
77
#pragma once
88

99
namespace Microsoft_Windows_DXGI {
@@ -43,6 +43,8 @@ EVENT_DESCRIPTOR_DECL(PresentMultiplaneOverlay_Start, 0x0037, 0x00, 0x10, 0x00,
4343
EVENT_DESCRIPTOR_DECL(PresentMultiplaneOverlay_Stop , 0x0038, 0x00, 0x10, 0x00, 0x02, 0x000e, 0x8000000000000002)
4444
EVENT_DESCRIPTOR_DECL(Present_Start , 0x002a, 0x00, 0x10, 0x00, 0x01, 0x0009, 0x8000000000000002)
4545
EVENT_DESCRIPTOR_DECL(Present_Stop , 0x002b, 0x00, 0x10, 0x00, 0x02, 0x0009, 0x8000000000000002)
46+
EVENT_DESCRIPTOR_DECL(ResizeBuffers_Start , 0x002d, 0x00, 0x10, 0x00, 0x01, 0x0005, 0x8000000000000002);
47+
EVENT_DESCRIPTOR_DECL(SwapChain_Start , 0x000a, 0x00, 0x10, 0x00, 0x01, 0x0002, 0x8000000000000001);
4648

4749
#undef EVENT_DESCRIPTOR_DECL
4850

@@ -56,4 +58,10 @@ enum class DXGIPresentFlags : uint32_t {
5658
DXGI_PRESENT_RESTRICT_TO_OUTPUT = 64,
5759
};
5860

61+
enum class HybridPresentMode : uint32_t {
62+
NOT_HYBRID = 0,
63+
TWO_COPY_PATH = 1,
64+
ONE_COPY_PATH_CASO = 2,
65+
};
66+
5967
}

PresentData/PresentMonTraceConsumer.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ PresentEvent::PresentEvent()
151151
, IsCompleted(false)
152152
, IsLost(false)
153153
, PresentFailed(false)
154+
, IsHybridPresent(false)
154155
, PresentInDwmWaitingStruct(false)
155156

156157
, WaitingForPresentStop(false)
@@ -292,6 +293,27 @@ void PMTraceConsumer::HandleDXGIEvent(EVENT_RECORD* pEventRecord)
292293
RuntimePresentStop(Runtime::DXGI, hdr, mMetadata.GetEventData<uint32_t>(pEventRecord, L"Result"));
293294
}
294295
break;
296+
case Microsoft_Windows_DXGI::SwapChain_Start::Id:
297+
case Microsoft_Windows_DXGI::ResizeBuffers_Start::Id:
298+
if (mTrackHybridPresent) {
299+
if (IsProcessTrackedForFiltering(hdr.ProcessId)) {
300+
EventDataDesc desc[] = {
301+
{ L"pIDXGISwapChain" },
302+
{ L"HybridPresentMode" },
303+
};
304+
// Check to see if the event has both the pIDXGISwapChain and HybridPresentMode
305+
// fields. If not do not process.
306+
uint32_t descCount = _countof(desc);
307+
mMetadata.GetEventData(pEventRecord, desc, &descCount);
308+
if (descCount == _countof(desc)) {
309+
auto pSwapChain = desc[0].GetData<uint64_t>();
310+
auto hybridPresentMode = desc[1].GetData<uint32_t>();
311+
auto key = std::make_pair(hdr.ProcessId, pSwapChain);
312+
mHybridPresentModeBySwapChainPid[key] = hybridPresentMode;
313+
}
314+
}
315+
}
316+
break;
295317
default:
296318
assert(!mFilteredEvents); // Assert that filtering is working if expected
297319
break;
@@ -2396,6 +2418,18 @@ void PMTraceConsumer::RuntimePresentStop(Runtime runtime, EVENT_HEADER const& hd
23962418
}
23972419
}
23982420

2421+
if (mTrackHybridPresent) {
2422+
// Determine if this is a hybrid present
2423+
auto key = std::make_pair(present->ProcessId, present->SwapChainAddress);
2424+
auto swapIter = mHybridPresentModeBySwapChainPid.find(key);
2425+
if (swapIter != mHybridPresentModeBySwapChainPid.end()) {
2426+
Microsoft_Windows_DXGI::HybridPresentMode hybridPresentMode = (Microsoft_Windows_DXGI::HybridPresentMode)swapIter->second;
2427+
if (hybridPresentMode != Microsoft_Windows_DXGI::HybridPresentMode::NOT_HYBRID) {
2428+
present->IsHybridPresent = true;
2429+
}
2430+
}
2431+
}
2432+
23992433
// Set the runtime and Present_Stop time.
24002434
VerboseTraceBeforeModifyingPresent(present.get());
24012435
present->Runtime = runtime;

PresentData/PresentMonTraceConsumer.hpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "Debug.hpp"
2525
#include "GpuTrace.hpp"
2626
#include "TraceConsumer.hpp"
27+
#include "../IntelPresentMon/CommonUtilities/Hash.h"
2728

2829
// PresentMode represents the different paths a present can take on windows.
2930
//
@@ -249,6 +250,7 @@ struct PresentEvent {
249250
bool IsLost; // This PresentEvent was found in an unexpected state and analysis could not continue (potentially
250251
// due to missing a critical ETW event'.
251252
bool PresentFailed; // The Present() call failed.
253+
bool IsHybridPresent; // This present is a hybrid present and is performing a cross adapter copy.
252254

253255
bool PresentInDwmWaitingStruct; // Whether this PresentEvent is currently stored in
254256
// PMTraceConsumer::mPresentsWaitingForDWM
@@ -293,6 +295,7 @@ struct PMTraceConsumer
293295
bool mTrackFrameType = false; // ... the frame type communicated through the Intel-PresentMon provider.
294296
bool mTrackPMMeasurements = false; // ... external measurements provided through the Intel-PresentMon provider
295297
bool mTrackAppTiming = false; // ... app timing data communicated through the Intel-PresentMon provider.
298+
bool mTrackHybridPresent = false; // ... hybrid presents.
296299

297300
// When PresentEvents are missing data that may still arrive later, they get put into a deferred
298301
// state until the data arrives. This time limit specifies how long a PresentEvent can be
@@ -423,12 +426,15 @@ struct PMTraceConsumer
423426
std::size_t operator()(Win32KPresentHistoryToken const& v) const noexcept;
424427
};
425428

426-
// Custom hash function for std::pair<uint32_t, uint32_t>
429+
template <typename T, typename U>
427430
struct PairHash {
428-
std::size_t operator()(const std::pair<uint32_t, uint32_t>& p) const noexcept {
429-
return std::hash<uint32_t>{}(p.first) ^ (std::hash<uint32_t>{}(p.second) << 1);
431+
size_t operator()(const std::pair<T, U>& p) const noexcept
432+
{
433+
using namespace pmon::util::hash;
434+
return DualHash(p.first, p.second);
430435
}
431436
};
437+
432438
std::unordered_map<uint32_t, std::shared_ptr<PresentEvent>> mPresentByThreadId; // ThreadId -> PresentEvent
433439
std::unordered_map<uint32_t, OrderedPresents> mOrderedPresentsByProcessId; // ProcessId -> ordered PresentStartTime -> PresentEvent
434440
std::unordered_map<uint32_t, std::unordered_map<uint64_t, std::shared_ptr<PresentEvent>>>
@@ -442,10 +448,15 @@ struct PMTraceConsumer
442448
std::unordered_map<uint64_t, std::shared_ptr<PresentEvent>> mLastPresentByWindow; // HWND -> PresentEvent
443449
std::unordered_map<uint64_t, MouseClickData> mReceivedMouseClickByHwnd; // HWND -> MouseClickData
444450
std::unordered_map<std::pair<uint32_t, uint32_t>,
445-
std::shared_ptr<PresentEvent>, PairHash> mPresentByAppFrameId; // Intel provider app frame id -> PresentEvent
451+
std::shared_ptr<PresentEvent>,
452+
PairHash<uint32_t, uint32_t>> mPresentByAppFrameId; // Intel provider app frame id -> PresentEvent
446453
std::unordered_map<uint32_t, uint32_t> mNextAppFrameIdByProcessid; // ProcessId -> Next Intel provider app frame id
447454
std::unordered_map<std::pair<uint32_t, uint32_t>,
448-
AppTimingData, PairHash> mPendingAppTimingDataByAppFrameId; // Intel provider app frame id -> AppTimingData
455+
AppTimingData,
456+
PairHash<uint32_t, uint32_t>> mPendingAppTimingDataByAppFrameId; // Intel provider app frame id -> AppTimingData
457+
std::unordered_map<std::pair<uint32_t, uint64_t>,
458+
uint32_t,
459+
PairHash<uint32_t, uint64_t>> mHybridPresentModeBySwapChainPid; // SwapChain and process id -> HybridPresentMode
449460

450461
// mGpuTrace tracks work executed on the GPU.
451462
GpuTrace mGpuTrace;

PresentData/PresentMonTraceSession.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,10 @@ ULONG EnableProvidersListing(
729729
provider.AddEvent<Microsoft_Windows_DXGI::Present_Stop>();
730730
provider.AddEvent<Microsoft_Windows_DXGI::PresentMultiplaneOverlay_Start>();
731731
provider.AddEvent<Microsoft_Windows_DXGI::PresentMultiplaneOverlay_Stop>();
732+
if (pmConsumer->mTrackHybridPresent) {
733+
provider.AddEvent<Microsoft_Windows_DXGI::SwapChain_Start>();
734+
provider.AddEvent<Microsoft_Windows_DXGI::ResizeBuffers_Start>();
735+
}
732736
status = provider.Enable(sessionHandle, Microsoft_Windows_DXGI::GUID);
733737
if (status != ERROR_SUCCESS) return status;
734738

PresentData/TraceConsumer.cpp

+21-4
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,24 @@ void EventMetadata::AddMetadata(EVENT_RECORD* eventRecord)
187187
// If the metadata isn't found look it up using TDH. Then, look up each
188188
// property in the metadata to obtain it's data pointer and size.
189189
void EventMetadata::GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc, uint32_t descCount, uint32_t optionalCount /*=0*/)
190+
{
191+
[[maybe_unused]] auto foundCount = GetEventDataWithCount(eventRecord, desc, descCount);
192+
assert(foundCount >= descCount - optionalCount);
193+
(void)optionalCount;
194+
}
195+
196+
// Some events have been evolving over time but not incrementing the version number. As an example DXGI::SwapChain::Start.
197+
// Use this version of GetEventData when a data param might be available based on the version of the event
198+
// being processed. Be sure to check the returned event cound to ensure the expected number of descriptions have
199+
// been found.
200+
void EventMetadata::GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc, uint32_t* descCount)
201+
{
202+
auto foundCount = GetEventDataWithCount(eventRecord, desc, *descCount);
203+
*descCount = foundCount;
204+
return;
205+
}
206+
207+
uint32_t EventMetadata::GetEventDataWithCount(EVENT_RECORD* eventRecord, EventDataDesc* desc, uint32_t descCount)
190208
{
191209
// Look up stored metadata. If not found, look up metadata using TDH and
192210
// cache it for future events.
@@ -207,7 +225,7 @@ void EventMetadata::GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc,
207225
ii = metadata_.emplace(key, std::vector<uint8_t>(sizeof(TRACE_EVENT_INFO), 0)).first;
208226
assert(false);
209227
}
210-
}
228+
}
211229

212230
auto tei = (TRACE_EVENT_INFO*) ii->second.data();
213231

@@ -235,7 +253,7 @@ void EventMetadata::GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc,
235253

236254
foundCount += 1;
237255
if (foundCount == descCount) {
238-
return;
256+
return foundCount;
239257
}
240258
}
241259
}
@@ -244,8 +262,7 @@ void EventMetadata::GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc,
244262
offset += info.size_ * info.count_;
245263
}
246264

247-
assert(foundCount >= descCount - optionalCount);
248-
(void) optionalCount;
265+
return foundCount;
249266
}
250267

251268
namespace {

PresentData/TraceConsumer.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,15 @@ struct EventMetadata {
7171

7272
void AddMetadata(EVENT_RECORD* eventRecord);
7373
void GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc, uint32_t descCount, uint32_t optionalCount=0);
74+
void GetEventData(EVENT_RECORD* eventRecord, EventDataDesc* desc, uint32_t* descCount);
7475

7576
template<typename T> T GetEventData(EVENT_RECORD* eventRecord, wchar_t const* name)
7677
{
7778
EventDataDesc desc = { name };
7879
GetEventData(eventRecord, &desc, 1);
7980
return desc.GetData<T>();
8081
}
82+
83+
private:
84+
uint32_t GetEventDataWithCount(EVENT_RECORD* eventRecord, EventDataDesc* desc, uint32_t descCount);
8185
};

PresentMon/CommandLine.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ void PrintUsage()
296296
LR"(--Beta Options)", nullptr,
297297
LR"(--track_frame_type)", LR"(Track the type of each displayed frame; requires application and/or driver instrumentation using Intel-PresentMon provider.)",
298298
LR"(--track_hw_measurements)", LR"(Tracks HW-measured latency and/or power data coming from a LMT and/or PCAT device.)",
299-
LR"(--track_app_timing)", LR"(Track app timines for each displayed frame; requires application and/or driver instrumentation using Intel-PresentMon provider.)",
299+
LR"(--track_app_timing)", LR"(Track app times for each displayed frame; requires application and/or driver instrumentation using Intel-PresentMon provider.)",
300+
LR"(--track_hybrid_present)", LR"(Tracks if the present is a hybrid present and is performing a cross adapter copy.)",
300301
};
301302

302303
// Layout
@@ -390,6 +391,7 @@ bool ParseCommandLine(int argc, wchar_t** argv)
390391
args->mTrackFrameType = false;
391392
args->mTrackPMMeasurements = false;
392393
args->mTrackAppTiming = false;
394+
args->mTrackHybridPresent = false;
393395
args->mScrollLockIndicator = false;
394396
args->mExcludeDropped = false;
395397
args->mTerminateExistingSession = false;
@@ -459,7 +461,8 @@ bool ParseCommandLine(int argc, wchar_t** argv)
459461
// Beta options:
460462
else if (ParseArg(argv[i], L"track_frame_type")) { args->mTrackFrameType = true; continue; }
461463
else if (ParseArg(argv[i], L"track_hw_measurements")) { args->mTrackPMMeasurements = true; continue; }
462-
else if (ParseArg(argv[i], L"track_app_timing")) { args->mTrackAppTiming = true; continue; }
464+
else if (ParseArg(argv[i], L"track_app_timing")) { args->mTrackAppTiming = true; continue; }
465+
else if (ParseArg(argv[i], L"track_hybrid_present")) { args->mTrackHybridPresent = true; continue; }
463466

464467
// Hidden options:
465468
#if PRESENTMON_ENABLE_DEBUG_TRACE

PresentMon/CsvOutput.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ void WriteCsvHeader<FrameMetrics>(FILE* fp)
281281
if (args.mTrackFrameType) {
282282
fwprintf(fp, L",FrameType");
283283
}
284+
if (args.mTrackHybridPresent) {
285+
fwprintf(fp, L",HybridPresent");
286+
}
284287
switch (args.mTimeUnit) {
285288
case TimeUnit::MilliSeconds: fwprintf(fp, L",CPUStartTime"); break;
286289
case TimeUnit::QPC: fwprintf(fp, L",CPUStartQPC"); break;
@@ -351,6 +354,10 @@ void WriteCsvRow<FrameMetrics>(
351354
if (args.mTrackFrameType) {
352355
fwprintf(fp, L",%hs", FrameTypeToString(metrics.mFrameType));
353356
}
357+
if (args.mTrackHybridPresent) {
358+
fwprintf(fp, L",%d", p.IsHybridPresent);
359+
}
360+
354361
switch (args.mTimeUnit) {
355362
case TimeUnit::MilliSeconds:
356363
fwprintf(fp, L",%.4lf", pmSession.TimestampToMilliSeconds(metrics.mCPUStart));

PresentMon/MainThread.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ int wmain(int argc, wchar_t** argv)
261261
pmConsumer.mTrackFrameType = args.mTrackFrameType;
262262
pmConsumer.mTrackPMMeasurements = args.mTrackPMMeasurements;
263263
pmConsumer.mTrackAppTiming = args.mTrackAppTiming;
264+
pmConsumer.mTrackHybridPresent = args.mTrackHybridPresent;
264265
pmConsumer.mDisableOfflineBackpressure = args.mDisableOfflineBackpressure;
265266
if (args.mTargetPid != 0) {
266267
pmConsumer.mFilteredProcessIds = true;

PresentMon/PresentMon.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct CommandLineArgs {
7575
bool mTrackFrameType;
7676
bool mTrackPMMeasurements;
7777
bool mTrackAppTiming;
78+
bool mTrackHybridPresent;
7879
bool mScrollLockIndicator;
7980
bool mExcludeDropped;
8081
bool mTerminateExistingSession;

PresentMon/PresentMon.vcxproj

+4
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
<Optimization>Disabled</Optimization>
128128
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
129129
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
130+
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard>
130131
</ClCompile>
131132
</ItemDefinitionGroup>
132133
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
@@ -136,6 +137,7 @@
136137
<IntrinsicFunctions>true</IntrinsicFunctions>
137138
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
138139
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
140+
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpp17</LanguageStandard>
139141
</ClCompile>
140142
<Link>
141143
<EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -145,6 +147,8 @@
145147
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
146148
<ClCompile>
147149
<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
150+
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">stdcpp17</LanguageStandard>
151+
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">stdcpp17</LanguageStandard>
148152
</ClCompile>
149153
</ItemDefinitionGroup>
150154
<ItemDefinitionGroup Condition="'$(Platform)'=='ARM'">

0 commit comments

Comments
 (0)