/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ThroughputCalculator.hpp Date: 2022-12-06 Author: Reece ***/ #pragma once namespace Aurora::Utility { struct ThroughputCalculator { // call me arbitrarily double inline OnUpdate(AuUInt uUnit) { AU_LOCK_GUARD(this->lock); OnTick(uUnit); return this->dCurFreq; } // then call me arbitrarily: double inline GetEstimatedHertz() { AU_LOCK_GUARD(this->lock); auto uNow = Aurora::Time::SteadyClockNS(); auto uDelta = uNow - this->uLast; // we cannot do anything on frame zero if (!this->dCurFreq) { return 0; } return this->dCurFreq; } AuUInt inline GetTotalStats() { return this->uTotalLifetime; } AuInt64 inline GetLastFrameTimeWall() { return this->uLastWall; } private: void inline OnTick(AuUInt64 uUnit) { struct EntryTable { AuUInt32 uBits {}; AuUInt32 uTimeDelta {}; }; auto uNow = Aurora::Time::SteadyClockNS(); auto uDelta = uNow - this->uLast; AuMemmove(uVecTable + 1, uVecTable, sizeof(uVecTable) - sizeof(*uVecTable)); auto pTable = ((EntryTable *)uVecTable); bool bFirst = !this->uLast; this->uLast = uNow; if (bFirst) { return; } this->uLastWall = Aurora::Time::CurrentClockMS(); static const auto kOneSecond = AuMSToNS(AuSToMS(1)); pTable[0].uBits = (AuUInt32)uUnit; pTable[0].uTimeDelta = (AuUInt32)(uDelta / 1000ull); if (!pTable[0].uTimeDelta) { pTable[0].uTimeDelta = 1; } if (uVecSize < 10) { uVecSize++; } AuLogDbg("Added: {} {}", pTable[0].uBits, pTable[0].uTimeDelta * 1000ull); double dTotal {}; double dTotalBits {}; double dTotalTime {}; double dSamples {}; for (AU_ITR_N(i, uVecSize)) { if (!pTable[i].uTimeDelta) { pTable[i].uTimeDelta = 1; } double dDeltaSeconds = ((double)((AuUInt64)pTable[i].uTimeDelta * 1000ull) / (double)kOneSecond); dTotalBits += pTable[i].uBits; dTotalTime += dDeltaSeconds; dTotal += (double)pTable[i].uBits / dDeltaSeconds; dSamples++; } AuLogDbg("{}/{} ({})", dTotal, dSamples, uVecSize); this->dCurFreq = dTotal / dSamples; double a = dTotalBits / dTotalTime; //if (this->dCurFreq > a) //{ //} //this->dCurFreq = AuMin(a, this->dCurFreq); } AuUInt8 uVecSize {}; AuUInt64 uVecTable[10]; AuThreadPrimitives::SpinLock lock; AuUInt64 uLast {}; AuUInt uTotalLifetime {}; AuInt64 uLastWall {}; double dCurFreq {}; }; }