Add v210 upload worker probe
This commit is contained in:
@@ -577,6 +577,10 @@ bool applyConfigFile(
|
|||||||
{
|
{
|
||||||
config.paceUploads = boolValue;
|
config.paceUploads = boolValue;
|
||||||
}
|
}
|
||||||
|
if (jsonBool(objectField(*root, "v210UploadWorker"), boolValue))
|
||||||
|
{
|
||||||
|
config.v210UploadWorker = boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
if (const std::string* present =
|
if (const std::string* present =
|
||||||
jsonString(objectField(*root, "present")))
|
jsonString(objectField(*root, "present")))
|
||||||
@@ -809,6 +813,7 @@ void printUsage(const char* executableName)
|
|||||||
<< " --perf Log per-frame CPU timing breakdown\n"
|
<< " --perf Log per-frame CPU timing breakdown\n"
|
||||||
<< " --verbose Enable detailed startup and SDK logs\n"
|
<< " --verbose Enable detailed startup and SDK logs\n"
|
||||||
<< " --pace-uploads Pace v210 uploads by feed frame rate\n"
|
<< " --pace-uploads Pace v210 uploads by feed frame rate\n"
|
||||||
|
<< " --v210-upload-worker Copy direct v210 payloads on a worker thread\n"
|
||||||
<< " --config <path> Load JSON feed configuration\n"
|
<< " --config <path> Load JSON feed configuration\n"
|
||||||
<< " --grid <cols>x<rows> Set multiview grid (default 2x2, max 16 feeds)\n"
|
<< " --grid <cols>x<rows> Set multiview grid (default 2x2, max 16 feeds)\n"
|
||||||
<< " --fps-cap <fps> Limit render loop FPS (default 60)\n"
|
<< " --fps-cap <fps> Limit render loop FPS (default 60)\n"
|
||||||
@@ -955,6 +960,12 @@ ConfigParseResult parseAppConfig(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg == "--v210-upload-worker")
|
||||||
|
{
|
||||||
|
result.config.v210UploadWorker = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg == "--v210-staging-memory")
|
if (arg == "--v210-staging-memory")
|
||||||
{
|
{
|
||||||
if (i + 1 >= argc)
|
if (i + 1 >= argc)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ struct AppConfig
|
|||||||
bool logPerf = false;
|
bool logPerf = false;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool paceUploads = false;
|
bool paceUploads = false;
|
||||||
|
bool v210UploadWorker = false;
|
||||||
uint32_t fpsCap = 60;
|
uint32_t fpsCap = 60;
|
||||||
uint32_t maxV210UploadsPerFrame = 0;
|
uint32_t maxV210UploadsPerFrame = 0;
|
||||||
uint32_t gridCols = DefaultGridCols;
|
uint32_t gridCols = DefaultGridCols;
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <deque>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -26,7 +28,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
@@ -49,6 +53,8 @@ struct PerfStats
|
|||||||
uint64_t stageCopyTicks = 0;
|
uint64_t stageCopyTicks = 0;
|
||||||
uint64_t directV210SourceReadNs = 0;
|
uint64_t directV210SourceReadNs = 0;
|
||||||
uint64_t directV210PayloadCopyNs = 0;
|
uint64_t directV210PayloadCopyNs = 0;
|
||||||
|
uint64_t workerV210SourceReadNs = 0;
|
||||||
|
uint64_t workerV210PayloadCopyNs = 0;
|
||||||
uint64_t uploadRecordTicks = 0;
|
uint64_t uploadRecordTicks = 0;
|
||||||
uint64_t submitPresentTicks = 0;
|
uint64_t submitPresentTicks = 0;
|
||||||
uint64_t idleDelayTicks = 0;
|
uint64_t idleDelayTicks = 0;
|
||||||
@@ -69,6 +75,8 @@ struct FramePerfStats
|
|||||||
uint64_t stageCopyTicks = 0;
|
uint64_t stageCopyTicks = 0;
|
||||||
uint64_t directV210SourceReadNs = 0;
|
uint64_t directV210SourceReadNs = 0;
|
||||||
uint64_t directV210PayloadCopyNs = 0;
|
uint64_t directV210PayloadCopyNs = 0;
|
||||||
|
uint64_t workerV210SourceReadNs = 0;
|
||||||
|
uint64_t workerV210PayloadCopyNs = 0;
|
||||||
uint64_t maxStageCopyTicks = 0;
|
uint64_t maxStageCopyTicks = 0;
|
||||||
uint64_t maxStageCopyBytes = 0;
|
uint64_t maxStageCopyBytes = 0;
|
||||||
uint32_t maxStageCopyFeed = 0;
|
uint32_t maxStageCopyFeed = 0;
|
||||||
@@ -95,6 +103,129 @@ struct FramePerfStats
|
|||||||
uint32_t maxProcessEventType = 0;
|
uint32_t maxProcessEventType = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct V210UploadJob
|
||||||
|
{
|
||||||
|
uint32_t feedIndex = 0;
|
||||||
|
uint32_t frameCounter = 0;
|
||||||
|
IVideoFeed* feed = nullptr;
|
||||||
|
void* destination = nullptr;
|
||||||
|
size_t destinationSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct V210UploadResult
|
||||||
|
{
|
||||||
|
uint32_t feedIndex = 0;
|
||||||
|
bool copied = false;
|
||||||
|
uint64_t version = 0;
|
||||||
|
V210ReadTiming timing{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class V210UploadWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
V210UploadWorker()
|
||||||
|
: mThread(&V210UploadWorker::run, this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~V210UploadWorker()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
V210UploadWorker(const V210UploadWorker&) = delete;
|
||||||
|
V210UploadWorker& operator=(const V210UploadWorker&) = delete;
|
||||||
|
|
||||||
|
void enqueue(V210UploadJob job)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
mJobs.push_back(job);
|
||||||
|
}
|
||||||
|
mCondition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drainResults(std::vector<V210UploadResult>& results)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
while (!mResults.empty())
|
||||||
|
{
|
||||||
|
results.push_back(mResults.front());
|
||||||
|
mResults.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
if (mStopping)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mStopping = true;
|
||||||
|
}
|
||||||
|
mCondition.notify_one();
|
||||||
|
if (mThread.joinable())
|
||||||
|
{
|
||||||
|
mThread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
V210UploadJob job{};
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
|
mCondition.wait(
|
||||||
|
lock,
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
return mStopping || !mJobs.empty();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mStopping && mJobs.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
job = mJobs.front();
|
||||||
|
mJobs.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
V210UploadResult result{};
|
||||||
|
result.feedIndex = job.feedIndex;
|
||||||
|
if (job.feed != nullptr && job.destination != nullptr)
|
||||||
|
{
|
||||||
|
result.copied = job.feed->readV210FrameInto(
|
||||||
|
job.frameCounter,
|
||||||
|
job.destination,
|
||||||
|
job.destinationSize,
|
||||||
|
&result.timing);
|
||||||
|
if (result.copied)
|
||||||
|
{
|
||||||
|
result.version = job.feed->frameVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
mResults.push_back(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mutex mMutex;
|
||||||
|
std::condition_variable mCondition;
|
||||||
|
std::deque<V210UploadJob> mJobs;
|
||||||
|
std::deque<V210UploadResult> mResults;
|
||||||
|
bool mStopping = false;
|
||||||
|
std::thread mThread;
|
||||||
|
};
|
||||||
|
|
||||||
struct FeedPerfStats
|
struct FeedPerfStats
|
||||||
{
|
{
|
||||||
uint64_t updates = 0;
|
uint64_t updates = 0;
|
||||||
@@ -842,8 +973,16 @@ int main(int argc, char* argv[])
|
|||||||
std::vector<bool> pendingUploadNeeded(feedCount);
|
std::vector<bool> pendingUploadNeeded(feedCount);
|
||||||
std::vector<bool> postFenceDirectV210Read(feedCount);
|
std::vector<bool> postFenceDirectV210Read(feedCount);
|
||||||
std::vector<double> feedUploadCredits(feedCount, 1.0);
|
std::vector<double> feedUploadCredits(feedCount, 1.0);
|
||||||
|
std::vector<bool> v210WorkerInFlight(feedCount);
|
||||||
|
std::unique_ptr<V210UploadWorker> v210UploadWorker;
|
||||||
|
std::vector<V210UploadResult> v210WorkerResults;
|
||||||
uint64_t lastUploadPaceTicks = SDL_GetPerformanceCounter();
|
uint64_t lastUploadPaceTicks = SDL_GetPerformanceCounter();
|
||||||
|
|
||||||
|
if (config.v210UploadWorker)
|
||||||
|
{
|
||||||
|
v210UploadWorker = std::make_unique<V210UploadWorker>();
|
||||||
|
}
|
||||||
|
|
||||||
std::fill(
|
std::fill(
|
||||||
uploadedVersions.begin(),
|
uploadedVersions.begin(),
|
||||||
uploadedVersions.end(),
|
uploadedVersions.end(),
|
||||||
@@ -1432,6 +1571,40 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto recordFeedUploadStats =
|
||||||
|
[&](uint32_t feedIndex)
|
||||||
|
{
|
||||||
|
if (!config.logPerf)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
++feedPerfStats[feedIndex].uploads;
|
||||||
|
|
||||||
|
const uint64_t uploadTicks =
|
||||||
|
SDL_GetPerformanceCounter();
|
||||||
|
if (feedPerfStats[feedIndex].lastUploadTicks != 0)
|
||||||
|
{
|
||||||
|
const uint64_t interval =
|
||||||
|
uploadTicks -
|
||||||
|
feedPerfStats[feedIndex].lastUploadTicks;
|
||||||
|
feedPerfStats[feedIndex].uploadIntervalTicks +=
|
||||||
|
interval;
|
||||||
|
feedPerfStats[feedIndex].minUploadIntervalTicks =
|
||||||
|
std::min(
|
||||||
|
feedPerfStats[feedIndex].minUploadIntervalTicks,
|
||||||
|
interval
|
||||||
|
);
|
||||||
|
feedPerfStats[feedIndex].maxUploadIntervalTicks =
|
||||||
|
std::max(
|
||||||
|
feedPerfStats[feedIndex].maxUploadIntervalTicks,
|
||||||
|
interval
|
||||||
|
);
|
||||||
|
++feedPerfStats[feedIndex].uploadIntervals;
|
||||||
|
}
|
||||||
|
feedPerfStats[feedIndex].lastUploadTicks = uploadTicks;
|
||||||
|
};
|
||||||
|
|
||||||
for (uint32_t i = 0; i < feedCount; ++i)
|
for (uint32_t i = 0; i < feedCount; ++i)
|
||||||
{
|
{
|
||||||
if (v210FeedReady[i] &&
|
if (v210FeedReady[i] &&
|
||||||
@@ -1500,6 +1673,54 @@ int main(int argc, char* argv[])
|
|||||||
framePerf.submitPresentTicks += elapsed;
|
framePerf.submitPresentTicks += elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.v210UploadWorker)
|
||||||
|
{
|
||||||
|
v210WorkerResults.clear();
|
||||||
|
v210UploadWorker->drainResults(v210WorkerResults);
|
||||||
|
|
||||||
|
for (const V210UploadResult& result : v210WorkerResults)
|
||||||
|
{
|
||||||
|
const uint32_t i = result.feedIndex;
|
||||||
|
if (i >= feedCount)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
v210WorkerInFlight[i] = false;
|
||||||
|
|
||||||
|
if (!result.copied)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool uploadNeeded =
|
||||||
|
uploadedVersions[i] != result.version;
|
||||||
|
recordFeedVersionStats(i, uploadNeeded);
|
||||||
|
|
||||||
|
if (!uploadNeeded)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingVersions[i] = result.version;
|
||||||
|
uploadedVersions[i] = result.version;
|
||||||
|
feedUploadNeeded[i] = true;
|
||||||
|
recordFeedUploadStats(i);
|
||||||
|
|
||||||
|
if (config.logPerf)
|
||||||
|
{
|
||||||
|
perfStats.workerV210SourceReadNs +=
|
||||||
|
result.timing.sourceReadNs;
|
||||||
|
perfStats.workerV210PayloadCopyNs +=
|
||||||
|
result.timing.payloadCopyNs;
|
||||||
|
framePerf.workerV210SourceReadNs +=
|
||||||
|
result.timing.sourceReadNs;
|
||||||
|
framePerf.workerV210PayloadCopyNs +=
|
||||||
|
result.timing.payloadCopyNs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
++frameCounter;
|
++frameCounter;
|
||||||
|
|
||||||
if (config.logFps)
|
if (config.logFps)
|
||||||
@@ -1615,6 +1836,42 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
if (directV210Read)
|
if (directV210Read)
|
||||||
{
|
{
|
||||||
|
if (config.v210UploadWorker)
|
||||||
|
{
|
||||||
|
if (!v210WorkerInFlight[i])
|
||||||
|
{
|
||||||
|
const size_t v210Bytes =
|
||||||
|
static_cast<size_t>(
|
||||||
|
feeds[i]->v210Stride()
|
||||||
|
) *
|
||||||
|
static_cast<size_t>(
|
||||||
|
feeds[i]->v210Height()
|
||||||
|
);
|
||||||
|
|
||||||
|
v210UploadWorker->enqueue(
|
||||||
|
V210UploadJob{
|
||||||
|
i,
|
||||||
|
frameCounter,
|
||||||
|
feeds[i].get(),
|
||||||
|
v210Feeds[i].v210MappedData,
|
||||||
|
v210Bytes
|
||||||
|
});
|
||||||
|
v210WorkerInFlight[i] = true;
|
||||||
|
++v210UploadsThisFrame;
|
||||||
|
|
||||||
|
if (config.paceUploads &&
|
||||||
|
feeds[i]->hasFrameRate())
|
||||||
|
{
|
||||||
|
feedUploadCredits[i] =
|
||||||
|
std::max(
|
||||||
|
0.0,
|
||||||
|
feedUploadCredits[i] - 1.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
V210ReadTiming directReadTiming{};
|
V210ReadTiming directReadTiming{};
|
||||||
const size_t v210Bytes =
|
const size_t v210Bytes =
|
||||||
static_cast<size_t>(
|
static_cast<size_t>(
|
||||||
@@ -1720,30 +1977,7 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
if (config.logPerf)
|
if (config.logPerf)
|
||||||
{
|
{
|
||||||
++feedPerfStats[i].uploads;
|
recordFeedUploadStats(i);
|
||||||
|
|
||||||
const uint64_t uploadTicks =
|
|
||||||
SDL_GetPerformanceCounter();
|
|
||||||
if (feedPerfStats[i].lastUploadTicks != 0)
|
|
||||||
{
|
|
||||||
const uint64_t interval =
|
|
||||||
uploadTicks -
|
|
||||||
feedPerfStats[i].lastUploadTicks;
|
|
||||||
feedPerfStats[i].uploadIntervalTicks +=
|
|
||||||
interval;
|
|
||||||
feedPerfStats[i].minUploadIntervalTicks =
|
|
||||||
std::min(
|
|
||||||
feedPerfStats[i].minUploadIntervalTicks,
|
|
||||||
interval
|
|
||||||
);
|
|
||||||
feedPerfStats[i].maxUploadIntervalTicks =
|
|
||||||
std::max(
|
|
||||||
feedPerfStats[i].maxUploadIntervalTicks,
|
|
||||||
interval
|
|
||||||
);
|
|
||||||
++feedPerfStats[i].uploadIntervals;
|
|
||||||
}
|
|
||||||
feedPerfStats[i].lastUploadTicks = uploadTicks;
|
|
||||||
}
|
}
|
||||||
feedUploadNeeded[i] = true;
|
feedUploadNeeded[i] = true;
|
||||||
}
|
}
|
||||||
@@ -2144,6 +2378,14 @@ int main(int argc, char* argv[])
|
|||||||
<< (static_cast<double>(
|
<< (static_cast<double>(
|
||||||
framePerf.directV210PayloadCopyNs) /
|
framePerf.directV210PayloadCopyNs) /
|
||||||
1000000.0)
|
1000000.0)
|
||||||
|
<< "ms v210WorkerRead="
|
||||||
|
<< (static_cast<double>(
|
||||||
|
framePerf.workerV210SourceReadNs) /
|
||||||
|
1000000.0)
|
||||||
|
<< "ms v210WorkerCopy="
|
||||||
|
<< (static_cast<double>(
|
||||||
|
framePerf.workerV210PayloadCopyNs) /
|
||||||
|
1000000.0)
|
||||||
<< "ms stageCopies="
|
<< "ms stageCopies="
|
||||||
<< framePerf.stageCopies
|
<< framePerf.stageCopies
|
||||||
<< " v210Copies="
|
<< " v210Copies="
|
||||||
@@ -2203,6 +2445,14 @@ int main(int argc, char* argv[])
|
|||||||
<< (static_cast<double>(
|
<< (static_cast<double>(
|
||||||
perfStats.directV210PayloadCopyNs) /
|
perfStats.directV210PayloadCopyNs) /
|
||||||
1000000.0 / frames)
|
1000000.0 / frames)
|
||||||
|
<< "ms v210WorkerRead="
|
||||||
|
<< (static_cast<double>(
|
||||||
|
perfStats.workerV210SourceReadNs) /
|
||||||
|
1000000.0 / frames)
|
||||||
|
<< "ms v210WorkerCopy="
|
||||||
|
<< (static_cast<double>(
|
||||||
|
perfStats.workerV210PayloadCopyNs) /
|
||||||
|
1000000.0 / frames)
|
||||||
<< "ms uploadRecord="
|
<< "ms uploadRecord="
|
||||||
<< (perfStats.uploadRecordTicks * invMs / frames)
|
<< (perfStats.uploadRecordTicks * invMs / frames)
|
||||||
<< "ms submitPresent="
|
<< "ms submitPresent="
|
||||||
@@ -2301,6 +2551,11 @@ int main(int argc, char* argv[])
|
|||||||
// Cleanup
|
// Cleanup
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
|
if (v210UploadWorker)
|
||||||
|
{
|
||||||
|
v210UploadWorker->stop();
|
||||||
|
}
|
||||||
|
|
||||||
vkDeviceWaitIdle(ctx.device());
|
vkDeviceWaitIdle(ctx.device());
|
||||||
|
|
||||||
ImGui_ImplVulkan_Shutdown();
|
ImGui_ImplVulkan_Shutdown();
|
||||||
|
|||||||
Reference in New Issue
Block a user