Profiler measuring detector costs with SHARED FFT context This measures ACTUAL detector overhead by using differential measurement: cost(A+B) - cost(A) = overhead of B All detector share the same Context and FFT cache.
| 113 | // cost(A+B) - cost(A) = overhead of B |
| 114 | // All detector share the same Context and FFT cache. |
| 115 | int runProfiler(bool jsonOutput) { |
| 116 | const int ITERATIONS = 500; |
| 117 | const int SAMPLE_RATE = 16000; |
| 118 | |
| 119 | fl::vector<DetectorResult> results; |
| 120 | SynthAudioGenerator baselineGen(SAMPLE_RATE); |
| 121 | |
| 122 | // Strategy: Measure baseline, then incremental costs |
| 123 | // by adding detector one at a time to the SAME processor |
| 124 | // This ensures FFT is cached and shared across all measurements |
| 125 | |
| 126 | // Create a SINGLE processor to measure incremental costs |
| 127 | // All measurements use the SAME Context and FFT cache |
| 128 | fl::audio::Processor processor; |
| 129 | processor.setSampleRate(SAMPLE_RATE); |
| 130 | |
| 131 | // ===== BASELINE: Energy Analyzer Only ===== |
| 132 | fl::u32 baselineTotal_us = 0; |
| 133 | { |
| 134 | processor.onEnergy([](float) {}); |
| 135 | |
| 136 | // Warm-up |
| 137 | for (int i = 0; i < 20; i++) { |
| 138 | processor.update(baselineGen.generateSample()); |
| 139 | } |
| 140 | |
| 141 | fl::u32 t0 = fl::micros(); |
| 142 | for (int i = 0; i < ITERATIONS; i++) { |
| 143 | processor.update(baselineGen.generateSample()); |
| 144 | } |
| 145 | fl::u32 t1 = fl::micros(); |
| 146 | baselineTotal_us = t1 - t0; |
| 147 | |
| 148 | results.push_back({"EnergyAnalyzer (BASELINE)", baselineTotal_us, ITERATIONS}); |
| 149 | } |
| 150 | |
| 151 | // ===== Add Beat (differential measurement) ===== |
| 152 | { |
| 153 | processor.onBeat([]() {}); |
| 154 | |
| 155 | fl::u32 t0 = fl::micros(); |
| 156 | for (int i = 0; i < ITERATIONS; i++) { |
| 157 | processor.update(baselineGen.generateSample()); |
| 158 | } |
| 159 | fl::u32 t1 = fl::micros(); |
| 160 | fl::u32 deltaUs = (t1 - t0) - baselineTotal_us; |
| 161 | |
| 162 | results.push_back({"+ Beat (overhead)", deltaUs, ITERATIONS}); |
| 163 | } |
| 164 | |
| 165 | // ===== Add TempoAnalyzer (differential) ===== |
| 166 | { |
| 167 | processor.onTempo([](float) {}); |
| 168 | |
| 169 | fl::u32 t0 = fl::micros(); |
| 170 | for (int i = 0; i < ITERATIONS; i++) { |
| 171 | processor.update(baselineGen.generateSample()); |
| 172 | } |
no test coverage detected