tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_PerformanceMeasurement.h
Go to the documentation of this file.
1 /*==============================================================================
2
3 Copyright 2016 by Tracktion Corporation.
4 For more information visit www.tracktion.com
5
6 ==============================================================================*/
7
8#pragma once
9
10#include <string>
11#include <chrono>
12#include <iostream>
13
14#ifdef __APPLE__
15 #include <sys/kdebug_signpost.h>
16 #include <os/signpost.h>
17#endif
18
19#include "../../tracktion_core/utilities/tracktion_CPU.h"
20
21namespace tracktion { inline namespace graph
22{
23
24//==============================================================================
25//==============================================================================
30{
32 ScopedSignpost (uint32_t signpostIndex)
33 : index (signpostIndex)
34 {
35 (void) index;
36 #ifdef __APPLE__
37 #pragma clang diagnostic push
38 #pragma clang diagnostic ignored "-Wdeprecated"
39 kdebug_signpost_start (index, 0, 0, 0, 0);
40 #pragma clang diagnostic pop
41 #endif
42 }
43
46 {
47 #ifdef __APPLE__
48 #pragma clang diagnostic push
49 #pragma clang diagnostic ignored "-Wdeprecated"
50 kdebug_signpost_end (index, 0, 0, 0, 0);
51 #pragma clang diagnostic pop
52 #endif
53 }
54
55private:
56 //==============================================================================
57 const uint32_t index;
58};
59
60
61#ifdef __APPLE__
62//==============================================================================
63//==============================================================================
64struct NamedSignpost
65{
66 NamedSignpost (const char* nameToUse)
67 : name (nameToUse)
68 {
69 #ifdef __APPLE__
70 if (__builtin_available (macOS 10.14, *))
71 os_signpost_interval_begin (getLog(), id, "", "%s", name);
72 #endif
73 }
74
75 ~NamedSignpost()
76 {
77 #ifdef __APPLE__
78 if (__builtin_available (macOS 10.14, *))
79 os_signpost_interval_end (getLog(), id, "", "%s", name);
80 #endif
81 }
82
83private:
84 [[ maybe_unused ]] const char* name;
85 #ifdef __APPLE__
86 const os_signpost_id_t id { generateID() };
87
88 static os_log_t getLog()
89 {
90 static os_log_t log;
91
92 if (__builtin_available (macOS 10.14, *))
93 if (log == nullptr)
94 log = os_log_create ("", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
95
96 return log;
97 }
98
99 static os_signpost_id_t generateID()
100 {
101 if (__builtin_available (macOS 10.14, *))
102 return os_signpost_id_generate (getLog());
103
104 return {};
105 }
106 #endif
107};
108#endif //__APPLE__
109
110
111//==============================================================================
112//==============================================================================
131{
132public:
133 //==============================================================================
141 int runsPerPrintout = 100,
142 bool printOnDestruction = true);
143
146
147 //==============================================================================
151 void start() noexcept;
152
160 bool stop();
161
163 void printStatistics();
164
167 {
168 Statistics() noexcept = default;
169
170 void clear() noexcept;
171 double getVarianceSeconds() const;
172 double getVarianceCycles() const;
173 std::string toString (const std::string& name) const;
174
175 void addResult (double secondsElapsed, uint64_t cyclesElapsed) noexcept;
176
177 double meanSeconds = 0.0;
178 double m2Seconds = 0.0;
179 double maximumSeconds = 0.0;
180 double minimumSeconds = 0.0;
181 double totalSeconds = 0.0;
182
183 double meanCycles = 0.0;
184 double m2Cycles = 0.0;
185 uint64_t maximumCycles = 0;
186 uint64_t minimumCycles = 0;
187 uint64_t totalCycles = 0;
188
189 int64_t numRuns = 0;
190 };
191
193 std::string getName() const;
194
197
200
201private:
202 //==============================================================================
203 Statistics stats;
204 std::string name;
205 int64_t runsPerPrint;
206 bool printOnDestruction;
208 uint64_t startCycles;
209};
210
211//==============================================================================
212//==============================================================================
217{
218public:
223 : performanceMeasurement (pm)
224 {
225 performanceMeasurement.start();
226 }
227
232 {
233 performanceMeasurement.stop();
234 }
235
236 PerformanceMeasurement& performanceMeasurement;
237};
238
239
240//==============================================================================
241// _ _ _ _
242// __| | ___ | |_ __ _ (_)| | ___
243// / _` | / _ \| __| / _` || || |/ __|
244// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
245// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
246//
247// Code beyond this point is implementation detail...
248//
249//==============================================================================
250
251inline PerformanceMeasurement::PerformanceMeasurement (std::string name_, int runsPerPrintout, bool shouldPrintOnDestruction)
252 : name (std::move (name_)), runsPerPrint (runsPerPrintout), printOnDestruction (shouldPrintOnDestruction)
253{
254}
255
257{
258 if (printOnDestruction && stats.numRuns > 0)
260}
261
262inline void PerformanceMeasurement::Statistics::clear() noexcept
263{
264 meanSeconds = m2Seconds = maximumSeconds = minimumSeconds = totalSeconds = 0;
265 meanCycles = m2Cycles = 0.0;
266 maximumCycles = minimumCycles = totalCycles = 0;
267 numRuns = 0;
268}
269
270inline void PerformanceMeasurement::Statistics::addResult (double secondsElapsed, uint64_t cyclesElapsed) noexcept
271{
272 if (numRuns == 0)
273 {
274 maximumSeconds = secondsElapsed;
275 minimumSeconds = secondsElapsed;
276
277 maximumCycles = cyclesElapsed;
278 minimumCycles = cyclesElapsed;
279 }
280 else
281 {
282 maximumSeconds = std::max (maximumSeconds, secondsElapsed);
283 minimumSeconds = std::min (minimumSeconds, secondsElapsed);
284
285 maximumCycles = std::max (maximumCycles, cyclesElapsed);
286 minimumCycles = std::min (minimumCycles, cyclesElapsed);
287 }
288
289 ++numRuns;
290 totalSeconds += secondsElapsed;
291 totalCycles += cyclesElapsed;
292
293 // Seconds
294 {
295 const double delta = secondsElapsed - meanSeconds;
296 meanSeconds += delta / (double) numRuns;
297 const double delta2 = secondsElapsed - meanSeconds;
298 m2Seconds += delta * delta2;
299 }
300
301 // Cycles
302 {
303 const auto delta = cyclesElapsed - meanCycles;
304 meanCycles += delta / (double) numRuns;
305 const double delta2 = cyclesElapsed - meanCycles;
306 m2Cycles += delta * delta2;
307 }
308}
309
310inline double PerformanceMeasurement::Statistics::getVarianceSeconds() const
311{
312 return numRuns > 0 ? (m2Seconds / (double) numRuns) : 0.0;
313}
314
315inline double PerformanceMeasurement::Statistics::getVarianceCycles() const
316{
317 return numRuns > 0 ? (m2Cycles / (double) numRuns) : 0.0;
318}
319
320inline std::string PerformanceMeasurement::Statistics::toString (const std::string& perfName) const
321{
322 auto timeToString = [] (double secs)
323 {
324 return std::to_string ((int64_t) (secs * (secs < 0.01 ? 1000000.0 : 1000.0) + 0.5))
325 + (secs < 0.01 ? " us" : " ms");
326 };
327
328 std::string s = "Performance count for \"" + perfName + "\" over " + std::to_string (numRuns) + " run(s)\n"
329 + "\t Seconds: Mean = " + timeToString (meanSeconds)
330 + ", min = " + timeToString (minimumSeconds)
331 + ", max = " + timeToString (maximumSeconds)
332 + ", SD = " + timeToString (std::sqrt (getVarianceSeconds()))
333 + ", total = " + timeToString (totalSeconds) + "\n"
334 + "\t Cycles: Mean = " + std::to_string (meanCycles)
335 + ", min = " + std::to_string (minimumCycles)
336 + ", max = " + std::to_string (maximumCycles)
337 + ", SD = " + std::to_string (std::sqrt (getVarianceCycles()))
338 + ", total = " + std::to_string (totalCycles) + "\n";
339
340 return s;
341}
342
343inline void PerformanceMeasurement::start() noexcept
344{
346 startCycles = rdtsc();
347}
348
350{
351 const auto elapsedSeconds = std::chrono::high_resolution_clock::now() - startTime;
352 const auto elapsedCycles = rdtsc() - startCycles;
353 stats.addResult (std::chrono::duration<double, std::ratio<1, 1>> (elapsedSeconds).count(),
354 elapsedCycles);
355
356 if (runsPerPrint < 0)
357 return false;
358
359 if (stats.numRuns < runsPerPrint)
360 return false;
361
363 return true;
364}
365
367{
368 const auto desc = getStatisticsAndReset().toString (name);
369 std::cout << (desc);
370}
371
373{
374 return name;
375}
376
381
383{
384 Statistics s (stats);
385 stats.clear();
386
387 return s;
388}
389
390}}
A timer for measuring performance of code.
Statistics getStatisticsAndReset()
Returns a copy of the current stats, and resets the internal counter.
bool stop()
Stops timing and prints out the results.
PerformanceMeasurement(std::string counterName, int runsPerPrintout=100, bool printOnDestruction=true)
Creates a PerformanceMeasurement object.
void printStatistics()
Dumps the current metrics to std::cout.
Statistics getStatistics() const
Returns a copy of the current stats.
RAII wrapper to start and stop a performance measurement.
ScopedPerformanceMeasurement(PerformanceMeasurement &pm)
Constructor.
log
typedef double
T max(T... args)
T min(T... args)
T sqrt(T... args)
typedef uint32_t
A macOS specific class to start/stop a signpost for use in Instruments.
ScopedSignpost(uint32_t signpostIndex)
Starts a signpost with a given index.
~ScopedSignpost()
Stops the signpost previously started.
T to_string(T... args)