skia2/tools/monobench.cpp
Mike Klein ef6bbbd063 monobench: don't sort the Bench vector while iterating through it...
We sort to display Bench results in an ascending order, but we're doing this while iterating through the bench vector.  This is probably undefined, and really screws up the sample distribution in practice.  Slow benches run more often.

Instead, copy the results of the benches to a new Result vector to sort and display.  Each bench now gets its fair share of samples.

Change-Id: I4ead0d9d69af271c9971eedb35604a4b3bca0784
Reviewed-on: https://skia-review.googlesource.com/6623
Reviewed-by: Mike Klein <mtklein@chromium.org>
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
2017-01-05 20:00:26 +00:00

139 lines
4.5 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Benchmark.h"
#include "OverwriteLine.h"
#include "SkGraphics.h"
#include "SkTaskGroup.h"
#include <algorithm>
#include <chrono>
#include <limits>
#include <regex>
#include <stdlib.h>
#include <string>
#include <vector>
#if defined(SK_BUILD_FOR_WIN32)
static const char* kEllipsis = "...";
#else
static const char* kEllipsis = "";
#endif
int main(int argc, char** argv) {
SkGraphics::Init();
SkTaskGroup::Enabler enabled;
using clock = std::chrono::high_resolution_clock;
using ns = std::chrono::duration<double, std::nano>;
std::regex pattern;
int limit = 2147483647;
if (argc > 1) { pattern = argv[1]; }
if (argc > 2) { limit = atoi(argv[2]); }
struct Bench {
std::unique_ptr<Benchmark> b;
std::string name;
ns best;
};
std::vector<Bench> benches;
for (auto r = BenchRegistry::Head(); r; r = r->next()) {
std::unique_ptr<Benchmark> bench{ r->factory()(nullptr) };
std::string name = bench->getName();
if (std::regex_search(name, pattern) &&
bench->isSuitableFor(Benchmark::kNonRendering_Backend)) {
bench->delayedSetup();
benches.emplace_back(Bench{std::move(bench), name,
ns{std::numeric_limits<double>::infinity()}});
}
}
if (benches.size() == 0) {
SkDebugf("No bench matched.\n");
return 1;
}
if (benches.size() > 1) {
int common_prefix = benches[0].name.size();
for (size_t i = 1; i < benches.size(); i++) {
int len = std::mismatch(benches[i-1].name.begin(), benches[i-1].name.end(),
benches[i-0].name.begin())
.first - benches[i-1].name.begin();
common_prefix = std::min(common_prefix, len);
}
std::string prefix = benches[0].name.substr(0, common_prefix);
if (common_prefix) {
for (auto& bench : benches) {
bench.name.replace(0, common_prefix, kEllipsis);
}
}
int common_suffix = benches[0].name.size();
for (size_t i = 1; i < benches.size(); i++) {
int len = std::mismatch(benches[i-1].name.rbegin(), benches[i-1].name.rend(),
benches[i-0].name.rbegin())
.first - benches[i-1].name.rbegin();
common_suffix = std::min(common_suffix, len);
}
std::string suffix = benches[0].name.substr(benches[0].name.size() - common_suffix);
if (common_suffix) {
for (auto& bench : benches) {
bench.name.replace(bench.name.size() - common_suffix, common_suffix, kEllipsis);
}
}
SkDebugf("%s%s%s\n", prefix.c_str(), kEllipsis, suffix.c_str());
}
int samples = 0;
while (samples < limit) {
std::random_shuffle(benches.begin(), benches.end());
for (auto& bench : benches) {
for (int loops = 1; loops < 1000000000;) {
bench.b->preDraw(nullptr);
auto start = clock::now();
bench.b->draw(loops, nullptr);
ns elapsed = clock::now() - start;
bench.b->postDraw(nullptr);
if (elapsed < std::chrono::milliseconds{10}) {
loops *= 2;
continue;
}
bench.best = std::min(bench.best, elapsed / loops);
samples++;
struct Result { const char* name; ns best; };
std::vector<Result> sorted(benches.size());
for (size_t i = 0; i < benches.size(); i++) {
sorted[i].name = benches[i].name.c_str();
sorted[i].best = benches[i].best;
}
std::sort(sorted.begin(), sorted.end(), [](const Result& a, const Result& b) {
return a.best < b.best;
});
SkDebugf("%s%d", kSkOverwriteLine, samples);
for (auto& result : sorted) {
if (sorted.size() == 1) {
SkDebugf(" %s %gns" , result.name, result.best.count());
} else {
SkDebugf(" %s %.3gx", result.name, result.best / sorted[0].best);
}
}
break;
}
}
}
return 0;
}