Skip to content

Commit 065d36d

Browse files
Merge pull request #347 from GameTechDev/feature/input_update
Feature/input update
2 parents 5c048b2 + 32d92af commit 065d36d

37 files changed

+2670
-945
lines changed

IntelPresentMon/Core/source/pmon/RawFrameDataMetricList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace p2c::pmon
4141
Element{.metricId = PM_METRIC_DISPLAY_LATENCY, .deviceId = 0 },
4242
Element{.metricId = PM_METRIC_DISPLAYED_TIME, .deviceId = 0 },
4343
Element{.metricId = PM_METRIC_ANIMATION_ERROR, .deviceId = 0 },
44+
Element{.metricId = PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, .deviceId = 0 },
4445
Element{.metricId = PM_METRIC_CLICK_TO_PHOTON_LATENCY, .deviceId = 0 },
4546

4647
Element{.metricId = PM_METRIC_GPU_POWER, .deviceId = activeDeviceId },

IntelPresentMon/Core/source/pmon/RawFrameDataWriter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ namespace p2c::pmon
136136
if (metricId == PM_METRIC_DISPLAYED_TIME ||
137137
metricId == PM_METRIC_DISPLAY_LATENCY ||
138138
metricId == PM_METRIC_ANIMATION_ERROR ||
139-
metricId == PM_METRIC_CLICK_TO_PHOTON_LATENCY) {
139+
metricId == PM_METRIC_CLICK_TO_PHOTON_LATENCY ||
140+
metricId == PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY) {
140141
flags |= Annotation_::FLAG_NAN_MEANS_NOT_AVAILABLE;
141142
}
142143

IntelPresentMon/Interprocess/source/metadata/MetricList.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,5 @@
8383
X_(PM_METRIC_CPU_POWER, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_WATTS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_GRAPHICS_ADAPTER, FULL_STATS) \
8484
X_(PM_METRIC_CPU_TEMPERATURE, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_CELSIUS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_GRAPHICS_ADAPTER, FULL_STATS) \
8585
X_(PM_METRIC_CPU_FREQUENCY, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MEGAHERTZ, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_GRAPHICS_ADAPTER, FULL_STATS) \
86-
X_(PM_METRIC_CPU_CORE_UTILITY, PM_METRIC_TYPE_DYNAMIC, PM_UNIT_PERCENT, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_VOID, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS)
86+
X_(PM_METRIC_CPU_CORE_UTILITY, PM_METRIC_TYPE_DYNAMIC, PM_UNIT_PERCENT, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_VOID, 0, PM_DEVICE_TYPE_INDEPENDENT, FULL_STATS) \
87+
X_(PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, PM_METRIC_TYPE_DYNAMIC_FRAME, PM_UNIT_MILLISECONDS, PM_DATA_TYPE_DOUBLE, PM_DATA_TYPE_DOUBLE, 0, PM_DEVICE_TYPE_INDEPENDENT, PM_STAT_NON_ZERO_AVG, PM_STAT_PERCENTILE_01, PM_STAT_PERCENTILE_05, PM_STAT_PERCENTILE_10, PM_STAT_MAX)

IntelPresentMon/PresentMonAPI2/PresentMonAPI.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ extern "C" {
113113
PM_METRIC_APPLICATION_FPS,
114114
PM_METRIC_FRAME_TYPE,
115115
PM_METRIC_ANIMATION_ERROR,
116+
117+
PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY,
116118
};
117119

118120
enum PM_METRIC_TYPE

IntelPresentMon/PresentMonAPI2Tests/CsvHelper.h

Lines changed: 80 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ enum Header {
4141
Header_DisplayedTime,
4242
Header_AnimationError,
4343
Header_ClickToPhotonLatency,
44+
Header_AllInputToPhotonLatency,
4445

4546
// --v1_metrics
4647
Header_Runtime,
@@ -88,54 +89,56 @@ struct v2Metrics {
8889
std::optional<double> displayedTime;
8990
std::optional<double> animationError;
9091
std::optional<double> clickToPhotonLatency;
92+
std::optional<double> AllInputToPhotonLatency;
9193
};
9294

9395
constexpr char const* GetHeaderString(Header h)
9496
{
9597
switch (h) {
96-
case Header_Application: return "Application";
97-
case Header_ProcessID: return "ProcessID";
98-
case Header_SwapChainAddress: return "SwapChainAddress";
99-
case Header_PresentRuntime: return "PresentRuntime";
100-
case Header_SyncInterval: return "SyncInterval";
101-
case Header_PresentFlags: return "PresentFlags";
102-
case Header_AllowsTearing: return "AllowsTearing";
103-
case Header_PresentMode: return "PresentMode";
104-
case Header_FrameType: return "FrameType";
105-
case Header_CPUStartTime: return "CPUStartTime";
106-
case Header_CPUStartQPC: return "CPUStartQPC";
107-
case Header_CPUStartQPCTime: return "CPUStartQPCTime";
108-
case Header_CPUStartDateTime: return "CPUStartDateTime";
109-
case Header_FrameTime: return "FrameTime";
110-
case Header_CPUBusy: return "CPUBusy";
111-
case Header_CPUWait: return "CPUWait";
112-
case Header_GPULatency: return "GPULatency";
113-
case Header_GPUTime: return "GPUTime";
114-
case Header_GPUBusy: return "GPUBusy";
115-
case Header_VideoBusy: return "VideoBusy";
116-
case Header_GPUWait: return "GPUWait";
117-
case Header_DisplayLatency: return "DisplayLatency";
118-
case Header_DisplayedTime: return "DisplayedTime";
119-
case Header_AnimationError: return "AnimationError";
120-
case Header_ClickToPhotonLatency: return "ClickToPhotonLatency";
121-
122-
case Header_Runtime: return "Runtime";
123-
case Header_Dropped: return "Dropped";
124-
case Header_TimeInSeconds: return "TimeInSeconds";
125-
case Header_msBetweenPresents: return "msBetweenPresents";
126-
case Header_msInPresentAPI: return "msInPresentAPI";
127-
case Header_msBetweenDisplayChange: return "msBetweenDisplayChange";
128-
case Header_msUntilRenderComplete: return "msUntilRenderComplete";
129-
case Header_msUntilDisplayed: return "msUntilDisplayed";
130-
case Header_msUntilRenderStart: return "msUntilRenderStart";
131-
case Header_msGPUActive: return "msGPUActive";
132-
case Header_msGPUVideoActive: return "msGPUVideoActive";
133-
case Header_msSinceInput: return "msSinceInput";
134-
case Header_QPCTime: return "QPCTime";
135-
136-
case Header_WasBatched: return "WasBatched";
137-
case Header_DwmNotified: return "DwmNotified";
138-
default: return "<unknown>";
98+
case Header_Application: return "Application";
99+
case Header_ProcessID: return "ProcessID";
100+
case Header_SwapChainAddress: return "SwapChainAddress";
101+
case Header_PresentRuntime: return "PresentRuntime";
102+
case Header_SyncInterval: return "SyncInterval";
103+
case Header_PresentFlags: return "PresentFlags";
104+
case Header_AllowsTearing: return "AllowsTearing";
105+
case Header_PresentMode: return "PresentMode";
106+
case Header_FrameType: return "FrameType";
107+
case Header_CPUStartTime: return "CPUStartTime";
108+
case Header_CPUStartQPC: return "CPUStartQPC";
109+
case Header_CPUStartQPCTime: return "CPUStartQPCTime";
110+
case Header_CPUStartDateTime: return "CPUStartDateTime";
111+
case Header_FrameTime: return "FrameTime";
112+
case Header_CPUBusy: return "CPUBusy";
113+
case Header_CPUWait: return "CPUWait";
114+
case Header_GPULatency: return "GPULatency";
115+
case Header_GPUTime: return "GPUTime";
116+
case Header_GPUBusy: return "GPUBusy";
117+
case Header_VideoBusy: return "VideoBusy";
118+
case Header_GPUWait: return "GPUWait";
119+
case Header_DisplayLatency: return "DisplayLatency";
120+
case Header_DisplayedTime: return "DisplayedTime";
121+
case Header_AnimationError: return "AnimationError";
122+
case Header_ClickToPhotonLatency: return "ClickToPhotonLatency";
123+
case Header_AllInputToPhotonLatency: return "AllInputToPhotonLatency";
124+
125+
case Header_Runtime: return "Runtime";
126+
case Header_Dropped: return "Dropped";
127+
case Header_TimeInSeconds: return "TimeInSeconds";
128+
case Header_msBetweenPresents: return "msBetweenPresents";
129+
case Header_msInPresentAPI: return "msInPresentAPI";
130+
case Header_msBetweenDisplayChange: return "msBetweenDisplayChange";
131+
case Header_msUntilRenderComplete: return "msUntilRenderComplete";
132+
case Header_msUntilDisplayed: return "msUntilDisplayed";
133+
case Header_msUntilRenderStart: return "msUntilRenderStart";
134+
case Header_msGPUActive: return "msGPUActive";
135+
case Header_msGPUVideoActive: return "msGPUVideoActive";
136+
case Header_msSinceInput: return "msSinceInput";
137+
case Header_QPCTime: return "QPCTime";
138+
139+
case Header_WasBatched: return "WasBatched";
140+
case Header_DwmNotified: return "DwmNotified";
141+
default: return "<unknown>";
139142
}
140143
}
141144

@@ -294,7 +297,7 @@ class CsvParser {
294297
bool Open(std::wstring const& path, uint32_t processId);
295298
void Close();
296299
bool VerifyBlobAgainstCsv(const std::string& processName, const unsigned int& processId,
297-
PM_QUERY_ELEMENT(&queryElements)[18], pmapi::BlobContainer& blobs);
300+
PM_QUERY_ELEMENT(&queryElements)[19], pmapi::BlobContainer& blobs);
298301
bool ResetCsv();
299302

300303
private:
@@ -323,7 +326,7 @@ CsvParser::CsvParser()
323326
{}
324327

325328
bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsigned int& processId,
326-
PM_QUERY_ELEMENT(&queryElements)[18], pmapi::BlobContainer& blobs)
329+
PM_QUERY_ELEMENT(&queryElements)[19], pmapi::BlobContainer& blobs)
327330
{
328331

329332
for (auto pBlob : blobs) {
@@ -346,7 +349,8 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
346349
const auto displayLatency = *reinterpret_cast<const double*>(&pBlob[queryElements[14].dataOffset]);
347350
const auto displayedTime = *reinterpret_cast<const double*>(&pBlob[queryElements[15].dataOffset]);
348351
const auto animationError = *reinterpret_cast<const double*>(&pBlob[queryElements[16].dataOffset]);
349-
const auto clickToPhotonLatency = *reinterpret_cast<const double*>(&pBlob[queryElements[17].dataOffset]);
352+
const auto allInputToPhotonLatency = *reinterpret_cast<const double*>(&pBlob[queryElements[17].dataOffset]);
353+
const auto clickToPhotonLatency = *reinterpret_cast<const double*>(&pBlob[queryElements[18].dataOffset]);
350354

351355
// Read rows until we find one with the process we are interested in
352356
// or we are out of data.
@@ -479,6 +483,21 @@ bool CsvParser::VerifyBlobAgainstCsv(const std::string& processName, const unsig
479483
}
480484
}
481485
break;
486+
case Header_AllInputToPhotonLatency:
487+
if (v2MetricRow_.AllInputToPhotonLatency.has_value()) {
488+
columnsMatch = Validate(v2MetricRow_.AllInputToPhotonLatency.value(), allInputToPhotonLatency);
489+
}
490+
else
491+
{
492+
if (std::isnan(allInputToPhotonLatency)) {
493+
columnsMatch = true;
494+
}
495+
else
496+
{
497+
columnsMatch = false;
498+
}
499+
}
500+
break;
482501
default:
483502
columnsMatch = true;
484503
break;
@@ -590,7 +609,8 @@ bool CsvParser::Open(std::wstring const& path, uint32_t processId) {
590609
Header_DisplayLatency,
591610
Header_DisplayedTime,
592611
Header_AnimationError,
593-
Header_ClickToPhotonLatency, });
612+
Header_ClickToPhotonLatency,
613+
Header_AllInputToPhotonLatency});
594614

595615
if (!columnsOK) {
596616
Assert::Fail(L"Missing required columns");
@@ -784,6 +804,19 @@ void CsvParser::ConvertToMetricDataType(const char* data, Header columnId)
784804
}
785805
}
786806
break;
807+
case Header_AllInputToPhotonLatency:
808+
{
809+
if (strncmp(data, "NA", 2) != 0) {
810+
double convertedData = 0.;
811+
CharConvert<double> converter;
812+
converter.Convert(data, convertedData, columnId, line_);
813+
v2MetricRow_.AllInputToPhotonLatency = convertedData;
814+
}
815+
else {
816+
v2MetricRow_.AllInputToPhotonLatency.reset();
817+
}
818+
}
819+
break;
787820
default:
788821
Assert::Fail(CreateErrorString(UnknownHeader, line_).c_str());
789822
}

IntelPresentMon/PresentMonAPI2Tests/EtlTests.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ namespace EtlTests
6262
"SyncInterval,PresentFlags,AllowsTearing,PresentMode,"
6363
"CPUStartQPC,CPUBusy,CPUWait,"
6464
"GPULatency,GPUBusy,GPUWait,VideoBusy,DisplayLatency,"
65-
"DisplayedTime,ClickToPhotonLatency";
65+
"DisplayedTime,AllInputToPhotonLatency,ClickToPhotonLatency";
6666
csvFile << std::endl;
6767
return csvFile;
6868
}
@@ -159,6 +159,7 @@ namespace EtlTests
159159
{ PM_METRIC_DISPLAY_LATENCY, PM_STAT_NONE, 0, 0 },
160160
{ PM_METRIC_DISPLAYED_TIME, PM_STAT_NONE, 0, 0 },
161161
{ PM_METRIC_ANIMATION_ERROR, PM_STAT_NONE, 0, 0 },
162+
{ PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0},
162163
{ PM_METRIC_CLICK_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0}
163164
};
164165

@@ -380,6 +381,7 @@ namespace EtlTests
380381
{ PM_METRIC_GPU_WAIT, PM_STAT_NONE, 0, 0},
381382
{ PM_METRIC_DISPLAY_LATENCY, PM_STAT_NONE, 0, 0 },
382383
{ PM_METRIC_DISPLAYED_TIME, PM_STAT_NONE, 0, 0 },
384+
{ PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0},
383385
{ PM_METRIC_CLICK_TO_PHOTON_LATENCY, PM_STAT_NONE, 0, 0}
384386
};
385387

@@ -1605,6 +1607,52 @@ namespace EtlTests
16051607
}
16061608
}
16071609

1610+
RunTestCaseV2(std::move(pSession), processId, processName, goldCsvFile);
1611+
goldCsvFile.Close();
1612+
}
1613+
TEST_METHOD(Tc5v2PresentBench24892)
1614+
{
1615+
namespace bp = boost::process;
1616+
using namespace std::string_literals;
1617+
using namespace std::chrono_literals;
1618+
1619+
const uint32_t processId = 24892;
1620+
const std::string processName = "PresentBench.exe";
1621+
1622+
bp::ipstream out; // Stream for reading the process's output
1623+
bp::opstream in; // Stream for writing to the process's input
1624+
1625+
const auto pipeName = R"(\\.\pipe\test-pipe-pmsvc-2)"s;
1626+
const auto introName = "PM_intro_test_nsm_2"s;
1627+
const auto etlName = "..\\..\\tests\\gold\\test_case_5.etl";
1628+
const auto goldCsvName = L"..\\..\\tests\\gold\\test_case_5.csv";
1629+
1630+
CsvParser goldCsvFile;
1631+
goldCsvFile.Open(goldCsvName, processId);
1632+
1633+
oChild.emplace("PresentMonService.exe"s,
1634+
"--timed-stop"s, "10000"s,
1635+
"--control-pipe"s, pipeName,
1636+
"--nsm-prefix"s, "pmon_nsm_utest_"s,
1637+
"--intro-nsm"s, introName,
1638+
"--etl-test-file"s, etlName,
1639+
bp::std_out > out, bp::std_in < in);
1640+
1641+
std::this_thread::sleep_for(1000ms);
1642+
1643+
std::unique_ptr<pmapi::Session> pSession;
1644+
{
1645+
try
1646+
{
1647+
pSession = std::make_unique<pmapi::Session>(pipeName.c_str(), introName.c_str());
1648+
}
1649+
catch (const std::exception& e) {
1650+
std::cout << "Error: " << e.what() << std::endl;
1651+
Assert::AreEqual(false, true, L"*** Connecting to service via named pipe");
1652+
return;
1653+
}
1654+
}
1655+
16081656
RunTestCaseV2(std::move(pSession), processId, processName, goldCsvFile);
16091657
goldCsvFile.Close();
16101658
}

IntelPresentMon/PresentMonMiddleware/ConcreteMiddleware.cpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ namespace pmon::mid
291291
case PM_METRIC_DISPLAYED_FPS:
292292
case PM_METRIC_DROPPED_FRAMES:
293293
case PM_METRIC_CLICK_TO_PHOTON_LATENCY:
294+
case PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY:
294295
pQuery->accumFpsData = true;
295296
break;
296297
case PM_METRIC_GPU_POWER:
@@ -468,8 +469,9 @@ struct FrameMetrics {
468469
double mGPUWait;
469470
double mDisplayLatency;
470471
double mDisplayedTime;
471-
double mClickToPhotonLatency;
472472
double mAnimationError;
473+
double mClickToPhotonLatency;
474+
double mAllInputPhotonLatency;
473475
};
474476

475477
// Copied from: PresentMon/OutputThread.cpp
@@ -564,12 +566,34 @@ void ReportMetrics(
564566
metrics.mDisplayedTime = pmSession.TimestampDeltaToUnsignedMilliSeconds(p->ScreenTime, nextDisplayedPresent->ScreenTime);
565567
metrics.mAnimationError = chain->mLastDisplayedCPUStart == 0 ? 0 : pmSession.TimestampDeltaToMilliSeconds(p->ScreenTime - chain->display_n_screen_time,
566568
metrics.mCPUStart - chain->mLastDisplayedCPUStart);
567-
metrics.mClickToPhotonLatency = p->InputTime == 0 ? 0.0 : pmSession.TimestampDeltaToUnsignedMilliSeconds(p->InputTime, p->ScreenTime);
569+
// If we have an input time that was associated with a dropped frame calculate the latency
570+
// based on this Presents screen time.
571+
auto updatedInputTime = chain->mLastReceivedNotDisplayedAllInputTime == 0 ? 0 :
572+
pmSession.TimestampDeltaToUnsignedMilliSeconds(chain->mLastReceivedNotDisplayedAllInputTime, p->ScreenTime);
573+
// If this present doesn't have an input associated with it use the time from the latest input time calculated
574+
// above. If there is an input associated with the Present use it.
575+
metrics.mAllInputPhotonLatency = p->InputTime == 0 ? updatedInputTime :
576+
pmSession.TimestampDeltaToUnsignedMilliSeconds(p->InputTime, p->ScreenTime);
577+
// Do the same for the mouse click input
578+
updatedInputTime = chain->mLastReceivedNotDisplayedMouseClickTime == 0 ? 0 :
579+
pmSession.TimestampDeltaToUnsignedMilliSeconds(chain->mLastReceivedNotDisplayedMouseClickTime, p->ScreenTime);
580+
metrics.mClickToPhotonLatency = p->MouseClickTime == 0 ? updatedInputTime :
581+
pmSession.TimestampDeltaToUnsignedMilliSeconds(p->MouseClickTime, p->ScreenTime);
582+
583+
chain->mLastReceivedNotDisplayedAllInputTime = 0;
584+
chain->mLastReceivedNotDisplayedMouseClickTime = 0;
568585
} else {
569586
metrics.mDisplayLatency = 0.0;
570587
metrics.mDisplayedTime = 0.0;
571588
metrics.mAnimationError = 0.0;
572589
metrics.mClickToPhotonLatency = 0.0;
590+
metrics.mAllInputPhotonLatency = 0.0;
591+
if (p->InputTime != 0) {
592+
chain->mLastReceivedNotDisplayedAllInputTime = p->InputTime;
593+
}
594+
if (p->MouseClickTime != 0) {
595+
chain->mLastReceivedNotDisplayedMouseClickTime = p->MouseClickTime;
596+
}
573597
}
574598

575599
if (p->FrameId == nextPresent->FrameId) {
@@ -599,10 +623,14 @@ void ReportMetrics(
599623
chain->mAppDisplayedTime.back() += metrics.mDisplayedTime;
600624
}
601625

602-
if (p->InputTime) {
626+
if (p->MouseClickTime) {
603627
chain->mClickToPhotonLatency.push_back(metrics.mClickToPhotonLatency);
604628
}
605629

630+
if (p->InputTime) {
631+
chain->mAllInputToPhotonLatency.push_back(metrics.mAllInputPhotonLatency);
632+
}
633+
606634
chain->mDisplayLatency.push_back(metrics.mDisplayLatency);
607635
chain->mDisplayedTime .push_back(metrics.mDisplayedTime);
608636
chain->mDropped .push_back(0.0);
@@ -1059,6 +1087,9 @@ void ReportMetrics(
10591087
case PM_METRIC_CLICK_TO_PHOTON_LATENCY:
10601088
output = CalculateStatistic(swapChain.mClickToPhotonLatency, element.stat);
10611089
break;
1090+
case PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY:
1091+
output = CalculateStatistic(swapChain.mAllInputToPhotonLatency, element.stat);
1092+
break;
10621093
default:
10631094
output = 0.;
10641095
break;
@@ -1545,6 +1576,7 @@ void ReportMetrics(
15451576
case PM_METRIC_GPU_BUSY:
15461577
case PM_METRIC_DISPLAY_LATENCY:
15471578
case PM_METRIC_CLICK_TO_PHOTON_LATENCY:
1579+
case PM_METRIC_ALL_INPUT_TO_PHOTON_LATENCY:
15481580
case PM_METRIC_PRESENTED_FPS:
15491581
case PM_METRIC_APPLICATION_FPS:
15501582
case PM_METRIC_DISPLAYED_FPS:

0 commit comments

Comments
 (0)