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 #ifndef SkResultsWriter_DEFINED 10 #define SkResultsWriter_DEFINED 11 12 #include "SkBenchLogger.h" 13 #include "SkJSONCPP.h" 14 #include "SkStream.h" 15 #include "SkString.h" 16 #include "SkTArray.h" 17 #include "SkTypes.h" 18 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(SkBenchLogger& 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 SkBenchLogger& fLogger; 77 const char* fTimeFormat; 78 }; 79 80 /** 81 * This ResultsWriter handles writing out the results in JSON. 82 * 83 * The output looks like: 84 * 85 * { 86 * "options" : { 87 * "alpha" : "0xFF", 88 * "scale" : "0", 89 * ... 90 * "system" : "UNIX" 91 * }, 92 * "results" : { 93 * "Xfermode_Luminosity_640_480" : { 94 * "565" : { 95 * "cmsecs" : 143.188128906250, 96 * "msecs" : 143.835957031250 97 * }, 98 * ... 99 */ 100 class JSONResultsWriter : public ResultsWriter { 101 public: 102 explicit JSONResultsWriter(const char filename[]) 103 : fFilename(filename) 104 , fRoot() 105 , fResults(fRoot["results"]) 106 , fBench(NULL) 107 , fConfig(NULL) { 108 } 109 virtual void option(const char name[], const char value[]) { 110 fRoot["options"][name] = value; 111 } 112 virtual void bench(const char name[], int32_t x, int32_t y) { 113 fBench = &fResults[SkStringPrintf( "%s_%d_%d", name, x, y).c_str()]; 114 } 115 virtual void config(const char name[]) { 116 SkASSERT(NULL != fBench); 117 fConfig = &(*fBench)[name]; 118 } 119 virtual void timer(const char name[], double ms) { 120 SkASSERT(NULL != fConfig); 121 (*fConfig)[name] = ms; 122 } 123 virtual void end() { 124 SkFILEWStream stream(fFilename.c_str()); 125 stream.writeText(fRoot.toStyledString().c_str()); 126 stream.flush(); 127 } 128 private: 129 SkString fFilename; 130 Json::Value fRoot; 131 Json::Value& fResults; 132 Json::Value* fBench; 133 Json::Value* fConfig; 134 }; 135 136 /** 137 * This ResultsWriter writes out to multiple ResultsWriters. 138 */ 139 class MultiResultsWriter : public ResultsWriter { 140 public: 141 MultiResultsWriter() : writers() { 142 }; 143 void add(ResultsWriter* writer) { 144 writers.push_back(writer); 145 } 146 virtual void option(const char name[], const char value[]) { 147 for (int i = 0; i < writers.count(); ++i) { 148 writers[i]->option(name, value); 149 } 150 } 151 virtual void bench(const char name[], int32_t x, int32_t y) { 152 for (int i = 0; i < writers.count(); ++i) { 153 writers[i]->bench(name, x, y); 154 } 155 } 156 virtual void config(const char name[]) { 157 for (int i = 0; i < writers.count(); ++i) { 158 writers[i]->config(name); 159 } 160 } 161 virtual void timer(const char name[], double ms) { 162 for (int i = 0; i < writers.count(); ++i) { 163 writers[i]->timer(name, ms); 164 } 165 } 166 virtual void end() { 167 for (int i = 0; i < writers.count(); ++i) { 168 writers[i]->end(); 169 } 170 } 171 private: 172 SkTArray<ResultsWriter *> writers; 173 }; 174 175 /** 176 * Calls the end() method of T on destruction. 177 */ 178 template <typename T> class CallEnd : SkNoncopyable { 179 public: 180 CallEnd(T& obj) : fObj(obj) {} 181 ~CallEnd() { fObj.end(); } 182 private: 183 T& fObj; 184 }; 185 186 #endif 187