1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "Benchmark.h" 9 #include "OverwriteLine.h" 10 #include "SkGraphics.h" 11 #include "SkTaskGroup.h" 12 #include <algorithm> 13 #include <chrono> 14 #include <limits> 15 #include <regex> 16 #include <stdlib.h> 17 #include <string> 18 #include <vector> 19 20 21 #if defined(SK_BUILD_FOR_WIN32) 22 static const char* kEllipsis = "..."; 23 #else 24 static const char* kEllipsis = ""; 25 #endif 26 27 int main(int argc, char** argv) { 28 SkGraphics::Init(); 29 SkTaskGroup::Enabler enabled; 30 31 using clock = std::chrono::high_resolution_clock; 32 using ns = std::chrono::duration<double, std::nano>; 33 34 std::regex pattern; 35 int limit = 2147483647; 36 if (argc > 1) { pattern = argv[1]; } 37 if (argc > 2) { limit = atoi(argv[2]); } 38 39 struct Bench { 40 std::unique_ptr<Benchmark> b; 41 std::string name; 42 ns best; 43 }; 44 std::vector<Bench> benches; 45 46 for (auto r = BenchRegistry::Head(); r; r = r->next()) { 47 std::unique_ptr<Benchmark> bench{ r->factory()(nullptr) }; 48 49 std::string name = bench->getName(); 50 if (std::regex_search(name, pattern) && 51 bench->isSuitableFor(Benchmark::kNonRendering_Backend)) { 52 bench->delayedSetup(); 53 benches.emplace_back(Bench{std::move(bench), name, 54 ns{std::numeric_limits<double>::infinity()}}); 55 } 56 } 57 58 if (benches.size() == 0) { 59 SkDebugf("No bench matched.\n"); 60 return 1; 61 } 62 63 if (benches.size() > 1) { 64 int common_prefix = benches[0].name.size(); 65 for (size_t i = 1; i < benches.size(); i++) { 66 int len = std::mismatch(benches[i-1].name.begin(), benches[i-1].name.end(), 67 benches[i-0].name.begin()) 68 .first - benches[i-1].name.begin(); 69 common_prefix = std::min(common_prefix, len); 70 } 71 std::string prefix = benches[0].name.substr(0, common_prefix); 72 if (common_prefix) { 73 for (auto& bench : benches) { 74 bench.name.replace(0, common_prefix, kEllipsis); 75 } 76 } 77 78 int common_suffix = benches[0].name.size(); 79 for (size_t i = 1; i < benches.size(); i++) { 80 int len = std::mismatch(benches[i-1].name.rbegin(), benches[i-1].name.rend(), 81 benches[i-0].name.rbegin()) 82 .first - benches[i-1].name.rbegin(); 83 common_suffix = std::min(common_suffix, len); 84 } 85 std::string suffix = benches[0].name.substr(benches[0].name.size() - common_suffix); 86 if (common_suffix) { 87 for (auto& bench : benches) { 88 bench.name.replace(bench.name.size() - common_suffix, common_suffix, kEllipsis); 89 } 90 } 91 92 SkDebugf("%s%s%s\n", prefix.c_str(), kEllipsis, suffix.c_str()); 93 } 94 95 int samples = 0; 96 while (samples < limit) { 97 std::random_shuffle(benches.begin(), benches.end()); 98 for (auto& bench : benches) { 99 for (int loops = 1; loops < 1000000000;) { 100 bench.b->preDraw(nullptr); 101 auto start = clock::now(); 102 bench.b->draw(loops, nullptr); 103 ns elapsed = clock::now() - start; 104 bench.b->postDraw(nullptr); 105 106 if (elapsed < std::chrono::milliseconds{10}) { 107 loops *= 2; 108 continue; 109 } 110 111 bench.best = std::min(bench.best, elapsed / loops); 112 samples++; 113 114 struct Result { const char* name; ns best; }; 115 std::vector<Result> sorted(benches.size()); 116 for (size_t i = 0; i < benches.size(); i++) { 117 sorted[i].name = benches[i].name.c_str(); 118 sorted[i].best = benches[i].best; 119 } 120 std::sort(sorted.begin(), sorted.end(), [](const Result& a, const Result& b) { 121 return a.best < b.best; 122 }); 123 124 SkDebugf("%s%d", kSkOverwriteLine, samples); 125 for (auto& result : sorted) { 126 if (sorted.size() == 1) { 127 SkDebugf(" %s %gns" , result.name, result.best.count()); 128 } else { 129 SkDebugf(" %s %.3gx", result.name, result.best / sorted[0].best); 130 } 131 } 132 break; 133 } 134 } 135 } 136 137 return 0; 138 } 139