diff --git a/modules/juce_core/time/juce_PerformanceCounter.cpp b/modules/juce_core/time/juce_PerformanceCounter.cpp index 64da598ae1..a071665319 100644 --- a/modules/juce_core/time/juce_PerformanceCounter.cpp +++ b/modules/juce_core/time/juce_PerformanceCounter.cpp @@ -26,71 +26,107 @@ ============================================================================== */ -PerformanceCounter::PerformanceCounter (const String& name_, - const int runsPerPrintout, - const File& loggingFile) - : name (name_), - numRuns (0), - runsPerPrint (runsPerPrintout), - totalTime (0), - started (0), - outputFile (loggingFile) +static void appendToFile (const File& f, const String& s) { - if (outputFile != File::nonexistent) + if (f != File::nonexistent) { - String s ("**** Counter for \""); - s << name_ << "\" started at: " - << Time::getCurrentTime().toString (true, true) - << newLine; + FileOutputStream out (f); - outputFile.appendText (s, false, false); + if (! out.failedToOpen()) + out << s << newLine; } } +PerformanceCounter::PerformanceCounter (const String& name, int runsPerPrintout, const File& loggingFile) + : runsPerPrint (runsPerPrintout), startTime (0), outputFile (loggingFile) +{ + stats.name = name; + appendToFile (outputFile, "**** Counter for \"" + name + "\" started at: " + Time::getCurrentTime().toString (true, true)); +} + PerformanceCounter::~PerformanceCounter() { printStatistics(); } -void PerformanceCounter::start() +PerformanceCounter::Statistics::Statistics() noexcept + : averageSeconds(), maximumSeconds(), minimumSeconds(), totalSeconds(), numRuns() { - started = Time::getHighResolutionTicks(); } -void PerformanceCounter::stop() +void PerformanceCounter::Statistics::clear() noexcept { - const int64 now = Time::getHighResolutionTicks(); + averageSeconds = maximumSeconds = minimumSeconds = totalSeconds = 0; + numRuns = 0; +} - totalTime += 1000.0 * Time::highResolutionTicksToSeconds (now - started); +void PerformanceCounter::Statistics::addResult (double elapsed) noexcept +{ + if (numRuns == 0) + { + maximumSeconds = elapsed; + minimumSeconds = elapsed; + } + else + { + maximumSeconds = jmax (maximumSeconds, elapsed); + minimumSeconds = jmin (minimumSeconds, elapsed); + } - if (++numRuns == runsPerPrint) - printStatistics(); + ++numRuns; + totalSeconds += elapsed; +} + +static String timeToString (double secs) +{ + return String ((int64) (secs * (secs < 0.01 ? 1000000.0 : 1000.0) + 0.5)) + + (secs < 0.01 ? " microsecs" : " millisecs"); +} + +String PerformanceCounter::Statistics::toString() const +{ + MemoryOutputStream s; + + s << "Performance count for \"" << name << "\" over " << numRuns << " run(s)" << newLine + << "Average = " << timeToString (averageSeconds) + << ", minimum = " << timeToString (minimumSeconds) + << ", maximum = " << timeToString (maximumSeconds) + << ", total = " << timeToString (totalSeconds); + + return s.toString(); +} + +void PerformanceCounter::start() noexcept +{ + startTime = Time::getHighResolutionTicks(); +} + +bool PerformanceCounter::stop() +{ + stats.addResult (Time::highResolutionTicksToSeconds (Time::getHighResolutionTicks() - startTime)); + + if (stats.numRuns < runsPerPrint) + return false; + + printStatistics(); + return true; } void PerformanceCounter::printStatistics() { - if (numRuns > 0) - { - String s ("Performance count for \""); - s << name << "\" - average over " << numRuns << " run(s) = "; + const String desc (getStatisticsAndReset().toString()); - const int micros = (int) (totalTime * (1000.0 / numRuns)); - - if (micros > 10000) - s << (micros/1000) << " millisecs"; - else - s << micros << " microsecs"; - - s << ", total = " << String (totalTime / 1000, 5) << " seconds"; - - Logger::outputDebugString (s); - - s << newLine; - - if (outputFile != File::nonexistent) - outputFile.appendText (s, false, false); - - numRuns = 0; - totalTime = 0; - } + Logger::outputDebugString (desc); + appendToFile (outputFile, desc); +} + +PerformanceCounter::Statistics PerformanceCounter::getStatisticsAndReset() +{ + Statistics s (stats); + stats.clear(); + + if (s.numRuns > 0) + s.averageSeconds = s.totalSeconds / s.numRuns; + + return s; } diff --git a/modules/juce_core/time/juce_PerformanceCounter.h b/modules/juce_core/time/juce_PerformanceCounter.h index 9d629ea2d3..81db85636e 100644 --- a/modules/juce_core/time/juce_PerformanceCounter.h +++ b/modules/juce_core/time/juce_PerformanceCounter.h @@ -72,10 +72,9 @@ public: //============================================================================== /** Starts timing. - @see stop */ - void start(); + void start() noexcept; /** Stops timing and prints out the results. @@ -84,7 +83,7 @@ public: @see start */ - void stop(); + bool stop(); /** Dumps the current metrics to the debugger output and to a file. @@ -94,13 +93,35 @@ public: */ void printStatistics(); + /** Holds the current statistics. */ + struct Statistics + { + Statistics() noexcept; + + void clear() noexcept; + String toString() const; + + void addResult (double elapsed) noexcept; + + String name; + double averageSeconds; + double maximumSeconds; + double minimumSeconds; + double totalSeconds; + int64 numRuns; + }; + + /** Returns a copy of the current stats, and resets the internal counter. */ + Statistics getStatisticsAndReset(); + private: //============================================================================== - String name; - int numRuns, runsPerPrint; - double totalTime; - int64 started; + Statistics stats; + int64 runsPerPrint, startTime; File outputFile; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PerformanceCounter) }; + #endif // JUCE_PERFORMANCECOUNTER_H_INCLUDED