Skip to content

Commit 0c6b5fc

Browse files
Improve --datetime accuracy
This commit has two changes to improve --datetime: 1) When processing an ETL, use full precision for the trace start time (previously was only using milliseconds). This will result in the same present time for WPA and PresentMon when using --datetime and --etl_file. 2) When collecting in realtime with --datetime, this changes the ETW timestamp from QPC to SYSTEMTIME. This ensures PresentMon's reported present start time will be the correct datetime, however it will not exactly match WPA. WPA converts QPC into datetimes, but PresentMon cannot match that during realtime collection without using the same trace start time, which I can't find a way to query. See issue #194
1 parent f2a1f61 commit 0c6b5fc

8 files changed

+97
-83
lines changed

PresentData/TraceSession.cpp

+25-20
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ void CALLBACK EventRecordCallback(EVENT_RECORD* pEventRecord)
352352
#pragma warning(disable: 4984) // c++17 extension
353353

354354
if constexpr (SAVE_FIRST_TIMESTAMP) {
355-
if (session->mStartQpc.QuadPart == 0) {
356-
session->mStartQpc = hdr.TimeStamp;
355+
if (session->mStartTimestamp.QuadPart == 0) {
356+
session->mStartTimestamp = hdr.TimeStamp;
357357
}
358358
}
359359

@@ -481,18 +481,19 @@ ULONG TraceSession::Start(
481481
PMTraceConsumer* pmConsumer,
482482
MRTraceConsumer* mrConsumer,
483483
wchar_t const* etlPath,
484-
wchar_t const* sessionName)
484+
wchar_t const* sessionName,
485+
TimestampType timestampType)
485486
{
486487
assert(mSessionHandle == 0);
487488
assert(mTraceHandle == INVALID_PROCESSTRACE_HANDLE);
488-
mStartQpc.QuadPart = 0;
489+
mStartTimestamp.QuadPart = 0;
489490
mPMConsumer = pmConsumer;
490491
mMRConsumer = mrConsumer;
491492
mContinueProcessingBuffers = TRUE;
492493

493494
// -------------------------------------------------------------------------
494495
// Configure trace properties
495-
EVENT_TRACE_LOGFILE traceProps = {};
496+
EVENT_TRACE_LOGFILEW traceProps = {};
496497
traceProps.LogFileName = (wchar_t*) etlPath;
497498
traceProps.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
498499
traceProps.Context = this;
@@ -528,7 +529,7 @@ ULONG TraceSession::Start(
528529

529530
TraceProperties sessionProps = {};
530531
sessionProps.Wnode.BufferSize = (ULONG) sizeof(TraceProperties);
531-
sessionProps.Wnode.ClientContext = 1; // Clock resolution to use when logging the timestamp for each event; 1 == query performance counter
532+
sessionProps.Wnode.ClientContext = timestampType; // Clock resolution to use when logging the timestamp for each event
532533
sessionProps.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; // We have a realtime consumer, not writing to a log file
533534
sessionProps.LogFileNameOffset = 0; // 0 means no output log file
534535
sessionProps.LoggerNameOffset = offsetof(TraceProperties, mSessionName); // Location of session name; will be written by StartTrace()
@@ -556,7 +557,7 @@ ULONG TraceSession::Start(
556557
sessionProps.LoggerThreadId // tracing session identifier
557558
*/
558559

559-
auto status = StartTrace(&mSessionHandle, sessionName, &sessionProps);
560+
auto status = StartTraceW(&mSessionHandle, sessionName, &sessionProps);
560561
if (status != ERROR_SUCCESS) {
561562
mSessionHandle = 0;
562563
return status;
@@ -571,7 +572,7 @@ ULONG TraceSession::Start(
571572

572573
// -------------------------------------------------------------------------
573574
// Open the trace
574-
mTraceHandle = OpenTrace(&traceProps);
575+
mTraceHandle = OpenTraceW(&traceProps);
575576
if (mTraceHandle == INVALID_PROCESSTRACE_HANDLE) {
576577
auto lastError = GetLastError();
577578
Stop();
@@ -584,14 +585,15 @@ ULONG TraceSession::Start(
584585
// captures are based off the timestamp here.
585586

586587
switch (traceProps.LogfileHeader.ReservedFlags) {
587-
case 2: // System time
588-
mQpcFrequency.QuadPart = 10000000ull;
588+
case TIMESTAMP_TYPE_SYSTEM_TIME:
589+
mTimestampFrequency.QuadPart = 10000000ull;
589590
break;
590-
case 3: // CPU cycle counter
591-
mQpcFrequency.QuadPart = 1000000ull * traceProps.LogfileHeader.CpuSpeedInMHz;
591+
case TIMESTAMP_TYPE_CPU_CYCLE_COUNTER:
592+
mTimestampFrequency.QuadPart = 1000000ull * traceProps.LogfileHeader.CpuSpeedInMHz;
592593
break;
593-
default: // 1 == QPC
594-
mQpcFrequency = traceProps.LogfileHeader.PerfFreq;
594+
case TIMESTAMP_TYPE_QPC:
595+
default:
596+
mTimestampFrequency = traceProps.LogfileHeader.PerfFreq;
595597
break;
596598
}
597599

@@ -602,17 +604,20 @@ ULONG TraceSession::Start(
602604
QueryPerformanceCounter(&qpc1);
603605
GetSystemTimeAsFileTime(&ft);
604606
QueryPerformanceCounter(&qpc2);
605-
FileTimeToLocalFileTime(&ft, &mStartTime);
606-
mStartQpc.QuadPart = qpc1.QuadPart + (qpc2.QuadPart - qpc1.QuadPart) / 2;
607+
FileTimeToLocalFileTime(&ft, (FILETIME*) &mStartFileTime);
608+
mStartTimestamp.QuadPart = (qpc1.QuadPart + qpc2.QuadPart) / 2;
607609
} else {
608-
SYSTEMTIME ust = {};
609-
SYSTEMTIME lst = {};
610+
// Convert start FILETIME to local start FILETIME
611+
SYSTEMTIME ust{};
612+
SYSTEMTIME lst{};
610613
FileTimeToSystemTime((FILETIME const*) &traceProps.LogfileHeader.StartTime, &ust);
611614
SystemTimeToTzSpecificLocalTime(&traceProps.LogfileHeader.TimeZone, &ust, &lst);
612-
SystemTimeToFileTime(&lst, &mStartTime);
615+
SystemTimeToFileTime(&lst, (FILETIME*) &mStartFileTime);
616+
// The above conversion stops at milliseconds, so copy the rest over too
617+
mStartFileTime += traceProps.LogfileHeader.StartTime.QuadPart % 10000;
613618
}
614619

615-
InitializeTimestampInfo(&mStartQpc, mQpcFrequency);
620+
InitializeTimestampInfo(&mStartTimestamp, mTimestampFrequency);
616621

617622
return ERROR_SUCCESS;
618623
}

PresentData/TraceSession.hpp

+14-7
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,27 @@ struct PMTraceConsumer;
55
struct MRTraceConsumer;
66

77
struct TraceSession {
8-
LARGE_INTEGER mStartQpc = {};
9-
LARGE_INTEGER mQpcFrequency = {};
10-
FILETIME mStartTime = {};
8+
LARGE_INTEGER mStartTimestamp = {};
9+
LARGE_INTEGER mTimestampFrequency = {};
10+
uint64_t mStartFileTime = 0;
1111
PMTraceConsumer* mPMConsumer = nullptr;
1212
MRTraceConsumer* mMRConsumer = nullptr;
1313
TRACEHANDLE mSessionHandle = 0; // invalid session handles are 0
1414
TRACEHANDLE mTraceHandle = INVALID_PROCESSTRACE_HANDLE; // invalid trace handles are INVALID_PROCESSTRACE_HANDLE
1515
ULONG mContinueProcessingBuffers = TRUE;
1616

17+
enum TimestampType {
18+
TIMESTAMP_TYPE_QPC = 1,
19+
TIMESTAMP_TYPE_SYSTEM_TIME = 2,
20+
TIMESTAMP_TYPE_CPU_CYCLE_COUNTER = 3,
21+
};
22+
1723
ULONG Start(
18-
PMTraceConsumer* pmConsumer, // Required PMTraceConsumer instance
19-
MRTraceConsumer* mrConsumer, // If nullptr, no WinMR tracing
20-
wchar_t const* etlPath, // If nullptr, live/realtime tracing session
21-
wchar_t const* sessionName); // Required session name
24+
PMTraceConsumer* pmConsumer, // Required PMTraceConsumer instance
25+
MRTraceConsumer* mrConsumer, // If nullptr, no WinMR tracing
26+
wchar_t const* etlPath, // If nullptr, live/realtime tracing session
27+
wchar_t const* sessionName, // Required session name
28+
TimestampType timestampType); // Which timestamp type to use
2229

2330
void Stop();
2431

PresentMon/Console.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ void UpdateConsole(uint32_t processId, ProcessInfo const& processInfo)
266266

267267
auto const& present0 = *chain.mPresentHistory[(chain.mNextPresentIndex - chain.mPresentHistoryCount) % SwapChainData::PRESENT_HISTORY_MAX_COUNT];
268268
auto const& presentN = *chain.mPresentHistory[(chain.mNextPresentIndex - 1) % SwapChainData::PRESENT_HISTORY_MAX_COUNT];
269-
auto cpuAvg = QpcDeltaToSeconds(presentN.PresentStartTime - present0.PresentStartTime) / (chain.mPresentHistoryCount - 1);
269+
auto cpuAvg = TimestampDeltaToSeconds(presentN.PresentStartTime - present0.PresentStartTime) / (chain.mPresentHistoryCount - 1);
270270
auto gpuAvg = 0.0;
271271
auto dspAvg = 0.0;
272272
auto latAvg = 0.0;
@@ -292,14 +292,14 @@ void UpdateConsole(uint32_t processId, ProcessInfo const& processInfo)
292292
}
293293
}
294294

295-
gpuAvg = QpcDeltaToSeconds(gpuSum) / (chain.mPresentHistoryCount - 1);
295+
gpuAvg = TimestampDeltaToSeconds(gpuSum) / (chain.mPresentHistoryCount - 1);
296296

297297
if (displayCount >= 2) {
298-
dspAvg = QpcDeltaToSeconds(displayN->ScreenTime - display0ScreenTime) / (displayCount - 1);
298+
dspAvg = TimestampDeltaToSeconds(displayN->ScreenTime - display0ScreenTime) / (displayCount - 1);
299299
}
300300

301301
if (displayCount >= 1) {
302-
latAvg = QpcDeltaToSeconds(latSum) / displayCount;
302+
latAvg = TimestampDeltaToSeconds(latSum) / displayCount;
303303
}
304304
}
305305

PresentMon/CsvOutput.cpp

+12-12
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,34 @@ void UpdateCsv(ProcessInfo* processInfo, SwapChainData const& chain, PresentEven
112112
auto lastPresented = chain.mPresentHistory[(chain.mNextPresentIndex - 1) % SwapChainData::PRESENT_HISTORY_MAX_COUNT].get();
113113

114114
// Compute frame statistics.
115-
double msBetweenPresents = 1000.0 * PositiveQpcDeltaToSeconds(lastPresented->PresentStartTime, p.PresentStartTime);
116-
double msInPresentApi = 1000.0 * PositiveQpcDeltaToSeconds(p.PresentStartTime, p.PresentStopTime);
115+
double msBetweenPresents = 1000.0 * PositiveTimestampDeltaToSeconds(lastPresented->PresentStartTime, p.PresentStartTime);
116+
double msInPresentApi = 1000.0 * PositiveTimestampDeltaToSeconds(p.PresentStartTime, p.PresentStopTime);
117117
double msUntilRenderComplete = 0.0;
118118
double msUntilDisplayed = 0.0;
119119
double msBetweenDisplayChange = 0.0;
120120

121121
if (args.mTrackDisplay) {
122-
msUntilRenderComplete = 1000.0 * QpcDeltaToSeconds(p.PresentStartTime, p.ReadyTime);
122+
msUntilRenderComplete = 1000.0 * TimestampDeltaToSeconds(p.PresentStartTime, p.ReadyTime);
123123

124124
if (presented) {
125-
msUntilDisplayed = 1000.0 * PositiveQpcDeltaToSeconds(p.PresentStartTime, p.ScreenTime);
125+
msUntilDisplayed = 1000.0 * PositiveTimestampDeltaToSeconds(p.PresentStartTime, p.ScreenTime);
126126

127127
if (chain.mLastDisplayedPresentIndex != UINT32_MAX) {
128128
auto lastDisplayed = chain.mPresentHistory[chain.mLastDisplayedPresentIndex % SwapChainData::PRESENT_HISTORY_MAX_COUNT].get();
129-
msBetweenDisplayChange = 1000.0 * PositiveQpcDeltaToSeconds(lastDisplayed->ScreenTime, p.ScreenTime);
129+
msBetweenDisplayChange = 1000.0 * PositiveTimestampDeltaToSeconds(lastDisplayed->ScreenTime, p.ScreenTime);
130130
}
131131
}
132132
}
133133

134134
double msUntilRenderStart = 0.0;
135135
if (args.mTrackGPU) {
136-
msUntilRenderStart = 1000.0 * QpcDeltaToSeconds(p.PresentStartTime, p.GPUStartTime);
136+
msUntilRenderStart = 1000.0 * TimestampDeltaToSeconds(p.PresentStartTime, p.GPUStartTime);
137137
}
138138

139139
double msSinceInput = 0.0;
140140
if (args.mTrackInput) {
141141
if (p.InputTime != 0) {
142-
msSinceInput = 1000.0 * QpcDeltaToSeconds(p.PresentStartTime - p.InputTime);
142+
msSinceInput = 1000.0 * TimestampDeltaToSeconds(p.PresentStartTime - p.InputTime);
143143
}
144144
}
145145

@@ -155,7 +155,7 @@ void UpdateCsv(ProcessInfo* processInfo, SwapChainData const& chain, PresentEven
155155
if (args.mOutputDateTime) {
156156
SYSTEMTIME st = {};
157157
uint64_t ns = 0;
158-
QpcToLocalSystemTime(p.PresentStartTime, &st, &ns);
158+
TimestampToLocalSystemTime(p.PresentStartTime, &st, &ns);
159159
fwprintf(fp, L"%u-%u-%u %u:%02u:%02u.%09llu",
160160
st.wYear,
161161
st.wMonth,
@@ -165,7 +165,7 @@ void UpdateCsv(ProcessInfo* processInfo, SwapChainData const& chain, PresentEven
165165
st.wSecond,
166166
ns);
167167
} else {
168-
fwprintf(fp, L"%.*lf", DBL_DIG - 1, QpcToSeconds(p.PresentStartTime));
168+
fwprintf(fp, L"%.*lf", DBL_DIG - 1, TimestampToSeconds(p.PresentStartTime));
169169
}
170170
fwprintf(fp, L",%.*lf,%.*lf",
171171
DBL_DIG - 1, msInPresentApi,
@@ -186,18 +186,18 @@ void UpdateCsv(ProcessInfo* processInfo, SwapChainData const& chain, PresentEven
186186
if (args.mTrackGPU) {
187187
fwprintf(fp, L",%.*lf,%.*lf",
188188
DBL_DIG - 1, msUntilRenderStart,
189-
DBL_DIG - 1, 1000.0 * QpcDeltaToSeconds(p.GPUDuration));
189+
DBL_DIG - 1, 1000.0 * TimestampDeltaToSeconds(p.GPUDuration));
190190
}
191191
if (args.mTrackGPUVideo) {
192192
fwprintf(fp, L",%.*lf",
193-
DBL_DIG - 1, 1000.0 * QpcDeltaToSeconds(p.GPUVideoDuration));
193+
DBL_DIG - 1, 1000.0 * TimestampDeltaToSeconds(p.GPUVideoDuration));
194194
}
195195
if (args.mTrackInput) {
196196
fwprintf(fp, L",%.*lf", DBL_DIG - 1, msSinceInput);
197197
}
198198
if (args.mOutputQpcTime) {
199199
if (args.mOutputQpcTimeInSeconds) {
200-
fwprintf(fp, L",%.*lf", DBL_DIG - 1, QpcDeltaToSeconds(p.PresentStartTime));
200+
fwprintf(fp, L",%.*lf", DBL_DIG - 1, TimestampDeltaToSeconds(p.PresentStartTime));
201201
} else {
202202
fwprintf(fp, L",%llu", p.PresentStartTime);
203203
}

PresentMon/LateStageReprojectionData.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ enum {
1414
void LateStageReprojectionData::PruneDeque(std::deque<LateStageReprojectionEvent> &lsrHistory, uint32_t msTimeDiff, uint32_t maxHistLen) {
1515
while (!lsrHistory.empty() && (
1616
lsrHistory.size() > maxHistLen ||
17-
1000.0 * QpcDeltaToSeconds(lsrHistory.back().QpcTime - lsrHistory.front().QpcTime) > msTimeDiff)) {
17+
1000.0 * TimestampDeltaToSeconds(lsrHistory.back().QpcTime - lsrHistory.front().QpcTime) > msTimeDiff)) {
1818
lsrHistory.pop_front();
1919
}
2020
}
@@ -63,7 +63,7 @@ double LateStageReprojectionData::ComputeHistoryTime(const std::deque<LateStageR
6363

6464
auto start = lsrHistory.front().QpcTime;
6565
auto end = lsrHistory.back().QpcTime;
66-
return QpcDeltaToSeconds(end - start);
66+
return TimestampDeltaToSeconds(end - start);
6767
}
6868

6969
size_t LateStageReprojectionData::ComputeHistorySize() const
@@ -89,7 +89,7 @@ double LateStageReprojectionData::ComputeFps(const std::deque<LateStageReproject
8989
auto end = lsrHistory.back().QpcTime;
9090
auto count = lsrHistory.size() - 1;
9191

92-
return count / QpcDeltaToSeconds(end - start);
92+
return count / TimestampDeltaToSeconds(end - start);
9393
}
9494

9595
double LateStageReprojectionData::ComputeSourceFps() const
@@ -168,8 +168,8 @@ LateStageReprojectionRuntimeStats LateStageReprojectionData::ComputeRuntimeStats
168168
stats.mAppProcessId = mLSRHistory[count - 1].GetAppProcessId();
169169
stats.mLsrProcessId = mLSRHistory[count - 1].ProcessId;
170170

171-
stats.mAppSourceCpuRenderTimeInMs = 1000.0 * QpcDeltaToSeconds(totalAppSourceCpuRenderTime);
172-
stats.mAppSourceReleaseToLsrAcquireInMs = 1000.0 * QpcDeltaToSeconds(totalAppSourceReleaseToLsrAcquireTime);
171+
stats.mAppSourceCpuRenderTimeInMs = 1000.0 * TimestampDeltaToSeconds(totalAppSourceCpuRenderTime);
172+
stats.mAppSourceReleaseToLsrAcquireInMs = 1000.0 * TimestampDeltaToSeconds(totalAppSourceReleaseToLsrAcquireTime);
173173

174174
stats.mAppSourceReleaseToLsrAcquireInMs /= count;
175175
stats.mAppSourceCpuRenderTimeInMs /= count;
@@ -249,8 +249,8 @@ void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageRe
249249

250250
auto& curr = lsr.mLSRHistory[len - 1];
251251
auto& prev = lsr.mLSRHistory[len - 2];
252-
const double deltaMilliseconds = 1000.0 * QpcDeltaToSeconds(curr.QpcTime - prev.QpcTime);
253-
const double timeInSeconds = QpcToSeconds(p.QpcTime);
252+
const double deltaMilliseconds = 1000.0 * TimestampDeltaToSeconds(curr.QpcTime - prev.QpcTime);
253+
const double timeInSeconds = TimestampToSeconds(p.QpcTime);
254254

255255
fprintf(fp, "%ws,%d,%d", proc->mModuleName.c_str(), curr.GetAppProcessId(), curr.ProcessId);
256256
if (args.mTrackDebug) {
@@ -262,18 +262,18 @@ void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageRe
262262
double appPresentToLsrMilliseconds = 0.0;
263263
if (curr.IsValidAppFrame()) {
264264
const uint64_t currAppPresentTime = curr.GetAppPresentTime();
265-
appPresentToLsrMilliseconds = 1000.0 * QpcDeltaToSeconds(curr.QpcTime - currAppPresentTime);
265+
appPresentToLsrMilliseconds = 1000.0 * TimestampDeltaToSeconds(curr.QpcTime - currAppPresentTime);
266266

267267
if (prev.IsValidAppFrame() && (curr.GetAppProcessId() == prev.GetAppProcessId())) {
268268
const uint64_t prevAppPresentTime = prev.GetAppPresentTime();
269-
appPresentDeltaMilliseconds = 1000.0 * QpcDeltaToSeconds(currAppPresentTime - prevAppPresentTime);
269+
appPresentDeltaMilliseconds = 1000.0 * TimestampDeltaToSeconds(currAppPresentTime - prevAppPresentTime);
270270
}
271271
}
272272
fprintf(fp, ",%.6lf,%.6lf", appPresentDeltaMilliseconds, appPresentToLsrMilliseconds);
273273
}
274274
fprintf(fp, ",%.6lf,%d,%d", deltaMilliseconds, !curr.NewSourceLatched, curr.MissedVsyncCount);
275275
if (args.mTrackDebug) {
276-
fprintf(fp, ",%.6lf,%.6lf", 1000 * QpcDeltaToSeconds(curr.Source.GetReleaseFromRenderingToAcquireForPresentationTime()), 1000.0 * QpcDeltaToSeconds(curr.GetAppCpuRenderFrameTime()));
276+
fprintf(fp, ",%.6lf,%.6lf", 1000 * TimestampDeltaToSeconds(curr.Source.GetReleaseFromRenderingToAcquireForPresentationTime()), 1000.0 * TimestampDeltaToSeconds(curr.GetAppCpuRenderFrameTime()));
277277
}
278278
fprintf(fp, ",%.6lf", curr.AppPredictionLatencyMs);
279279
if (args.mTrackDebug) {

PresentMon/OutputThread.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -345,12 +345,12 @@ static void PruneHistory(
345345
{
346346
assert(processEvents.size() + presentEvents.size() + lsrEvents.size() > 0);
347347

348-
auto latestQpc = std::max(std::max(
348+
auto latestTimestamp = std::max(std::max(
349349
processEvents.empty() ? 0ull : processEvents.back().QpcTime,
350350
presentEvents.empty() ? 0ull : presentEvents.back()->PresentStartTime),
351351
lsrEvents.empty() ? 0ull : lsrEvents.back()->QpcTime);
352352

353-
auto minQpc = latestQpc - SecondsDeltaToQpc(2.0);
353+
auto minTimestamp = latestTimestamp - SecondsDeltaToTimestamp(2.0);
354354

355355
for (auto& pair : gProcesses) {
356356
auto processInfo = &pair.second;
@@ -361,7 +361,7 @@ static void PruneHistory(
361361
for (; count > 0; --count) {
362362
auto index = swapChain->mNextPresentIndex - count;
363363
auto const& presentEvent = swapChain->mPresentHistory[index % SwapChainData::PRESENT_HISTORY_MAX_COUNT];
364-
if (presentEvent->PresentStartTime >= minQpc) {
364+
if (presentEvent->PresentStartTime >= minTimestamp) {
365365
break;
366366
}
367367
if (index == swapChain->mLastDisplayedPresentIndex) {

PresentMon/PresentMon.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ void DequeueAnalyzedInfo(
155155
std::vector<std::shared_ptr<PresentEvent>>* presentEvents,
156156
std::vector<std::shared_ptr<PresentEvent>>* lostPresentEvents,
157157
std::vector<std::shared_ptr<LateStageReprojectionEvent>>* lsrs);
158-
double QpcDeltaToSeconds(uint64_t qpcDelta);
159-
double QpcDeltaToSeconds(uint64_t qpcFrom, uint64_t qpcTo);
160-
double PositiveQpcDeltaToSeconds(uint64_t qpcFrom, uint64_t qpcTo);
161-
uint64_t SecondsDeltaToQpc(double secondsDelta);
162-
double QpcToSeconds(uint64_t qpc);
163-
void QpcToLocalSystemTime(uint64_t qpc, SYSTEMTIME* st, uint64_t* ns);
158+
double TimestampDeltaToSeconds(uint64_t timestampDelta);
159+
double TimestampDeltaToSeconds(uint64_t timestampFrom, uint64_t timestampTo);
160+
double PositiveTimestampDeltaToSeconds(uint64_t timestampFrom, uint64_t timestampTo);
161+
uint64_t SecondsDeltaToTimestamp(double secondsDelta);
162+
double TimestampToSeconds(uint64_t timestamp);
163+
void TimestampToLocalSystemTime(uint64_t timestamp, SYSTEMTIME* st, uint64_t* ns);

0 commit comments

Comments
 (0)