Home | History | Annotate | Download | only in tools
      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