Skip to content

Instantly share code, notes, and snippets.

@jthistle
Created February 5, 2019 17:43
Show Gist options
  • Save jthistle/233f9876a1ee6da3bb4c1f1e20d328e6 to your computer and use it in GitHub Desktop.
Save jthistle/233f9876a1ee6da3bb4c1f1e20d328e6 to your computer and use it in GitHub Desktop.
Benchmarks different methods for single note dynamics in MuseScore
#include <iostream>
#include <vector>
#include <functional>
#include <math.h>
#include <sys/time.h>
#include <ctime>
namespace Bm
{
void benchmark1(int method)
{
int startExpr = 0;
int endExpr = 100;
int exprDiff = endExpr-startExpr;
int exprTicks = 100;
int tickInc = 1;
std::function<int(std::vector<double>&, int)> valueFunction;
std::vector<double> preCalculated;
switch (method) {
case 0:
// Due to the nth-root, exponential functions do not flip with negative values, and cause errors,
// so treat it as a piecewise function.
if (exprDiff > 0) {
preCalculated.push_back(
pow((exprDiff + 1), 1.0 / double(exprTicks)) // the exprTicks root of d+1
);
valueFunction = [](std::vector<double>& pc, int ct) { return int(
pow(
pc[0],
double(ct) // to the power of the current tick (exponential)
) - 1
); };
}
else {
preCalculated.push_back(
pow((-exprDiff + 1), 1.0 / double(exprTicks)) // the exprTicks root of 1-d
);
valueFunction = [](std::vector<double>& pc, int ct) { return -int(
pow(
pc[0],
double(ct) // again to the power of ct
) + 1
); };
}
break;
// Uses sin x transformed, which _does_ flip with negative numbers
case 1:
preCalculated.push_back(double(exprDiff) / 2.0);
preCalculated.push_back(double(M_PI / double(exprTicks)));
preCalculated.push_back(double(M_PI / 2.0));
valueFunction = [](std::vector<double>& pc, int ct) { return int(
pc[0] * (
sin(
double(ct) * (
pc[1]
) - pc[2]
) + 1
)
); };
break;
case 2:
preCalculated.push_back(double(exprDiff));
preCalculated.push_back(double(exprTicks));
preCalculated.push_back(double(M_PI / double(2 * exprTicks)));
valueFunction = [](std::vector<double>& pc, int ct) { return int(
pc[0] * (
sin(
double(ct - pc[1]) * (
pc[2]
)
) + 1
)
); };
break;
case 3:
preCalculated.push_back(double(exprDiff));
preCalculated.push_back(double(M_PI / double(2 * exprTicks)));
valueFunction = [](std::vector<double>& pc, int ct) { return int(
pc[0] * sin(
double(ct) * (
pc[1]
)
)
); };
break;
case 4:
default:
// We can calculate how to increase the ticks, since it is linear
tickInc = exprTicks / abs(exprDiff);
preCalculated.push_back(double(exprDiff));
preCalculated.push_back(double(exprTicks));
valueFunction = [](std::vector<double>& pc, int ct) { return int(pc[0] * (double(ct) / pc[1])); };
break;
}
// prevent possible infinite loop
if (tickInc < 1)
tickInc = 1;
int lastVal = -1;
for (int i = 0; i < exprTicks; i += tickInc) {
int valueToAdd = valueFunction(preCalculated, i);
if (lastVal == valueToAdd)
continue;
lastVal = valueToAdd;
int exprVal = startExpr + valueToAdd;
}
}
void benchmark2(int method)
{
int startExpr = 0;
int endExpr = 100;
int exprDiff = endExpr-startExpr;
int exprTicks = 100;
int tickInc = 1;
// See these functions graphically at: https://www.desmos.com/calculator/kk89ficmjk
std::function<int(int,int,int)> valueFunction;
switch (method) {
case 0:
// Due to the nth-root, exponential functions do not flip with negative values, and cause errors,
// so treat it as a piecewise function.
if (exprDiff > 0)
valueFunction = [](int d, int ct, int tt) { return int(
pow(
pow((d + 1), 1.0 / double(tt)), // the tt root of d+1
double(ct) // to the power of the current tick (exponential)
) - 1
); };
else
valueFunction = [](int d, int ct, int tt) { return -int(
pow(
pow((-d + 1), 1.0 / double(tt)), // the tt root of 1 - d
double(ct) // again to the power of ct
) + 1
); };
break;
// Uses sin x transformed, which _does_ flip with negative numbers
case 1:
valueFunction = [](int d, int ct, int tt) { return int(
(double(d) / 2.0) * (
sin(
double(ct) * (
M_PI / double(tt)
) - M_PI / 2.0
) + 1
)
); };
break;
case 2:
valueFunction = [](int d, int ct, int tt) { return int(
double(d) * (
sin(
double(ct - tt) * (
M_PI / double(2 * tt)
)
) + 1
)
); };
break;
case 3:
valueFunction = [](int d, int ct, int tt) { return int(
double(d) * sin(
double(ct) * (
M_PI / double(2 * tt)
)
)
); };
break;
case 4:
default:
// We can calculate how to increase the ticks, since it is linear
tickInc = exprTicks / abs(exprDiff);
valueFunction = [](int d, int ct, int tt) { return int(d * (double(ct) / double(tt))); };
break;
}
// prevent possible infinite loop
if (tickInc < 1)
tickInc = 1;
int lastVal = -1;
for (int i = 0; i < exprTicks; i += tickInc) {
int valueToAdd = valueFunction(exprDiff, i, exprTicks);
if (lastVal == valueToAdd)
continue;
lastVal = valueToAdd;
int exprVal = startExpr + valueToAdd;
}
}
}
/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;
/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
* windows and linux. */
uint64 GetTimeMs64()
{
struct timeval tv;
gettimeofday(&tv, NULL);
uint64 ret = tv.tv_usec;
/* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
ret /= 1000;
/* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
ret += (tv.tv_sec * 1000);
return ret;
}
int main()
{
const int testCount = 1000000;
const int repeats = 5;
std::cout << "Running benchmark: " << testCount << " iterations, " << repeats << " repeats" << std::endl;
std::vector<double> pImp;
for (int r = 0; r < repeats; ++r) {
uint64 st, et;
int m1, m2;
st = GetTimeMs64();
for (int i = 0; i <= testCount; ++i)
Bm::benchmark1(i%5);
et = GetTimeMs64();
m1 = et-st;
std::cout << "Method 1 (new): " << m1 << "ms" << std::endl;
st = GetTimeMs64();
for (int i = 0; i < testCount; ++i)
Bm::benchmark2(i%5);
et = GetTimeMs64();
m2 = et-st;
std::cout << "Method 2: " << m2 << "ms" << std::endl;
double p = (double(m2-m1)/double(m2))*100;
pImp.push_back(p);
std::cout << "Method 1 runs " << p << "% faster than m2" << std::endl;
}
double avg;
for (int p : pImp) avg += p;
avg /= double(pImp.size());
std::cout << "Average percentage increase in performance: " << avg << "%" << std::endl;
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment