WE Core
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
PerformanceTests.cpp
Go to the documentation of this file.
1/*
2 * File: PerformanceTests.cpp
3 *
4 * Created: 26/05/2017
5 *
6 * This file is part of WECore.
7 *
8 * WECore is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * WECore is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with WECore. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "catch.hpp"
23#include <ctime>
24#include <algorithm>
25#include <iostream>
26#include <iomanip>
27#include <fstream>
28#include <chrono>
29
32
33
39namespace {
43 struct Stats {
44 double average;
45 double deviation;
46 };
47 std::ostream& operator<< (std::ostream& stream, const Stats& stats) {
48 stream << "Average: " << stats.average << " Deviation: " << stats.deviation;
49 return stream;
50 }
51
55 struct Limits {
56 const double INDIVIDUAL;
57 const double AVERAGE;
58 const double DEVIATION;
59 };
60
65 inline Stats calcAverageAndDeviation(const std::vector<double>& executionTimes) {
66 Stats retVal;
67
68 // calculate the average first
69 retVal.average = 0;
70 for (double time : executionTimes) {
71 retVal.average += time;
72 }
73 retVal.average = retVal.average / static_cast<double>(executionTimes.size());
74
75 // now calculate deviation
76 retVal.deviation = 0;
77 for (const double& time : executionTimes) {
78 retVal.deviation += std::pow((time - retVal.average), 2);
79 }
80 retVal.deviation = retVal.deviation / (static_cast<double>(executionTimes.size()) - 1);
81 retVal.deviation = std::sqrt(retVal.deviation);
82
83 return retVal;
84 }
85
86 bool isNewRun {true};
87 inline void appendToResultsFile(const Stats& stats, const std::string& testName) {
88 const std::string FILE_PATH("wecore_performance.log");
89 std::ofstream outStream;
90 outStream.open(FILE_PATH, std::ios_base::app);
91
92 if (isNewRun) {
93 isNewRun = false;
94
95 std::time_t now {std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())};
96 outStream << std::endl << std::endl << "**** New Test Run: "
97 << std::put_time(std::localtime(&now), "%F %T");
98 }
99 outStream << std::endl << testName << ": " << stats;
100
101 }
102}
103
104
105/*** TESTS BEGIN HERE ***/
106
107SCENARIO("Performance: CarveDSPUnit, 100 buffers of 1024 samples each") {
108 GIVEN("A CarveDSPUnit and a buffer of samples") {
109
110 const int NUM_BUFFERS {100};
111 std::vector<double> buffer(1024);
113
114 // set the performance limits
115 Limits mLimits{0.11, 0.07, 0.01};
116
117 // store the execution time for each buffer
118 std::vector<double> executionTimes;
119
120 WHEN("The samples are processed") {
121 // turn the unit on
122 mCarve.setMode(2);
123
124 for (int nbuf {0}; nbuf < NUM_BUFFERS; nbuf++) {
125
126 // fill the buffer with a sine wave
127 int iii {0};
128 std::generate(buffer.begin(), buffer.end(), [&iii]{ return std::sin(iii++); });
129
130
131 // do processing
132 const clock_t startTime {clock()};
133 for (size_t jjj {0}; jjj < buffer.size(); jjj++) {
134 buffer[jjj] = mCarve.process(buffer[jjj]);
135 }
136 const clock_t endTime {clock()};
137
138 // calculate the execution time
139 const double CLOCKS_PER_MICROSEC {static_cast<double>(CLOCKS_PER_SEC) / 1000};
140 const double executionTime {static_cast<double>(endTime - startTime) / CLOCKS_PER_MICROSEC};
141 executionTimes.push_back(executionTime);
142 CHECK(executionTime < mLimits.INDIVIDUAL);
143 }
144
145 THEN("The average and variance are within limits") {
146 Stats mStats = calcAverageAndDeviation(executionTimes);
147 CHECK(mStats.average < mLimits.AVERAGE);
148 CHECK(mStats.deviation < mLimits.DEVIATION);
149
150 appendToResultsFile(mStats, Catch::getResultCapture().getCurrentTestName());
151 }
152 }
153 }
154}
155
156SCENARIO("Performance: SongbirdFilterModule (blend mode), 100 buffers of 1024 samples each") {
157 GIVEN("A SongbirdFilterModule and a buffer of samples") {
158
159 const int NUM_BUFFERS {100};
160 std::vector<double> leftBuffer(1024);
161 std::vector<double> rightBuffer(1024);
163 mSongbird.setModMode(false);
164
165 // set the performance limits
166 Limits mLimits{1.8, 1.5, 0.12};
167
168 // store the execution time for each buffer
169 std::vector<double> executionTimes;
170
171 WHEN("The samples are processed") {
172
173 for (int nbuf {0}; nbuf < NUM_BUFFERS; nbuf++) {
174
175 // fill the buffer with a sine wave
176 int iii {0};
177 std::generate(leftBuffer.begin(), leftBuffer.end(), [&iii]{ return std::sin(iii++); });
178 rightBuffer = leftBuffer;
179
180
181 // do processing
182 const clock_t startTime {clock()};
183 mSongbird.Process2in2out(&leftBuffer[0], &rightBuffer[0], leftBuffer.size());
184 const clock_t endTime {clock()};
185
186 // calculate the execution time
187 const double CLOCKS_PER_MICROSEC {static_cast<double>(CLOCKS_PER_SEC) / 1000};
188 const double executionTime {static_cast<double>(endTime - startTime) / CLOCKS_PER_MICROSEC};
189 executionTimes.push_back(executionTime);
190 CHECK(executionTime < mLimits.INDIVIDUAL);
191 }
192
193 THEN("The average and variance are within limits") {
194 Stats mStats = calcAverageAndDeviation(executionTimes);
195 CHECK(mStats.average < mLimits.AVERAGE);
196 CHECK(mStats.deviation < mLimits.DEVIATION);
197
198 appendToResultsFile(mStats, Catch::getResultCapture().getCurrentTestName());
199 }
200 }
201 }
202}
203
204SCENARIO("Performance: SongbirdFilterModule (freq mode), 100 buffers of 1024 samples each") {
205 GIVEN("A SongbirdFilterModule and a buffer of samples") {
206
207 const int NUM_BUFFERS {100};
208 std::vector<double> leftBuffer(1024);
209 std::vector<double> rightBuffer(1024);
211 mSongbird.setModMode(true);
212
213 // set the performance limits
214 Limits mLimits{1.8, 1.5, 0.12};
215
216 // store the execution time for each buffer
217 std::vector<double> executionTimes;
218
219 WHEN("The samples are processed") {
220
221 for (int nbuf {0}; nbuf < NUM_BUFFERS; nbuf++) {
222
223 // fill the buffer with a sine wave
224 int iii {0};
225 std::generate(leftBuffer.begin(), leftBuffer.end(), [&iii]{ return std::sin(iii++); });
226 rightBuffer = leftBuffer;
227
228
229 // do processing
230 const clock_t startTime {clock()};
231 mSongbird.Process2in2out(&leftBuffer[0], &rightBuffer[0], leftBuffer.size());
232 const clock_t endTime {clock()};
233
234 // calculate the execution time
235 const double CLOCKS_PER_MICROSEC {static_cast<double>(CLOCKS_PER_SEC) / 1000};
236 const double executionTime {static_cast<double>(endTime - startTime) / CLOCKS_PER_MICROSEC};
237 executionTimes.push_back(executionTime);
238 CHECK(executionTime < mLimits.INDIVIDUAL);
239 }
240
241 THEN("The average and variance are within limits") {
242 Stats mStats = calcAverageAndDeviation(executionTimes);
243 CHECK(mStats.average < mLimits.AVERAGE);
244 CHECK(mStats.deviation < mLimits.DEVIATION);
245
246 appendToResultsFile(mStats, Catch::getResultCapture().getCurrentTestName());
247 }
248 }
249 }
250}
SCENARIO("CarveNoiseFilter: Silence in = silence out")
T process(T inSample) const
void Process2in2out(T *leftSamples, T *rightSamples, size_t numSamples)