commit c9b4b39514938f9ac50bc8ae4706f31eca3cef45
parent 6ab2359b98a1b06fa9ddbb0ee8acf098a6f112c4
Author: Matt Demanett <matt@demanett.net>
Date: Sun, 3 Dec 2017 02:08:41 -0500
Create benchmarks (performance tests) on dsp routines; some trivial optimization; bug fixes.
Diffstat:
10 files changed, 202 insertions(+), 24 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -32,3 +32,4 @@
*.app
dist/
+benchmark
diff --git a/Makefile b/Makefile
@@ -1,9 +1,16 @@
SOURCES = $(wildcard src/*.cpp src/dsp/*cpp)
+CXXFLAGS += -Isrc/dsp
include ../../plugin.mk
-CXXFLAGS += -Isrc/dsp
+BENCHMARK_SOURCES = $(wildcard benchmarks/*.cpp src/dsp/*cpp)
+BENCHMARK_OBJECTS = $(patsubst %, build/%.o, $(BENCHMARK_SOURCES))
+benchmark: $(BENCHMARK_OBJECTS)
+ $(CXX) -o $@ $^ ../../build/src/util.cpp.o -lbenchmark
+benchmark_clean:
+ rm -f benchmark
+clean: benchmark_clean
dist: all
mkdir -p dist/BogaudioModules
diff --git a/benchmarks/analyzer.cpp b/benchmarks/analyzer.cpp
@@ -0,0 +1,104 @@
+
+#include <benchmark/benchmark.h>
+
+#include <dsp.hpp>
+
+using namespace bogaudio::dsp;
+
+static void BM_HanningWindowInit(benchmark::State& state) {
+ for (auto _ : state) {
+ delete new HanningWindow(1024);
+ }
+}
+BENCHMARK(BM_HanningWindowInit);
+
+static void BM_HanningWindowApply(benchmark::State& state) {
+ const int n = 1024;
+ HanningWindow w(n);
+ float in[n];
+ std::fill_n(in, n, 1.1);
+ float out[n] {};
+ for (auto _ : state) {
+ w.apply(in, out);
+ in[0] = out[0]; // prevents the call from being optimized away?
+ }
+}
+BENCHMARK(BM_HanningWindowApply);
+
+static void BM_CompileTimeFFT1024(benchmark::State& state) {
+ FFT1024 fft;
+ const int n = 1024;
+ float in[n];
+ std::fill_n(in, n, 1.1);
+ float out[n] {};
+ for (auto _ : state) {
+ fft.do_fft(out, in);
+ }
+}
+BENCHMARK(BM_CompileTimeFFT1024);
+
+static void BM_RuntimeFFT1024(benchmark::State& state) {
+ const int n = 1024;
+ ffft::FFTReal<float> fft(n);
+ float in[n];
+ std::fill_n(in, n, 1.1);
+ float out[n] {};
+ for (auto _ : state) {
+ fft.do_fft(out, in);
+ }
+}
+BENCHMARK(BM_RuntimeFFT1024);
+
+static void BM_SpectrumAnalyzerStep(benchmark::State& state) {
+ SpectrumAnalyzer sa(
+ SpectrumAnalyzer::SIZE_1024,
+ SpectrumAnalyzer::OVERLAP_1,
+ SpectrumAnalyzer::WINDOW_HANNING,
+ 44100.0
+ );
+ float in[8] = { 0.0, 0.7, 1.0, 0.7, 0.0, -0.7, -1.0, -0.7 };
+ int i = 0;
+ for (auto _ : state) {
+ sa.step(in[i]);
+ i = ++i % 8;
+ }
+}
+BENCHMARK(BM_SpectrumAnalyzerStep);
+
+static void BM_SpectrumAnalyzerProcess(benchmark::State& state) {
+ SpectrumAnalyzer sa(
+ SpectrumAnalyzer::SIZE_1024,
+ SpectrumAnalyzer::OVERLAP_1,
+ SpectrumAnalyzer::WINDOW_HANNING,
+ 44100.0
+ );
+ float in[8] = { 0.0, 0.7, 1.0, 0.7, 0.0, -0.7, -1.0, -0.7 };
+ for (int i = 0; i < 1024; ++i) {
+ sa.step(in[i % 8]);
+ }
+
+ for (auto _ : state) {
+ sa.process(sa._samples);
+ }
+}
+BENCHMARK(BM_SpectrumAnalyzerProcess);
+
+static void BM_SpectrumAnalyzerGetMagnitudes(benchmark::State& state) {
+ SpectrumAnalyzer sa(
+ SpectrumAnalyzer::SIZE_1024,
+ SpectrumAnalyzer::OVERLAP_1,
+ SpectrumAnalyzer::WINDOW_HANNING,
+ 44100.0
+ );
+ const int nBins = 256;
+ float bins[nBins];
+ float in[8] = { 0.0, 0.7, 1.0, 0.7, 0.0, -0.7, -1.0, -0.7 };
+ for (int i = 0; i < 1024; ++i) {
+ sa.step(in[i % 8]);
+ }
+
+ for (auto _ : state) {
+ sa.getMagnitudes(bins, nBins);
+ }
+}
+BENCHMARK(BM_SpectrumAnalyzerGetMagnitudes);
diff --git a/benchmarks/buffer.cpp b/benchmarks/buffer.cpp
@@ -0,0 +1,20 @@
+
+#include <benchmark/benchmark.h>
+
+#include <dsp.hpp>
+
+using namespace bogaudio::dsp;
+
+struct BMOverlappingBuffer : OverlappingBuffer<float> {
+ BMOverlappingBuffer(int size, int o) : OverlappingBuffer(size, o) {}
+ virtual void process(float* samples) {}
+};
+
+static void BM_OverlappingBuffer(benchmark::State& state) {
+ BMOverlappingBuffer b(1024, 2);
+ int i = 0;
+ for (auto _ : state) {
+ b.step(i++);
+ }
+}
+BENCHMARK(BM_OverlappingBuffer);
diff --git a/benchmarks/main.cpp b/benchmarks/main.cpp
@@ -0,0 +1,4 @@
+
+#include <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/benchmarks/noise.cpp b/benchmarks/noise.cpp
@@ -0,0 +1,38 @@
+
+#include <benchmark/benchmark.h>
+
+#include <dsp.hpp>
+
+using namespace bogaudio::dsp;
+
+static void BM_WhiteNoise(benchmark::State& state) {
+ WhiteNoiseGenerator g;
+ for (auto _ : state) {
+ g.next();
+ }
+}
+BENCHMARK(BM_WhiteNoise);
+
+static void BM_PinkNoise(benchmark::State& state) {
+ PinkNoiseGenerator g;
+ for (auto _ : state) {
+ g.next();
+ }
+}
+BENCHMARK(BM_PinkNoise);
+
+static void BM_RedNoise(benchmark::State& state) {
+ RedNoiseGenerator g;
+ for (auto _ : state) {
+ g.next();
+ }
+}
+BENCHMARK(BM_RedNoise);
+
+static void BM_GaussianNoise(benchmark::State& state) {
+ GaussianNoiseGenerator g;
+ for (auto _ : state) {
+ g.next();
+ }
+}
+BENCHMARK(BM_GaussianNoise);
diff --git a/src/Analyzer.cpp b/src/Analyzer.cpp
@@ -21,10 +21,10 @@ struct ChannelAnalyzer : bogaudio::dsp::SpectrumAnalyzer {
: bogaudio::dsp::SpectrumAnalyzer(size, overlap, windowType, sampleRate)
, _averageN(averageN)
, _binsN(size / 2)
+ , _bins(new float[size] {})
+ , _frames(new float[_averageN * _binsN] {})
, _currentFrame(0)
{
- _bins = new float[size] { 0.0 };
- _frames = new float[_averageN * _binsN] { 0.0 };
}
virtual ~ChannelAnalyzer() {
delete[] _bins;
diff --git a/src/dsp/analyzer.hpp b/src/dsp/analyzer.hpp
@@ -13,18 +13,18 @@ struct Window {
Window(int size)
: _size(size)
- , _window(new float[_size] { 0.0 })
+ , _window(new float[_size] {})
, _sum(0.0)
{}
virtual ~Window() {
delete[] _window;
}
- virtual float sum() {
+ float sum() {
return _sum;
}
- virtual void apply(float* in, float* out) {
+ void apply(float* in, float* out) {
for (int i = 0; i < _size; ++i) {
out[i] = in[i] * _window[i];
}
@@ -164,31 +164,29 @@ struct SpectrumAnalyzer : OverlappingBuffer<float> {
const int bands = _size / 2;
const int binWidth = bands / nBins;
- const float normalization = powf(_window ? _window->sum() : _size, 2.0);
+ const float invBinWidth = 1.0 / (float)binWidth;
+ const float normalization = 2.0 / powf(_window ? _window->sum() : _size, 2.0);
for (int bin = 0; bin < nBins; ++bin) {
float sum = 0.0;
int binEnd = bin * binWidth + binWidth;
for (int i = binEnd - binWidth; i < binEnd; ++i) {
- float power = powf(_fftOut[i], 2.0) + powf(_fftOut[i + bands], 2.0);
- power *= 2.0;
- power /= normalization;
- sum += power;
+ sum += (_fftOut[i]*_fftOut[i] + _fftOut[i + bands]*_fftOut[i + bands]) * normalization;
}
- bins[bin] = sum / (float)binWidth; // FIXME: averaging is the way to go?
+ bins[bin] = sum * invBinWidth;
}
}
- void getFrequencies(float* bins, int nBins) {
- assert(nBins <= _size / 2);
- assert(_size % nBins == 0);
-
- const int bands = _size / 2;
- const int binWidth = bands / nBins;
- const float fundamental = _sampleRate / (float)_size;
- for (int bin = 0; bin < nBins; ++bin) {
- bins[bin] = roundf(bin*binWidth*fundamental + binWidth*fundamental/2.0);
- }
- }
+ // void getFrequencies(float* bins, int nBins) {
+ // assert(nBins <= _size / 2);
+ // assert(_size % nBins == 0);
+ //
+ // const int bands = _size / 2;
+ // const int binWidth = bands / nBins;
+ // const float fundamental = _sampleRate / (float)_size;
+ // for (int bin = 0; bin < nBins; ++bin) {
+ // bins[bin] = roundf(bin*binWidth*fundamental + binWidth*fundamental/2.0);
+ // }
+ // }
};
} // namespace dsp
diff --git a/src/dsp/buffer.hpp b/src/dsp/buffer.hpp
@@ -1,6 +1,9 @@
#include <algorithm>
+namespace bogaudio {
+namespace dsp {
+
template<typename T>
struct OverlappingBuffer {
const int _size;
@@ -47,3 +50,6 @@ struct OverlappingBuffer {
return false;
}
};
+
+} // namespace dsp
+} // namespace bogaudio
diff --git a/src/dsp/noise.hpp b/src/dsp/noise.hpp
@@ -7,7 +7,7 @@ struct NoiseGenerator : Generator {};
struct WhiteNoiseGenerator : NoiseGenerator {
const uint32_t _mask = -1;
const float _randMax = powf(2.0, 31) - 1;
- int _last = 0; // rack::randomu32();
+ int _last = rack::randomu32();
virtual float _next() {
// don't use this for cryptography.