Home | History | Annotate | Download | only in bench
      1 /*
      2  * Copyright 2013 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  * Classes for writing out bench results in various formats.
      8  */
      9 
     10 #ifndef SkResultsWriter_DEFINED
     11 #define SkResultsWriter_DEFINED
     12 
     13 #include "BenchLogger.h"
     14 #include "SkJSONCPP.h"
     15 #include "SkStream.h"
     16 #include "SkString.h"
     17 #include "SkTArray.h"
     18 #include "SkTypes.h"
     19 
     20 /**
     21  * Base class for writing out the bench results.
     22  *
     23  * TODO(jcgregorio) Add info if tests fail to converge?
     24  */
     25 class ResultsWriter : SkNoncopyable {
     26 public:
     27     virtual ~ResultsWriter() {};
     28 
     29     // Records one option set for this run. All options must be set before
     30     // calling bench().
     31     virtual void option(const char name[], const char value[]) = 0;
     32 
     33     // Denotes the start of a specific benchmark. Once bench is called,
     34     // then config and timer can be called multiple times to record runs.
     35     virtual void bench(const char name[], int32_t x, int32_t y) = 0;
     36 
     37     // Records the specific configuration a bench is run under, such as "8888".
     38     virtual void config(const char name[]) = 0;
     39 
     40     // Records a single test metric.
     41     virtual void timer(const char name[], double ms) = 0;
     42 
     43     // Call when all results are finished.
     44     virtual void end() = 0;
     45 };
     46 
     47 /**
     48  * This ResultsWriter handles writing out the human readable format of the
     49  * bench results.
     50  */
     51 class LoggerResultsWriter : public ResultsWriter {
     52 public:
     53     explicit LoggerResultsWriter(BenchLogger& logger, const char* timeFormat)
     54         : fLogger(logger)
     55         , fTimeFormat(timeFormat) {
     56         fLogger.logProgress("skia bench:");
     57     }
     58     virtual void option(const char name[], const char value[]) {
     59         fLogger.logProgress(SkStringPrintf(" %s=%s", name, value));
     60     }
     61     virtual void bench(const char name[], int32_t x, int32_t y) {
     62         fLogger.logProgress(SkStringPrintf(
     63             "\nrunning bench [%3d %3d] %40s", x, y, name));
     64     }
     65     virtual void config(const char name[]) {
     66         fLogger.logProgress(SkStringPrintf("   %s:", name));
     67     }
     68     virtual void timer(const char name[], double ms) {
     69         fLogger.logProgress(SkStringPrintf("  %s = ", name));
     70         fLogger.logProgress(SkStringPrintf(fTimeFormat, ms));
     71     }
     72     virtual void end() {
     73         fLogger.logProgress("\n");
     74     }
     75 private:
     76     BenchLogger& fLogger;
     77     const char* fTimeFormat;
     78 };
     79 
     80 /**
     81  * This ResultsWriter handles writing out the results in JSON.
     82  *
     83  * The output looks like (except compressed to a single line):
     84  *
     85  *  {
     86  *   "options" : {
     87  *      "alpha" : "0xFF",
     88  *      "scale" : "0",
     89  *      ...
     90  *      "system" : "UNIX"
     91  *   },
     92  *   "results" : [
     93  *      {
     94  *      "name" : "Xfermode_Luminosity_640_480",
     95  *      "results" : [
     96  *         {
     97  *            "name": "565",
     98  *            "cmsecs" : 143.188128906250,
     99  *            "msecs" : 143.835957031250
    100  *         },
    101  *         ...
    102  */
    103 
    104 Json::Value* SkFindNamedNode(Json::Value* root, const char name[]);
    105 class JSONResultsWriter : public ResultsWriter {
    106 public:
    107     explicit JSONResultsWriter(const char filename[])
    108         : fFilename(filename)
    109         , fRoot()
    110         , fResults(fRoot["results"])
    111         , fBench(NULL)
    112         , fConfig(NULL) {
    113     }
    114     virtual void option(const char name[], const char value[]) {
    115         fRoot["options"][name] = value;
    116     }
    117     virtual void bench(const char name[], int32_t x, int32_t y) {
    118         SkString sk_name(name);
    119         sk_name.append("_");
    120         sk_name.appendS32(x);
    121         sk_name.append("_");
    122         sk_name.appendS32(y);
    123         Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str());
    124         fBench = &(*bench_node)["results"];
    125     }
    126     virtual void config(const char name[]) {
    127         SkASSERT(NULL != fBench);
    128         fConfig = SkFindNamedNode(fBench, name);
    129     }
    130     virtual void timer(const char name[], double ms) {
    131         SkASSERT(NULL != fConfig);
    132         (*fConfig)[name] = ms;
    133     }
    134     virtual void end() {
    135         SkFILEWStream stream(fFilename.c_str());
    136         stream.writeText(Json::FastWriter().write(fRoot).c_str());
    137         stream.flush();
    138     }
    139 private:
    140 
    141     SkString fFilename;
    142     Json::Value fRoot;
    143     Json::Value& fResults;
    144     Json::Value* fBench;
    145     Json::Value* fConfig;
    146 };
    147 
    148 /**
    149  * This ResultsWriter writes out to multiple ResultsWriters.
    150  */
    151 class MultiResultsWriter : public ResultsWriter {
    152 public:
    153     MultiResultsWriter() : writers() {
    154     };
    155     void add(ResultsWriter* writer) {
    156       writers.push_back(writer);
    157     }
    158     virtual void option(const char name[], const char value[]) {
    159         for (int i = 0; i < writers.count(); ++i) {
    160             writers[i]->option(name, value);
    161         }
    162     }
    163     virtual void bench(const char name[], int32_t x, int32_t y) {
    164         for (int i = 0; i < writers.count(); ++i) {
    165             writers[i]->bench(name, x, y);
    166         }
    167     }
    168     virtual void config(const char name[]) {
    169         for (int i = 0; i < writers.count(); ++i) {
    170             writers[i]->config(name);
    171         }
    172     }
    173     virtual void timer(const char name[], double ms) {
    174         for (int i = 0; i < writers.count(); ++i) {
    175             writers[i]->timer(name, ms);
    176         }
    177     }
    178     virtual void end() {
    179         for (int i = 0; i < writers.count(); ++i) {
    180             writers[i]->end();
    181         }
    182     }
    183 private:
    184     SkTArray<ResultsWriter *> writers;
    185 };
    186 
    187 /**
    188  * Calls the end() method of T on destruction.
    189  */
    190 template <typename T> class CallEnd : SkNoncopyable {
    191 public:
    192     CallEnd(T& obj) : fObj(obj) {}
    193     ~CallEnd() { fObj.end(); }
    194 private:
    195     T&  fObj;
    196 };
    197 
    198 #endif
    199