You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
4.2KB

  1. #pragma once
  2. #include <functional>
  3. #define __STDC_FORMAT_MACROS
  4. #include <inttypes.h>
  5. #include "TimeStatsCollector.h"
  6. template <typename T>
  7. class TestBuffers;
  8. /**
  9. * class MeasureTime.
  10. *
  11. * Used to estimate the amount of time a function takes to execute.
  12. * Will run the function over and over in a tight loop. Return value of function
  13. * is saved to testBuffers. Otherwise the compiler might optimize the whole thing away.
  14. * Usually ends by printing out the data.
  15. *
  16. * One of that statistics printed out is "quota used per 1 percent". Here we are arbitrarily
  17. * stating that a synthesizer module "should" use only one percent of the available audio processing CPU.
  18. * This won't be the case for all plugins/developers, but certainly is a plausible benchmark.
  19. *
  20. * A big caveat to all this is that code running inside VCV Rack will most likely run slower than the
  21. * same code running in at right loop. Some reasons are:
  22. * - VCV's audio processing thread probably has some internal overheard, so
  23. * it's unlikely that modules will get 100% of one core.
  24. * - In a tight loop all the data you code references will probably end up in fast on-chip
  25. * cache memory. In VCV your step function is called once, then all the other module's step
  26. * functions are called. This may force your data out of cache.
  27. */
  28. template <typename T>
  29. class MeasureTime
  30. {
  31. public:
  32. MeasureTime() = delete; // we are only static
  33. /**
  34. * Executes function "func" and measures how long it takes.
  35. * Will call func in a tight loop lasting minTime seconds.
  36. * When done, prints out statistics.
  37. *
  38. * returns - percent used
  39. */
  40. static double run(double overhead, const char * name, std::function<T()> func, float minTime)
  41. {
  42. int64_t iterations;
  43. bool done = false;
  44. double percent = 0;
  45. //keep increasing the number of iterations until we last at least minTime seconds
  46. for (iterations = 100; !done; iterations *= 2) {
  47. double elapsed = measureTimeSub(func, iterations);
  48. if (elapsed >= minTime) {
  49. double itersPerSec = iterations / elapsed;
  50. double full = 44100;
  51. percent = full * 100 / itersPerSec;
  52. percent -= overhead;
  53. printf("\nmeasure %s over time %f\n", name, minTime);
  54. printf("did %" PRId64 " iterations in %f seconds\n", iterations, elapsed);
  55. printf("that's %f per sec\n", itersPerSec);
  56. printf("percent CPU usage: %f\n", percent);
  57. printf("best case instances: %f\n", 100 / percent);
  58. printf("quota used per 1 percent : %f\n", percent * 100);
  59. fflush(stdout);
  60. done = true;
  61. }
  62. }
  63. return percent;
  64. }
  65. /**
  66. * Run test iterators time, return total seconds.
  67. */
  68. static double measureTimeSub(std::function<T()> func, int64_t iterations)
  69. {
  70. const double t0 = SqTime::seconds();
  71. for (int64_t i = 0; i < iterations; ++i) {
  72. const T x = func();
  73. TestBuffers<T>::put(x);
  74. }
  75. const double t1 = SqTime::seconds();
  76. const double elapsed = t1 - t0;
  77. return elapsed;
  78. }
  79. };
  80. /**
  81. * Simple producer / consumer for test data.
  82. * Serves up a pre-calculated list of random numbers.
  83. */
  84. template <typename T>
  85. class TestBuffers
  86. {
  87. public:
  88. static const size_t size = 60000;
  89. static void put(T x)
  90. {
  91. destData[destIndex++] = x;
  92. if (destIndex >= size) {
  93. destIndex = 0;
  94. }
  95. }
  96. static T get()
  97. {
  98. T ret = sourceData[sourceIndex++];
  99. if (sourceIndex >= size) {
  100. sourceIndex = 0;
  101. }
  102. return ret;
  103. }
  104. //
  105. TestBuffers()
  106. {
  107. for (int i = 0; i < size; ++i) {
  108. sourceData[i] = (float) rand() / (float) RAND_MAX;
  109. }
  110. }
  111. private:
  112. static size_t sourceIndex;
  113. static size_t destIndex;
  114. static T sourceData[size];
  115. static T destData[size];
  116. };
  117. template <typename T>
  118. T TestBuffers<T>::sourceData[size];
  119. template <typename T>
  120. T TestBuffers<T>::destData[size];
  121. template <typename T>
  122. size_t TestBuffers<T>::sourceIndex = 0;
  123. template <typename T>
  124. size_t TestBuffers<T>::destIndex = 512;