benchmarks: add option --min-duration=SECONDS
- with this option test_runner() will be called repeatedly (doing the given number of --iterations each time) until SECONDS have elapsed - added output column showing average time per iteration, should help when comparing different runs - shrinked the # of iterations column using k/M suffixes
This commit is contained in:
parent
2f303e4da4
commit
8762e1d034
1 changed files with 64 additions and 30 deletions
|
@ -39,6 +39,10 @@ public:
|
|||
{
|
||||
return iterations_;
|
||||
}
|
||||
mapnik::parameters const& params() const
|
||||
{
|
||||
return params_;
|
||||
}
|
||||
virtual bool validate() const = 0;
|
||||
virtual bool operator()() const = 0;
|
||||
virtual ~test_case() {}
|
||||
|
@ -138,52 +142,82 @@ int run(T const& test_runner, std::string const& name)
|
|||
if (!test_runner.validate())
|
||||
{
|
||||
std::clog << "test did not validate: " << name << "\n";
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
// run test once before timing
|
||||
// if it returns false then we'll abort timing
|
||||
if (test_runner())
|
||||
if (!test_runner())
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point start;
|
||||
std::chrono::high_resolution_clock::duration elapsed;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (test_runner.threads() > 0)
|
||||
std::chrono::high_resolution_clock::time_point start;
|
||||
std::chrono::high_resolution_clock::duration elapsed;
|
||||
auto opt_min_duration = test_runner.params().template get<double>("min-duration", 0.0);
|
||||
std::chrono::duration<double> min_seconds(*opt_min_duration);
|
||||
auto min_duration = std::chrono::duration_cast<decltype(elapsed)>(min_seconds);
|
||||
std::size_t loops = 0;
|
||||
|
||||
if (test_runner.threads() > 0)
|
||||
{
|
||||
using thread_group = std::vector<std::unique_ptr<std::thread> >;
|
||||
using value_type = thread_group::value_type;
|
||||
thread_group tg;
|
||||
for (std::size_t i=0;i<test_runner.threads();++i)
|
||||
{
|
||||
using thread_group = std::vector<std::unique_ptr<std::thread> >;
|
||||
using value_type = thread_group::value_type;
|
||||
thread_group tg;
|
||||
for (std::size_t i=0;i<test_runner.threads();++i)
|
||||
{
|
||||
tg.emplace_back(new std::thread(test_runner));
|
||||
}
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
|
||||
elapsed = std::chrono::high_resolution_clock::now() - start;
|
||||
tg.emplace_back(new std::thread(test_runner));
|
||||
}
|
||||
else
|
||||
{
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
|
||||
elapsed = std::chrono::high_resolution_clock::now() - start;
|
||||
loops = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
do {
|
||||
test_runner();
|
||||
elapsed = std::chrono::high_resolution_clock::now() - start;
|
||||
}
|
||||
|
||||
char msg[200];
|
||||
std::snprintf(msg, sizeof(msg),
|
||||
"%-43s %3zu threads %9zu iters %6.0f milliseconds",
|
||||
name.c_str(),
|
||||
test_runner.threads(),
|
||||
test_runner.iterations(),
|
||||
std::chrono::duration<double, std::milli>(elapsed).count());
|
||||
std::clog << msg << "\n";
|
||||
++loops;
|
||||
} while (elapsed < min_duration);
|
||||
}
|
||||
|
||||
double iters = loops * test_runner.iterations();
|
||||
double dur_total = std::chrono::duration<double, std::milli>(elapsed).count();
|
||||
double dur_avg = dur_total / iters;
|
||||
char iters_unit = ' ';
|
||||
char msg[200];
|
||||
|
||||
if (iters >= 1e7) iters *= 1e-6, iters_unit = 'M';
|
||||
else if (iters >= 1e4) iters *= 1e-3, iters_unit = 'k';
|
||||
|
||||
std::snprintf(msg, sizeof(msg),
|
||||
"%-43s %3zu threads %4.0f%c iters %6.0f milliseconds",
|
||||
name.c_str(),
|
||||
test_runner.threads(),
|
||||
iters, iters_unit,
|
||||
dur_total);
|
||||
std::clog << msg;
|
||||
|
||||
// log average time per iteration, currently only for non-threaded runs
|
||||
if (test_runner.threads() == 0)
|
||||
{
|
||||
char unit = 'm';
|
||||
if (dur_avg < 1e-5) dur_avg *= 1e+9, unit = 'p';
|
||||
else if (dur_avg < 1e-2) dur_avg *= 1e+6, unit = 'n';
|
||||
else if (dur_avg < 1e+1) dur_avg *= 1e+3, unit = 'u';
|
||||
std::snprintf(msg, sizeof(msg), " %4.0f%cs/iter", dur_avg, unit);
|
||||
std::clog << msg;
|
||||
}
|
||||
|
||||
std::clog << "\n";
|
||||
return 0;
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
std::clog << "test runner did not complete: " << ex.what() << "\n";
|
||||
return -1;
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sequencer
|
||||
|
|
Loading…
Add table
Reference in a new issue