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.

146 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 look lasting minTime seconds.
  36. * When done, prints out statistics.
  37. */
  38. static void run(const char * name, std::function<T()> func, float minTime)
  39. {
  40. int64_t iterations;
  41. bool done = false;
  42. //keep increasing the number of iterations until we last at least minTime seconds
  43. for (iterations = 100; !done; iterations *= 2) {
  44. double elapsed = measureTimeSub(func, iterations);
  45. if (elapsed >= minTime) {
  46. double itersPerSec = iterations / elapsed;
  47. double full = 44100;
  48. double percent = full * 100 / itersPerSec;
  49. printf("\nmeasure %s over time %f\n", name, minTime);
  50. printf("did %" PRId64 " iterations in %f seconds\n", iterations, elapsed);
  51. printf("that's %f per sec\n", itersPerSec);
  52. printf("percent CPU usage: %f\n", percent);
  53. printf("best case instances: %f\n", 100 / percent);
  54. printf("quota used per 1 percent : %f\n", percent * 100);
  55. fflush(stdout);
  56. done = true;
  57. }
  58. }
  59. }
  60. /**
  61. * Run test iterators time, return total seconds.
  62. */
  63. static double measureTimeSub(std::function<T()> func, int64_t iterations)
  64. {
  65. const double t0 = SqTime::seconds();
  66. for (int64_t i = 0; i < iterations; ++i) {
  67. const T x = func();
  68. TestBuffers<T>::put(x);
  69. }
  70. const double t1 = SqTime::seconds();
  71. const double elapsed = t1 - t0;
  72. return elapsed;
  73. }
  74. };
  75. /**
  76. * Simple producer / consumer for test data.
  77. * Serves up a precalculated list of random numbers.
  78. */
  79. template <typename T>
  80. class TestBuffers
  81. {
  82. public:
  83. static const size_t size = 60000;
  84. static void put(T x)
  85. {
  86. destData[destIndex++] = x;
  87. if (destIndex >= size) {
  88. destIndex = 0;
  89. }
  90. }
  91. static T get()
  92. {
  93. T ret = sourceData[sourceIndex++];
  94. if (sourceIndex >= size) {
  95. sourceIndex = 0;
  96. }
  97. return ret;
  98. }
  99. //
  100. TestBuffers()
  101. {
  102. for (int i = 0; i < size; ++i) {
  103. sourceData[i] = (float) rand() / (float) RAND_MAX;
  104. }
  105. }
  106. private:
  107. static size_t sourceIndex;
  108. static size_t destIndex;
  109. static T sourceData[size];
  110. static T destData[size];
  111. };
  112. template <typename T>
  113. T TestBuffers<T>::sourceData[size];
  114. template <typename T>
  115. T TestBuffers<T>::destData[size];
  116. template <typename T>
  117. size_t TestBuffers<T>::sourceIndex = 0;
  118. template <typename T>
  119. size_t TestBuffers<T>::destIndex = 512;
  120. /**
  121. * Simple timer implementation for running inside Visual Studio
  122. */