196 lines
5.7 KiB
C++
196 lines
5.7 KiB
C++
#include "CadenceTelemetry.h"
|
|
#include "CadenceTelemetryJson.h"
|
|
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <thread>
|
|
|
|
namespace
|
|
{
|
|
int gFailures = 0;
|
|
|
|
void Expect(bool condition, const char* message)
|
|
{
|
|
if (condition)
|
|
return;
|
|
|
|
std::cerr << "FAIL: " << message << "\n";
|
|
++gFailures;
|
|
}
|
|
|
|
struct FakeExchangeMetrics
|
|
{
|
|
std::size_t freeCount = 0;
|
|
std::size_t completedCount = 0;
|
|
std::size_t scheduledCount = 0;
|
|
uint64_t completedFrames = 0;
|
|
uint64_t scheduledFrames = 0;
|
|
};
|
|
|
|
struct FakeExchange
|
|
{
|
|
FakeExchangeMetrics metrics;
|
|
FakeExchangeMetrics Metrics() const { return metrics; }
|
|
};
|
|
|
|
struct FakeOutputThreadMetrics
|
|
{
|
|
uint64_t completedPollMisses = 0;
|
|
uint64_t scheduleFailures = 0;
|
|
};
|
|
|
|
struct FakeOutputThread
|
|
{
|
|
FakeOutputThreadMetrics metrics;
|
|
FakeOutputThreadMetrics Metrics() const { return metrics; }
|
|
};
|
|
|
|
struct FakeOutputMetrics
|
|
{
|
|
uint64_t completions = 0;
|
|
uint64_t displayedLate = 0;
|
|
uint64_t dropped = 0;
|
|
uint64_t scheduleFailures = 0;
|
|
bool actualBufferedFramesAvailable = false;
|
|
uint64_t actualBufferedFrames = 0;
|
|
double scheduleCallMilliseconds = 0.0;
|
|
};
|
|
|
|
struct FakeOutput
|
|
{
|
|
FakeOutputMetrics metrics;
|
|
FakeOutputMetrics Metrics() const { return metrics; }
|
|
};
|
|
|
|
struct FakeRenderThreadMetrics
|
|
{
|
|
uint64_t shaderBuildsCommitted = 0;
|
|
uint64_t shaderBuildFailures = 0;
|
|
};
|
|
|
|
struct FakeRenderThread
|
|
{
|
|
FakeRenderThreadMetrics metrics;
|
|
FakeRenderThreadMetrics GetMetrics() const { return metrics; }
|
|
};
|
|
|
|
void TestTelemetrySamplesCompletedPollMissesAndShaderCounts()
|
|
{
|
|
RenderCadenceCompositor::CadenceTelemetry telemetry;
|
|
FakeExchange exchange;
|
|
exchange.metrics.freeCount = 7;
|
|
exchange.metrics.completedCount = 1;
|
|
exchange.metrics.scheduledCount = 4;
|
|
exchange.metrics.completedFrames = 100;
|
|
exchange.metrics.scheduledFrames = 96;
|
|
|
|
FakeOutput output;
|
|
output.metrics.actualBufferedFramesAvailable = true;
|
|
output.metrics.actualBufferedFrames = 4;
|
|
|
|
FakeOutputThread outputThread;
|
|
outputThread.metrics.completedPollMisses = 12;
|
|
outputThread.metrics.scheduleFailures = 0;
|
|
|
|
FakeRenderThread renderThread;
|
|
renderThread.metrics.shaderBuildsCommitted = 1;
|
|
renderThread.metrics.shaderBuildFailures = 0;
|
|
|
|
const auto snapshot = telemetry.Sample(exchange, output, outputThread, renderThread);
|
|
Expect(snapshot.freeFrames == 7, "free frame count is sampled");
|
|
Expect(snapshot.completedFrames == 1, "completed frame count is sampled");
|
|
Expect(snapshot.scheduledFrames == 4, "scheduled frame count is sampled");
|
|
Expect(snapshot.completedPollMisses == 12, "completed poll misses are sampled");
|
|
Expect(snapshot.shaderBuildsCommitted == 1, "shader committed count is sampled");
|
|
Expect(snapshot.shaderBuildFailures == 0, "shader failure count is sampled");
|
|
Expect(snapshot.deckLinkBufferedAvailable, "buffer telemetry availability is sampled");
|
|
Expect(snapshot.deckLinkBuffered == 4, "buffer depth is sampled");
|
|
}
|
|
|
|
void TestTelemetryComputesRatesFromDeltas()
|
|
{
|
|
RenderCadenceCompositor::CadenceTelemetry telemetry;
|
|
FakeExchange exchange;
|
|
FakeOutput output;
|
|
FakeOutputThread outputThread;
|
|
FakeRenderThread renderThread;
|
|
|
|
exchange.metrics.completedFrames = 10;
|
|
exchange.metrics.scheduledFrames = 10;
|
|
(void)telemetry.Sample(exchange, output, outputThread, renderThread);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
|
|
exchange.metrics.completedFrames = 20;
|
|
exchange.metrics.scheduledFrames = 19;
|
|
const auto snapshot = telemetry.Sample(exchange, output, outputThread, renderThread);
|
|
Expect(snapshot.sampleSeconds > 0.0, "second telemetry sample has elapsed time");
|
|
Expect(snapshot.renderFps > 0.0, "render fps is computed from completed frame delta");
|
|
Expect(snapshot.scheduleFps > 0.0, "schedule fps is computed from scheduled frame delta");
|
|
}
|
|
|
|
void TestTelemetrySerializesToJson()
|
|
{
|
|
RenderCadenceCompositor::CadenceTelemetrySnapshot snapshot;
|
|
snapshot.sampleSeconds = 1.0;
|
|
snapshot.renderFps = 59.94;
|
|
snapshot.scheduleFps = 60.0;
|
|
snapshot.freeFrames = 7;
|
|
snapshot.completedFrames = 1;
|
|
snapshot.scheduledFrames = 4;
|
|
snapshot.renderedTotal = 120;
|
|
snapshot.scheduledTotal = 118;
|
|
snapshot.completedPollMisses = 3;
|
|
snapshot.scheduleFailures = 0;
|
|
snapshot.completions = 117;
|
|
snapshot.displayedLate = 1;
|
|
snapshot.dropped = 2;
|
|
snapshot.shaderBuildsCommitted = 1;
|
|
snapshot.shaderBuildFailures = 0;
|
|
snapshot.deckLinkBufferedAvailable = true;
|
|
snapshot.deckLinkBuffered = 4;
|
|
snapshot.deckLinkScheduleCallMilliseconds = 1.25;
|
|
|
|
const std::string json = RenderCadenceCompositor::CadenceTelemetryToJson(snapshot);
|
|
const std::string expected =
|
|
"{\"sampleSeconds\":1,\"renderFps\":59.94,\"scheduleFps\":60,"
|
|
"\"free\":7,\"completed\":1,\"scheduled\":4,"
|
|
"\"renderedTotal\":120,\"scheduledTotal\":118,"
|
|
"\"completedPollMisses\":3,\"scheduleFailures\":0,"
|
|
"\"completions\":117,\"late\":1,\"dropped\":2,"
|
|
"\"shaderCommitted\":1,\"shaderFailures\":0,"
|
|
"\"deckLinkBufferedAvailable\":true,\"deckLinkBuffered\":4,"
|
|
"\"scheduleCallMs\":1.25}";
|
|
Expect(json == expected, "telemetry snapshot serializes to stable JSON");
|
|
}
|
|
|
|
void TestUnavailableDeckLinkBufferSerializesAsNull()
|
|
{
|
|
RenderCadenceCompositor::CadenceTelemetrySnapshot snapshot;
|
|
snapshot.deckLinkBufferedAvailable = false;
|
|
|
|
const std::string json = RenderCadenceCompositor::CadenceTelemetryToJson(snapshot);
|
|
Expect(
|
|
json.find("\"deckLinkBufferedAvailable\":false,\"deckLinkBuffered\":null") != std::string::npos,
|
|
"unavailable DeckLink buffer depth serializes as null");
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
TestTelemetrySamplesCompletedPollMissesAndShaderCounts();
|
|
TestTelemetryComputesRatesFromDeltas();
|
|
TestTelemetrySerializesToJson();
|
|
TestUnavailableDeckLinkBufferSerializesAsNull();
|
|
|
|
if (gFailures != 0)
|
|
{
|
|
std::cerr << gFailures << " telemetry test failure(s).\n";
|
|
return 1;
|
|
}
|
|
|
|
std::cout << "RenderCadenceCompositor telemetry tests passed.\n";
|
|
return 0;
|
|
}
|