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