Input telemetry
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m56s
CI / Windows Release Package (push) Has been skipped

This commit is contained in:
Aiden
2026-05-12 21:13:22 +10:00
parent d72272b5a8
commit 5c66cfdc64
7 changed files with 86 additions and 0 deletions

View File

@@ -273,6 +273,10 @@ Input telemetry:
- `inputFramesReceived`: frames accepted into `InputFrameMailbox` - `inputFramesReceived`: frames accepted into `InputFrameMailbox`
- `inputFramesDropped`: ready input frames dropped or missed because the mailbox was full - `inputFramesDropped`: ready input frames dropped or missed because the mailbox was full
- `inputConsumeMisses`: render ticks where no ready input frame was available to upload
- `inputUploadMisses`: input texture upload attempts that reused the previous GL input texture
- `inputReadyFrames`: ready input frames currently queued in `InputFrameMailbox`
- `inputReadingFrames`: input frames currently protected while render uploads them
- `inputLatestAgeMs`: age of the newest submitted input frame - `inputLatestAgeMs`: age of the newest submitted input frame
- `inputUploadMs`: render-thread GL upload/decode submission time for the latest uploaded input frame - `inputUploadMs`: render-thread GL upload/decode submission time for the latest uploaded input frame
- `inputFormatSupported`: whether the latest frame reaching the render upload path was BGRA8 or UYVY8 compatible - `inputFormatSupported`: whether the latest frame reaching the render upload path was BGRA8 or UYVY8 compatible

View File

@@ -87,6 +87,10 @@ RenderThread::Metrics RenderThread::GetMetrics() const
metrics.shaderBuildFailures = mShaderBuildFailures.load(std::memory_order_relaxed); metrics.shaderBuildFailures = mShaderBuildFailures.load(std::memory_order_relaxed);
metrics.inputFramesReceived = mInputFramesReceived.load(std::memory_order_relaxed); metrics.inputFramesReceived = mInputFramesReceived.load(std::memory_order_relaxed);
metrics.inputFramesDropped = mInputFramesDropped.load(std::memory_order_relaxed); metrics.inputFramesDropped = mInputFramesDropped.load(std::memory_order_relaxed);
metrics.inputConsumeMisses = mInputConsumeMisses.load(std::memory_order_relaxed);
metrics.inputUploadMisses = mInputUploadMisses.load(std::memory_order_relaxed);
metrics.inputReadyFrames = mInputReadyFrames.load(std::memory_order_relaxed);
metrics.inputReadingFrames = mInputReadingFrames.load(std::memory_order_relaxed);
metrics.inputLatestAgeMilliseconds = mInputLatestAgeMilliseconds.load(std::memory_order_relaxed); metrics.inputLatestAgeMilliseconds = mInputLatestAgeMilliseconds.load(std::memory_order_relaxed);
metrics.inputUploadMilliseconds = mInputUploadMilliseconds.load(std::memory_order_relaxed); metrics.inputUploadMilliseconds = mInputUploadMilliseconds.load(std::memory_order_relaxed);
metrics.inputFormatSupported = mInputFormatSupported.load(std::memory_order_relaxed); metrics.inputFormatSupported = mInputFormatSupported.load(std::memory_order_relaxed);
@@ -240,6 +244,9 @@ void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture)
const InputFrameMailboxMetrics mailboxMetrics = mInputMailbox->Metrics(); const InputFrameMailboxMetrics mailboxMetrics = mInputMailbox->Metrics();
mInputFramesReceived.store(mailboxMetrics.submittedFrames, std::memory_order_relaxed); mInputFramesReceived.store(mailboxMetrics.submittedFrames, std::memory_order_relaxed);
mInputFramesDropped.store(mailboxMetrics.droppedReadyFrames + mailboxMetrics.submitMisses, std::memory_order_relaxed); mInputFramesDropped.store(mailboxMetrics.droppedReadyFrames + mailboxMetrics.submitMisses, std::memory_order_relaxed);
mInputConsumeMisses.store(mailboxMetrics.consumeMisses, std::memory_order_relaxed);
mInputReadyFrames.store(mailboxMetrics.readyCount, std::memory_order_relaxed);
mInputReadingFrames.store(mailboxMetrics.readingCount, std::memory_order_relaxed);
mInputLatestAgeMilliseconds.store(mailboxMetrics.latestFrameAgeMilliseconds, std::memory_order_relaxed); mInputLatestAgeMilliseconds.store(mailboxMetrics.latestFrameAgeMilliseconds, std::memory_order_relaxed);
mInputSignalPresent.store(mailboxMetrics.hasSubmittedFrame, std::memory_order_relaxed); mInputSignalPresent.store(mailboxMetrics.hasSubmittedFrame, std::memory_order_relaxed);
} }
@@ -247,10 +254,14 @@ void RenderThread::PublishInputMetrics(const InputFrameTexture& inputTexture)
{ {
mInputFramesReceived.store(0, std::memory_order_relaxed); mInputFramesReceived.store(0, std::memory_order_relaxed);
mInputFramesDropped.store(0, std::memory_order_relaxed); mInputFramesDropped.store(0, std::memory_order_relaxed);
mInputConsumeMisses.store(0, std::memory_order_relaxed);
mInputReadyFrames.store(0, std::memory_order_relaxed);
mInputReadingFrames.store(0, std::memory_order_relaxed);
mInputLatestAgeMilliseconds.store(0.0, std::memory_order_relaxed); mInputLatestAgeMilliseconds.store(0.0, std::memory_order_relaxed);
mInputSignalPresent.store(false, std::memory_order_relaxed); mInputSignalPresent.store(false, std::memory_order_relaxed);
} }
mInputUploadMisses.store(inputTexture.UploadMisses(), std::memory_order_relaxed);
mInputUploadMilliseconds.store(inputTexture.LastUploadMilliseconds(), std::memory_order_relaxed); mInputUploadMilliseconds.store(inputTexture.LastUploadMilliseconds(), std::memory_order_relaxed);
mInputFormatSupported.store(inputTexture.LastFrameFormatSupported(), std::memory_order_relaxed); mInputFormatSupported.store(inputTexture.LastFrameFormatSupported(), std::memory_order_relaxed);
} }

View File

@@ -40,6 +40,10 @@ public:
uint64_t shaderBuildFailures = 0; uint64_t shaderBuildFailures = 0;
uint64_t inputFramesReceived = 0; uint64_t inputFramesReceived = 0;
uint64_t inputFramesDropped = 0; uint64_t inputFramesDropped = 0;
uint64_t inputConsumeMisses = 0;
uint64_t inputUploadMisses = 0;
std::size_t inputReadyFrames = 0;
std::size_t inputReadingFrames = 0;
double inputLatestAgeMilliseconds = 0.0; double inputLatestAgeMilliseconds = 0.0;
double inputUploadMilliseconds = 0.0; double inputUploadMilliseconds = 0.0;
bool inputFormatSupported = true; bool inputFormatSupported = true;
@@ -94,6 +98,10 @@ private:
std::atomic<uint64_t> mShaderBuildFailures{ 0 }; std::atomic<uint64_t> mShaderBuildFailures{ 0 };
std::atomic<uint64_t> mInputFramesReceived{ 0 }; std::atomic<uint64_t> mInputFramesReceived{ 0 };
std::atomic<uint64_t> mInputFramesDropped{ 0 }; std::atomic<uint64_t> mInputFramesDropped{ 0 };
std::atomic<uint64_t> mInputConsumeMisses{ 0 };
std::atomic<uint64_t> mInputUploadMisses{ 0 };
std::atomic<std::size_t> mInputReadyFrames{ 0 };
std::atomic<std::size_t> mInputReadingFrames{ 0 };
std::atomic<double> mInputLatestAgeMilliseconds{ 0.0 }; std::atomic<double> mInputLatestAgeMilliseconds{ 0.0 };
std::atomic<double> mInputUploadMilliseconds{ 0.0 }; std::atomic<double> mInputUploadMilliseconds{ 0.0 };
std::atomic<bool> mInputFormatSupported{ true }; std::atomic<bool> mInputFormatSupported{ true };

View File

@@ -26,6 +26,10 @@ struct CadenceTelemetrySnapshot
uint64_t shaderBuildFailures = 0; uint64_t shaderBuildFailures = 0;
uint64_t inputFramesReceived = 0; uint64_t inputFramesReceived = 0;
uint64_t inputFramesDropped = 0; uint64_t inputFramesDropped = 0;
uint64_t inputConsumeMisses = 0;
uint64_t inputUploadMisses = 0;
std::size_t inputReadyFrames = 0;
std::size_t inputReadingFrames = 0;
double inputLatestAgeMilliseconds = 0.0; double inputLatestAgeMilliseconds = 0.0;
double inputUploadMilliseconds = 0.0; double inputUploadMilliseconds = 0.0;
bool inputFormatSupported = true; bool inputFormatSupported = true;
@@ -104,6 +108,10 @@ public:
snapshot.shaderBuildFailures = renderMetrics.shaderBuildFailures; snapshot.shaderBuildFailures = renderMetrics.shaderBuildFailures;
snapshot.inputFramesReceived = renderMetrics.inputFramesReceived; snapshot.inputFramesReceived = renderMetrics.inputFramesReceived;
snapshot.inputFramesDropped = renderMetrics.inputFramesDropped; snapshot.inputFramesDropped = renderMetrics.inputFramesDropped;
snapshot.inputConsumeMisses = renderMetrics.inputConsumeMisses;
snapshot.inputUploadMisses = renderMetrics.inputUploadMisses;
snapshot.inputReadyFrames = renderMetrics.inputReadyFrames;
snapshot.inputReadingFrames = renderMetrics.inputReadingFrames;
snapshot.inputLatestAgeMilliseconds = renderMetrics.inputLatestAgeMilliseconds; snapshot.inputLatestAgeMilliseconds = renderMetrics.inputLatestAgeMilliseconds;
snapshot.inputUploadMilliseconds = renderMetrics.inputUploadMilliseconds; snapshot.inputUploadMilliseconds = renderMetrics.inputUploadMilliseconds;
snapshot.inputFormatSupported = renderMetrics.inputFormatSupported; snapshot.inputFormatSupported = renderMetrics.inputFormatSupported;

View File

@@ -28,6 +28,10 @@ inline void WriteCadenceTelemetryJson(JsonWriter& writer, const CadenceTelemetry
writer.KeyUInt("shaderFailures", snapshot.shaderBuildFailures); writer.KeyUInt("shaderFailures", snapshot.shaderBuildFailures);
writer.KeyUInt("inputFramesReceived", snapshot.inputFramesReceived); writer.KeyUInt("inputFramesReceived", snapshot.inputFramesReceived);
writer.KeyUInt("inputFramesDropped", snapshot.inputFramesDropped); writer.KeyUInt("inputFramesDropped", snapshot.inputFramesDropped);
writer.KeyUInt("inputConsumeMisses", snapshot.inputConsumeMisses);
writer.KeyUInt("inputUploadMisses", snapshot.inputUploadMisses);
writer.KeyUInt("inputReadyFrames", static_cast<uint64_t>(snapshot.inputReadyFrames));
writer.KeyUInt("inputReadingFrames", static_cast<uint64_t>(snapshot.inputReadingFrames));
writer.KeyDouble("inputLatestAgeMs", snapshot.inputLatestAgeMilliseconds); writer.KeyDouble("inputLatestAgeMs", snapshot.inputLatestAgeMilliseconds);
writer.KeyDouble("inputUploadMs", snapshot.inputUploadMilliseconds); writer.KeyDouble("inputUploadMs", snapshot.inputUploadMilliseconds);
writer.KeyBool("inputFormatSupported", snapshot.inputFormatSupported); writer.KeyBool("inputFormatSupported", snapshot.inputFormatSupported);

View File

@@ -649,6 +649,39 @@ components:
type: number type: number
flushedFrameCount: flushedFrameCount:
type: number type: number
cadence:
$ref: "#/components/schemas/CadenceTelemetry"
CadenceTelemetry:
type: object
properties:
inputFramesReceived:
type: number
inputFramesDropped:
type: number
inputConsumeMisses:
type: number
description: Render ticks where no ready input frame was available to upload.
inputUploadMisses:
type: number
description: Input texture upload attempts that reused the previous GL input texture.
inputReadyFrames:
type: number
description: Ready input frames currently queued in the input mailbox.
inputReadingFrames:
type: number
description: Input frames currently protected while render uploads them.
inputLatestAgeMs:
type: number
inputUploadMs:
type: number
inputCaptureFps:
type: number
inputConvertMs:
type: number
inputSubmitMs:
type: number
inputCaptureFormat:
type: string
BackendPlayoutStatus: BackendPlayoutStatus:
type: object type: object
properties: properties:

View File

@@ -69,6 +69,10 @@ struct FakeRenderThreadMetrics
uint64_t shaderBuildFailures = 0; uint64_t shaderBuildFailures = 0;
uint64_t inputFramesReceived = 0; uint64_t inputFramesReceived = 0;
uint64_t inputFramesDropped = 0; uint64_t inputFramesDropped = 0;
uint64_t inputConsumeMisses = 0;
uint64_t inputUploadMisses = 0;
std::size_t inputReadyFrames = 0;
std::size_t inputReadingFrames = 0;
double inputLatestAgeMilliseconds = 0.0; double inputLatestAgeMilliseconds = 0.0;
double inputUploadMilliseconds = 0.0; double inputUploadMilliseconds = 0.0;
bool inputFormatSupported = true; bool inputFormatSupported = true;
@@ -104,6 +108,10 @@ void TestTelemetrySamplesCompletedPollMissesAndShaderCounts()
renderThread.metrics.shaderBuildFailures = 0; renderThread.metrics.shaderBuildFailures = 0;
renderThread.metrics.inputFramesReceived = 9; renderThread.metrics.inputFramesReceived = 9;
renderThread.metrics.inputFramesDropped = 2; renderThread.metrics.inputFramesDropped = 2;
renderThread.metrics.inputConsumeMisses = 3;
renderThread.metrics.inputUploadMisses = 4;
renderThread.metrics.inputReadyFrames = 1;
renderThread.metrics.inputReadingFrames = 0;
renderThread.metrics.inputLatestAgeMilliseconds = 4.5; renderThread.metrics.inputLatestAgeMilliseconds = 4.5;
renderThread.metrics.inputUploadMilliseconds = 0.25; renderThread.metrics.inputUploadMilliseconds = 0.25;
renderThread.metrics.inputFormatSupported = true; renderThread.metrics.inputFormatSupported = true;
@@ -118,6 +126,10 @@ void TestTelemetrySamplesCompletedPollMissesAndShaderCounts()
Expect(snapshot.shaderBuildFailures == 0, "shader failure count is sampled"); Expect(snapshot.shaderBuildFailures == 0, "shader failure count is sampled");
Expect(snapshot.inputFramesReceived == 9, "input received count is sampled"); Expect(snapshot.inputFramesReceived == 9, "input received count is sampled");
Expect(snapshot.inputFramesDropped == 2, "input dropped count is sampled"); Expect(snapshot.inputFramesDropped == 2, "input dropped count is sampled");
Expect(snapshot.inputConsumeMisses == 3, "input consume miss count is sampled");
Expect(snapshot.inputUploadMisses == 4, "input upload miss count is sampled");
Expect(snapshot.inputReadyFrames == 1, "input ready frame count is sampled");
Expect(snapshot.inputReadingFrames == 0, "input reading frame count is sampled");
Expect(snapshot.inputLatestAgeMilliseconds == 4.5, "input latest age is sampled"); Expect(snapshot.inputLatestAgeMilliseconds == 4.5, "input latest age is sampled");
Expect(snapshot.inputUploadMilliseconds == 0.25, "input upload timing is sampled"); Expect(snapshot.inputUploadMilliseconds == 0.25, "input upload timing is sampled");
Expect(snapshot.inputFormatSupported, "input format support is sampled"); Expect(snapshot.inputFormatSupported, "input format support is sampled");
@@ -168,6 +180,10 @@ void TestTelemetrySerializesToJson()
snapshot.shaderBuildFailures = 0; snapshot.shaderBuildFailures = 0;
snapshot.inputFramesReceived = 10; snapshot.inputFramesReceived = 10;
snapshot.inputFramesDropped = 1; snapshot.inputFramesDropped = 1;
snapshot.inputConsumeMisses = 2;
snapshot.inputUploadMisses = 3;
snapshot.inputReadyFrames = 1;
snapshot.inputReadingFrames = 0;
snapshot.inputLatestAgeMilliseconds = 3.5; snapshot.inputLatestAgeMilliseconds = 3.5;
snapshot.inputUploadMilliseconds = 0.75; snapshot.inputUploadMilliseconds = 0.75;
snapshot.inputFormatSupported = true; snapshot.inputFormatSupported = true;
@@ -192,6 +208,8 @@ void TestTelemetrySerializesToJson()
"\"completions\":117,\"late\":1,\"dropped\":2," "\"completions\":117,\"late\":1,\"dropped\":2,"
"\"shaderCommitted\":1,\"shaderFailures\":0," "\"shaderCommitted\":1,\"shaderFailures\":0,"
"\"inputFramesReceived\":10,\"inputFramesDropped\":1," "\"inputFramesReceived\":10,\"inputFramesDropped\":1,"
"\"inputConsumeMisses\":2,\"inputUploadMisses\":3,"
"\"inputReadyFrames\":1,\"inputReadingFrames\":0,"
"\"inputLatestAgeMs\":3.5,\"inputUploadMs\":0.75," "\"inputLatestAgeMs\":3.5,\"inputUploadMs\":0.75,"
"\"inputFormatSupported\":true,\"inputSignalPresent\":true," "\"inputFormatSupported\":true,\"inputSignalPresent\":true,"
"\"inputCaptureFps\":59.94,\"inputConvertMs\":4.25," "\"inputCaptureFps\":59.94,\"inputConvertMs\":4.25,"