solvespace/bench/harness.cpp

136 lines
3.6 KiB
C++

//-----------------------------------------------------------------------------
// Our harness for running benchmarks.
//
// Copyright 2016 whitequark
//-----------------------------------------------------------------------------
#include "solvespace.h"
#if defined(WIN32)
#include <windows.h>
#else
#include <unistd.h>
#endif
namespace SolveSpace {
// These are defined in headless.cpp, and aren't exposed in solvespace.h.
extern std::string resourceDir;
}
static std::string ResourceRoot() {
static std::string rootDir;
if(!rootDir.empty()) return rootDir;
// No especially good way to do this, so let's assume somewhere up from
// the current directory there's our repository, with CMakeLists.txt, and
// pivot from there.
#if defined(WIN32)
wchar_t currentDirW[MAX_PATH];
GetCurrentDirectoryW(MAX_PATH, currentDirW);
rootDir = Narrow(currentDirW);
#else
rootDir = ".";
#endif
// We're never more than four levels deep.
for(size_t i = 0; i < 4; i++) {
std::string listsPath = rootDir;
listsPath += PATH_SEP;
listsPath += "CMakeLists.txt";
FILE *f = ssfopen(listsPath, "r");
if(f) {
fclose(f);
rootDir += PATH_SEP;
rootDir += "res";
return rootDir;
}
if(rootDir[0] == '.') {
rootDir += PATH_SEP;
rootDir += "..";
} else {
rootDir.erase(rootDir.rfind(PATH_SEP));
}
}
ssassert(false, "Couldn't locate repository root");
}
static bool RunBenchmark(std::function<void()> setupFn,
std::function<bool()> benchFn,
std::function<void()> teardownFn,
size_t minIter = 5, double minTime = 5.0) {
// Warmup
setupFn();
if(!benchFn()) {
fprintf(stderr, "Benchmark failed\n");
return false;
}
teardownFn();
// Benchmark
size_t iter = 0;
double time = 0.0;
while(iter < minIter || time < minTime) {
setupFn();
auto testStartTime = std::chrono::steady_clock::now();
benchFn();
auto testEndTime = std::chrono::steady_clock::now();
teardownFn();
std::chrono::duration<double> testTime = testEndTime - testStartTime;
time += testTime.count();
iter += 1;
}
// Report
fprintf(stdout, "Iterations: %zd\n", iter);
fprintf(stdout, "Time: %.3f s\n", time);
fprintf(stdout, "Per iter.: %.3f s\n", time / (double)iter);
return true;
}
int main(int argc, char **argv) {
#if defined(_MSC_VER)
_set_abort_behavior(0, _WRITE_ABORT_MSG);
#endif
#if defined(WIN32)
InitHeaps();
#endif
resourceDir = ResourceRoot();
std::string mode, filename;
if(argc == 3) {
mode = argv[1];
filename = argv[2];
} else {
fprintf(stderr, "Usage: %s [mode] [filename]\n", argv[0]);
fprintf(stderr, "Mode can be one of: load.\n");
return 1;
}
bool result = false;
if(mode == "load") {
result = RunBenchmark(
[] {
SS.Init();
},
[&] {
if(!SS.LoadFromFile(filename))
return false;
if(!SS.ReloadAllImported(/*canCancel=*/false))
return false;
SS.AfterNewFile();
return true;
},
[] {
SK.Clear();
SS.Clear();
});
} else {
fprintf(stderr, "Unknown mode \"%s\"\n", mode.c_str());
}
return (result == true ? 0 : 1);
}