perf(window): ring buffer for CRAFTER_TIMING frame times (#44) #76
2 changed files with 26 additions and 17 deletions
perf(window): ring buffer for CRAFTER_TIMING frame times (#44)
Replace the std::vector<nanoseconds> frameTimes plus erase(begin()) with a fixed-size std::array ring buffer (head + count). The previous code memmoved ~99 elements left every frame once the window filled. LogTiming computes order-independent sum/avg/min/max, so the ring's write order is irrelevant to the reported stats. Behind CRAFTER_TIMING only; shipping builds are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
commit
41d99890c1
|
|
@ -657,11 +657,12 @@ void Window::Update() {
|
||||||
#ifdef CRAFTER_TIMING
|
#ifdef CRAFTER_TIMING
|
||||||
frameEnd = std::chrono::high_resolution_clock::now();
|
frameEnd = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
frameTimes.push_back(totalUpdate+totalRender);
|
// Ring buffer: overwrite the oldest entry once full. Order doesn't matter
|
||||||
|
// to LogTiming, so we never need to shift elements.
|
||||||
// Keep only the last 100 frame times
|
frameTimes[frameTimesHead] = totalUpdate+totalRender;
|
||||||
if (frameTimes.size() > 100) {
|
frameTimesHead = (frameTimesHead + 1) % frameTimeCapacity;
|
||||||
frameTimes.erase(frameTimes.begin());
|
if (frameTimesCount < frameTimeCapacity) {
|
||||||
|
++frameTimesCount;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
lastFrameBegin = startTime;
|
lastFrameBegin = startTime;
|
||||||
|
|
@ -843,21 +844,22 @@ void Window::LogTiming() {
|
||||||
std::cout << std::format("Total: {}", duration_cast<std::chrono::milliseconds>(totalUpdate+totalRender)) << std::endl;
|
std::cout << std::format("Total: {}", duration_cast<std::chrono::milliseconds>(totalUpdate+totalRender)) << std::endl;
|
||||||
std::cout << std::format("Vblank: {}", duration_cast<std::chrono::milliseconds>(vblank)) << std::endl;
|
std::cout << std::format("Vblank: {}", duration_cast<std::chrono::milliseconds>(vblank)) << std::endl;
|
||||||
|
|
||||||
// Add 100-frame average and min-max timing info
|
// Add 100-frame average and min-max timing info. Only the first
|
||||||
if (!frameTimes.empty()) {
|
// frameTimesCount entries of the ring buffer hold valid samples.
|
||||||
|
if (frameTimesCount != 0) {
|
||||||
// Calculate average
|
// Calculate average
|
||||||
std::chrono::nanoseconds sum(0);
|
std::chrono::nanoseconds sum(0);
|
||||||
for (const auto& frameTime : frameTimes) {
|
for (std::size_t i = 0; i < frameTimesCount; ++i) {
|
||||||
sum += frameTime;
|
sum += frameTimes[i];
|
||||||
}
|
}
|
||||||
auto average = sum / frameTimes.size();
|
auto average = sum / frameTimesCount;
|
||||||
|
|
||||||
// Find min and max
|
// Find min and max
|
||||||
auto min = frameTimes.front();
|
auto min = frameTimes[0];
|
||||||
auto max = frameTimes.front();
|
auto max = frameTimes[0];
|
||||||
for (const auto& frameTime : frameTimes) {
|
for (std::size_t i = 0; i < frameTimesCount; ++i) {
|
||||||
if (frameTime < min) min = frameTime;
|
if (frameTimes[i] < min) min = frameTimes[i];
|
||||||
if (frameTime > max) max = frameTime;
|
if (frameTimes[i] > max) max = frameTimes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::format("Last 100 Frame Times - Avg: {}, Min: {}, Max: {}",
|
std::cout << std::format("Last 100 Frame Times - Avg: {}, Min: {}, Max: {}",
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,14 @@ export namespace Crafter {
|
||||||
std::chrono::nanoseconds vblank;
|
std::chrono::nanoseconds vblank;
|
||||||
std::chrono::nanoseconds totalFrame;
|
std::chrono::nanoseconds totalFrame;
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> frameEnd;
|
std::chrono::time_point<std::chrono::high_resolution_clock> frameEnd;
|
||||||
std::vector<std::chrono::nanoseconds> frameTimes;
|
// Fixed-size ring buffer of the most recent frame times. LogTiming does
|
||||||
|
// order-independent sum/avg/min/max, so head position is irrelevant to
|
||||||
|
// the reported stats; this avoids the per-frame memmove a vector::erase
|
||||||
|
// at the front would incur once full.
|
||||||
|
static constexpr std::size_t frameTimeCapacity = 100;
|
||||||
|
std::array<std::chrono::nanoseconds, frameTimeCapacity> frameTimes{};
|
||||||
|
std::size_t frameTimesHead = 0;
|
||||||
|
std::size_t frameTimesCount = 0;
|
||||||
void LogTiming();
|
void LogTiming();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue