/[svn]/linuxsampler/trunk/benchmarks/triang.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/benchmarks/triang.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3611 by schoenebeck, Fri Apr 21 13:33:03 2017 UTC revision 3612 by schoenebeck, Mon Sep 30 18:03:43 2019 UTC
# Line 4  Line 4 
4      This is a benchmark for comparison between a integer math, table lookup      This is a benchmark for comparison between a integer math, table lookup
5      and numeric sine wave harmonics solution.      and numeric sine wave harmonics solution.
6    
7      Copyright (C) 2005 - 2017 Christian Schoenebeck <cuse@users.sf.net>      Copyright (C) 2005 - 2019 Christian Schoenebeck <cuse@users.sf.net>
8  */  */
9    
10  #include <math.h>  #include "lfobench.h"
 #include <time.h>  
 #include <stdio.h>  
11    
12  #include "../src/engines/common/LFOTriangleIntMath.h"  #include "../src/engines/common/LFOTriangleIntMath.h"
13  #include "../src/engines/common/LFOTriangleIntAbsMath.h"  #include "../src/engines/common/LFOTriangleIntAbsMath.h"
14  #include "../src/engines/common/LFOTriangleDiHarmonic.h"  #include "../src/engines/common/LFOTriangleDiHarmonic.h"
15    
 // whether we should not show any messages on the console  
 #ifndef SILENT  
 # define SILENT 0  
 #endif  
   
 // set to 1 if you want to output the three calculated waves as RAW files  
 // you can e.g. open it as RAW file in Rezound  
 // (32 bit SP-FP PCM, mono, little endian, 44100kHz)  
 #ifndef OUTPUT_AS_RAW_WAVE  
 # define OUTPUT_AS_RAW_WAVE     0  
 #endif  
   
 // how many sample points should we calculate in one sequence  
 #ifndef STEPS  
 # define STEPS                  16384  
 #endif  
   
 // how often should we repeat the benchmark loop of each solution  
 #ifndef RUNS  
 # define RUNS                   1000  
 #endif  
   
 // whether the wave should have positive and negative range (signed -> 1) or just positive (unsigned -> 0)  
 #ifndef SIGNED  
 # define SIGNED                 1  
 #endif  
   
 // maximum value of the LFO output (also depends on SIGNED above)  
 #ifndef MAX  
 # define MAX                    1.0f  
 #endif  
   
 // pro forma  
 #ifndef SAMPLING_RATE  
 # define SAMPLING_RATE          44100.0f  
 #endif  
   
16  // return value of this benchmark  // return value of this benchmark
17  // to indicate the best performing solution  // to indicate the best performing solution
18  #define INT_MATH_SOLUTION       2  /* we don't start with 1, as this is reserved for unknown errors */  #define TRIANG_INT_MATH_SOLUTION        2  /* we don't start with 1, as this is reserved for unknown errors */
19  #define DI_HARMONIC_SOLUTION    3  #define TRIANG_DI_HARMONIC_SOLUTION     3
20  #define TABLE_LOOKUP_SOLUTION   4  /* table lookup solution is currently disabled in this benchmark, see below */  #define TRIANG_TABLE_LOOKUP_SOLUTION    4  /* table lookup solution is currently disabled in this benchmark, see below */
21  #define INT_MATH_ABS_SOLUTION   5  /* integer math with abs() */  #define TRIANG_INT_MATH_ABS_SOLUTION    5  /* integer math with abs() */
22  #define INVALID_RESULT          -1  #define INVALID_RESULT                 -1
   
 // we use 32 bit single precision floating point as sample point format  
 typedef float smpl_t; // (sample_t is already defined as int16_t by global_private.h)  
   
 using namespace LinuxSampler;  
23    
24  #if SIGNED  #if SIGNED
25  LFOTriangleIntMath<range_signed>*    pIntLFO        = NULL;  LFOTriangleIntMath<LFO::range_signed>*    pIntLFO        = NULL;
26  LFOTriangleIntAbsMath<range_signed>* pIntAbsLFO     = NULL;  LFOTriangleIntAbsMath<LFO::range_signed>* pIntAbsLFO     = NULL;
27  LFOTriangleDiHarmonic<range_signed>* pDiHarmonicLFO = NULL;  LFOTriangleDiHarmonic<LFO::range_signed>* pDiHarmonicLFO = NULL;
28  #else // unsigned  #else // unsigned
29  LFOTriangleIntMath<range_unsigned>*    pIntLFO        = NULL;  LFOTriangleIntMath<LFO::range_unsigned>*    pIntLFO        = NULL;
30  LFOTriangleIntAbsMath<range_unsigned>* pIntAbsLFO     = NULL;  LFOTriangleIntAbsMath<LFO::range_unsigned>* pIntAbsLFO     = NULL;
31  LFOTriangleDiHarmonic<range_unsigned>* pDiHarmonicLFO = NULL;  LFOTriangleDiHarmonic<LFO::range_unsigned>* pDiHarmonicLFO = NULL;
32  #endif  #endif
33    
34  // integer math solution  // integer math solution
35  float int_math(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {  double int_math(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
36      // pro forma      // pro forma
37      pIntLFO->trigger(frequency, start_level_max, 1200 /* max. internal depth */, 0, false, (unsigned int) SAMPLING_RATE);      pIntLFO->trigger(frequency, LFO::start_level_min, 0 /* max. internal depth */, 1200, false, (unsigned int) SAMPLING_RATE);
38        //pIntLFO->setPhase(0);
39        //pIntLFO->setFrequency(frequency*2, SAMPLING_RATE);
40    
41      clock_t stop_time;      clock_t stop_time;
42      clock_t start_time = clock();      clock_t start_time = clock();
# Line 86  float int_math(smpl_t* pDestinationBuffe Line 44  float int_math(smpl_t* pDestinationBuffe
44      for (int run = 0; run < RUNS; run++) {      for (int run = 0; run < RUNS; run++) {
45          pIntLFO->updateByMIDICtrlValue(127); // pro forma          pIntLFO->updateByMIDICtrlValue(127); // pro forma
46          for (int i = 0; i < steps; ++i) {          for (int i = 0; i < steps; ++i) {
47                //pIntLFO->updateByMIDICtrlValue(float(i)/float(steps)*127.f);
48              pDestinationBuffer[i] = pIntLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load              pDestinationBuffer[i] = pIntLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load
49          }          }
50      }      }
51    
52      stop_time = clock();      stop_time = clock();
53      float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);      double elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
54      #if ! SILENT      #if ! SILENT
55      printf("int math solution elapsed time: %1.0f ms\n", elapsed_time);      printf("int math solution elapsed time: %.1f ms\n", elapsed_time);
56      #endif      #endif
57    
58      return elapsed_time;      return elapsed_time;
59  }  }
60    
61  // integer math abs solution  // integer math abs solution
62  float int_math_abs(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {  double int_math_abs(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
63      // pro forma      // pro forma
64      pIntAbsLFO->trigger(frequency, start_level_max, 1200 /* max. internal depth */, 0, false, (unsigned int) SAMPLING_RATE);      pIntAbsLFO->trigger(frequency, LFO::start_level_min, 0 /* max. internal depth */, 1200, false, (unsigned int) SAMPLING_RATE);
65        //pIntAbsLFO->setPhase(0);
66        //pIntAbsLFO->setFrequency(frequency*2, SAMPLING_RATE);
67    
68      clock_t stop_time;      clock_t stop_time;
69      clock_t start_time = clock();      clock_t start_time = clock();
70    
71      for (int run = 0; run < RUNS; run++) {      for (int run = 0; run < RUNS; run++) {
72          pIntAbsLFO->updateByMIDICtrlValue(0); // pro forma          pIntAbsLFO->updateByMIDICtrlValue(127); // pro forma
73          for (int i = 0; i < steps; ++i) {          for (int i = 0; i < steps; ++i) {
74                //pIntAbsLFO->updateByMIDICtrlValue(float(i)/float(steps)*127.f);
75              pDestinationBuffer[i] = pIntAbsLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load              pDestinationBuffer[i] = pIntAbsLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load
76          }          }
77      }      }
78    
79      stop_time = clock();      stop_time = clock();
80      float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);      double elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
81      #if ! SILENT      #if ! SILENT
82      printf("int math abs solution elapsed time: %1.0f ms\n", elapsed_time);      printf("int math abs solution elapsed time: %.1f ms\n", elapsed_time);
83      #endif      #endif
84    
85      return elapsed_time;      return elapsed_time;
# Line 131  float int_math_abs(smpl_t* pDestinationB Line 93  float int_math_abs(smpl_t* pDestinationB
93  // anyway. If you found an architecture where this seems to be the best  // anyway. If you found an architecture where this seems to be the best
94  // solution, please let us know!  // solution, please let us know!
95  #if 0  #if 0
96  float table_lookup(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {  double table_lookup(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
97      // pro forma      // pro forma
98      const float r = frequency / SAMPLING_RATE; // frequency alteration quotient      const float r = frequency / SAMPLING_RATE; // frequency alteration quotient
99      #if SIGNED      #if SIGNED
# Line 182  float table_lookup(smpl_t* pDestinationB Line 144  float table_lookup(smpl_t* pDestinationB
144      }      }
145    
146      stop_time = clock();      stop_time = clock();
147      float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);      double elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
148      #if ! SILENT      #if ! SILENT
149      printf("Table lookup solution elapsed time: %1.0f ms\n", elapsed_time);      printf("Table lookup solution elapsed time: %.1f ms\n", elapsed_time);
150      #endif      #endif
151    
152      if (pPrerenderingBuffer) delete[] pPrerenderingBuffer;      if (pPrerenderingBuffer) delete[] pPrerenderingBuffer;
# Line 194  float table_lookup(smpl_t* pDestinationB Line 156  float table_lookup(smpl_t* pDestinationB
156  #endif  #endif
157    
158  // numeric, di-harmonic solution  // numeric, di-harmonic solution
159  float numeric_di_harmonic_solution(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {  double numeric_di_harmonic_solution(smpl_t* pDestinationBuffer, float* pAmp, const int steps, const float frequency) {
160      // pro forma      // pro forma
161      pDiHarmonicLFO->trigger(frequency, start_level_max, 1200 /* max. internal depth */, 0, false, (unsigned int) SAMPLING_RATE);      pDiHarmonicLFO->trigger(frequency, LFO::start_level_min, 0 /* max. internal depth */, 1200, false, (unsigned int) SAMPLING_RATE);
162        //pDiHarmonicLFO->setPhase(0);
163        //pDiHarmonicLFO->setFrequency(frequency*2, SAMPLING_RATE);
164    
165      clock_t stop_time;      clock_t stop_time;
166      clock_t start_time = clock();      clock_t start_time = clock();
# Line 204  float numeric_di_harmonic_solution(smpl_ Line 168  float numeric_di_harmonic_solution(smpl_
168      for (int run = 0; run < RUNS; run++) {      for (int run = 0; run < RUNS; run++) {
169          pDiHarmonicLFO->updateByMIDICtrlValue(127); // pro forma          pDiHarmonicLFO->updateByMIDICtrlValue(127); // pro forma
170          for (int i = 0; i < steps; ++i) {          for (int i = 0; i < steps; ++i) {
171                //pDiHarmonicLFO->updateByMIDICtrlValue(float(i)/float(steps)*127.f);
172              pDestinationBuffer[i] = pDiHarmonicLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load              pDestinationBuffer[i] = pDiHarmonicLFO->render() * pAmp[i]; // * pAmp[i] just to simulate some memory load
173          }          }
174      }      }
175    
176      stop_time = clock();      stop_time = clock();
177      float elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);      double elapsed_time = (stop_time - start_time) / (double(CLOCKS_PER_SEC) / 1000.0);
178      #if ! SILENT      #if ! SILENT
179      printf("Numeric harmonics solution elapsed time: %1.0f ms\n", elapsed_time);      printf("Numeric harmonics solution elapsed time: %.1f ms\n", elapsed_time);
180      #endif      #endif
181    
182      return elapsed_time;      return elapsed_time;
183  }  }
184    
 // output calculated values as RAW audio format (32 bit floating point, mono) file  
 void output_as_raw_file(const char* filename, smpl_t* pOutputBuffer, int steps) {  
     FILE* file = fopen(filename, "w");  
     if (file) {  
         fwrite((void*) pOutputBuffer, sizeof(float), steps, file);  
         fclose(file);  
     } else {  
         fprintf(stderr, "Could not open %s\n", filename);  
     }  
 }  
   
185  int main() {  int main() {
186      const int steps = STEPS;      const int steps = STEPS;
187      const int sinusoidFrequency = 100; // Hz      const int sinusoidFrequency = 100; // Hz
188    
189      #if ! SILENT      #if ! SILENT
190        printf("\n");
191      # if SIGNED      # if SIGNED
192      printf("Signed triangular wave benchmark\n");      printf("Signed triangular wave benchmark\n");
     printf("--------------------------------\n");  
193      # else      # else
194      printf("Unsigned triangular wave benchmark\n");      printf("Unsigned triangular wave benchmark\n");
     printf("----------------------------------\n");  
195      # endif      # endif
196        printf("----------------------------------\n");
197        printf("\n");
198      #endif      #endif
199    
200      #if SIGNED      #if SIGNED
201      pIntLFO        = new LFOTriangleIntMath<range_signed>(MAX);      pIntLFO        = new LFOTriangleIntMath<LFO::range_signed>(MAX);
202      pIntAbsLFO     = new LFOTriangleIntAbsMath<range_signed>(MAX);      pIntAbsLFO     = new LFOTriangleIntAbsMath<LFO::range_signed>(MAX);
203      pDiHarmonicLFO = new LFOTriangleDiHarmonic<range_signed>(MAX);      pDiHarmonicLFO = new LFOTriangleDiHarmonic<LFO::range_signed>(MAX);
204      #else // unsigned      #else // unsigned
205      pIntLFO        = new LFOTriangleIntMath<range_unsigned>(MAX);      pIntLFO        = new LFOTriangleIntMath<LFO::range_unsigned>(MAX);
206      pIntAbsLFO     = new LFOTriangleIntAbsMath<range_unsigned>(MAX);      pIntAbsLFO     = new LFOTriangleIntAbsMath<LFO::range_unsigned>(MAX);
207      pDiHarmonicLFO = new LFOTriangleDiHarmonic<range_unsigned>(MAX);      pDiHarmonicLFO = new LFOTriangleDiHarmonic<LFO::range_unsigned>(MAX);
208      #endif      #endif
209    
210      // output buffer for the calculated sinusoid wave      // output buffer for the calculated sinusoid wave
# Line 261  int main() { Line 216  int main() {
216      for (int i = 0; i < steps; ++i)      for (int i = 0; i < steps; ++i)
217          pAmplitude[i] = (float) i / (float) steps;          pAmplitude[i] = (float) i / (float) steps;
218    
219      // how long each solution took (in seconds)      // going to store how long each solution took (in seconds)
220      float int_math_result, int_math_abs_result, /*table_lookup_result,*/ numeric_di_harmonic_result;      std::vector<BenchRes> results;
221    
222      int_math_result = int_math(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);  
223        results.push_back({
224            .algorithmID = TRIANG_INT_MATH_SOLUTION,
225            .algorithmName = "int math",
226            .timeMSecs = int_math(pOutputBuffer, pAmplitude, steps, sinusoidFrequency)
227        });
228      #if OUTPUT_AS_RAW_WAVE      #if OUTPUT_AS_RAW_WAVE
229        output_as_raw_file("bench_int_math.raw", pOutputBuffer, steps);      output_as_raw_file("bench_int_math.raw", pOutputBuffer, steps);
230      #endif      #endif
231    
232      int_math_abs_result = int_math_abs(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);  
233        results.push_back({
234            .algorithmID = TRIANG_INT_MATH_ABS_SOLUTION,
235            .algorithmName = "int math abs",
236            .timeMSecs = int_math_abs(pOutputBuffer, pAmplitude, steps, sinusoidFrequency)
237        });
238      #if OUTPUT_AS_RAW_WAVE      #if OUTPUT_AS_RAW_WAVE
239        output_as_raw_file("bench_int_math_abs.raw", pOutputBuffer, steps);      output_as_raw_file("bench_int_math_abs.raw", pOutputBuffer, steps);
240      #endif      #endif
241    
242    
243      //table_lookup_result = table_lookup(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);      //table_lookup_result = table_lookup(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
244      //#if OUTPUT_AS_RAW_WAVE      //#if OUTPUT_AS_RAW_WAVE
245      //  output_as_raw_file("bench_table_lookup.raw", pOutputBuffer, steps);      //  output_as_raw_file("bench_table_lookup.raw", pOutputBuffer, steps);
246      //#endif      //#endif
247      numeric_di_harmonic_result = numeric_di_harmonic_solution(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);  
248    
249        results.push_back({
250            .algorithmID = TRIANG_DI_HARMONIC_SOLUTION,
251            .algorithmName = "Numeric di harmonic",
252            .timeMSecs = numeric_di_harmonic_solution(pOutputBuffer, pAmplitude, steps, sinusoidFrequency)
253        });
254      #if OUTPUT_AS_RAW_WAVE      #if OUTPUT_AS_RAW_WAVE
255        output_as_raw_file("bench_numeric_harmonics.raw", pOutputBuffer, steps);      output_as_raw_file("bench_numeric_harmonics.raw", pOutputBuffer, steps);
256      #endif      #endif
257    
258    
259      #if ! SILENT      #if ! SILENT
260      printf("\nOK, 2nd try\n\n");      printf("\nOK, 2nd try\n\n");
261      #endif      #endif
262    
263      int_math_result            += int_math(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);  
264      int_math_abs_result = int_math_abs(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);      results[0].timeMSecs += int_math(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
265      //table_lookup_result        += table_lookup(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);      results[1].timeMSecs += int_math_abs(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
266      numeric_di_harmonic_result += numeric_di_harmonic_solution(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);      //table_lookup_result += table_lookup(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
267        results[2].timeMSecs += numeric_di_harmonic_solution(pOutputBuffer, pAmplitude, steps, sinusoidFrequency);
268    
269    
270      if (pAmplitude)    delete[] pAmplitude;      if (pAmplitude)    delete[] pAmplitude;
271      if (pOutputBuffer) delete[] pOutputBuffer;      if (pOutputBuffer) delete[] pOutputBuffer;
272    
273      if (pIntLFO)        delete pIntLFO;      if (pIntLFO)        delete pIntLFO;
274        if (pIntAbsLFO)     delete pIntAbsLFO;
275      if (pDiHarmonicLFO) delete pDiHarmonicLFO;      if (pDiHarmonicLFO) delete pDiHarmonicLFO;
276    
277      if (int_math_abs_result <= int_math_result && int_math_abs_result <= numeric_di_harmonic_result) return INT_MATH_ABS_SOLUTION;      sortResultsFirstToBeBest(results);
278      if (int_math_result <= int_math_abs_result && int_math_result <= numeric_di_harmonic_result) return INT_MATH_SOLUTION;      printResultSummary(results);
     if (numeric_di_harmonic_result <= int_math_abs_result && numeric_di_harmonic_result <= int_math_result) return DI_HARMONIC_SOLUTION;  
279    
280      return INVALID_RESULT; // error      return results[0].algorithmID; // return the winner's numeric algorithm ID
281  }  }

Legend:
Removed from v.3611  
changed lines
  Added in v.3612

  ViewVC Help
Powered by ViewVC