ResultsWriter.h revision 3089004cc88e919526e43a8122a74db8f0a7790b
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 */ 25class ResultsWriter : SkNoncopyable { 26public: 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 */ 51class LoggerResultsWriter : public ResultsWriter { 52public: 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 } 75private: 76 SkBenchLogger& fLogger; 77 const char* fTimeFormat; 78}; 79 80#ifdef SK_BUILD_JSON_WRITER 81/** 82 * This ResultsWriter handles writing out the results in JSON. 83 * 84 * The output looks like (except compressed to a single line): 85 * 86 * { 87 * "options" : { 88 * "alpha" : "0xFF", 89 * "scale" : "0", 90 * ... 91 * "system" : "UNIX" 92 * }, 93 * "results" : [ 94 * { 95 * "name" : "Xfermode_Luminosity_640_480", 96 * "results" : [ 97 * { 98 * "name": "565", 99 * "cmsecs" : 143.188128906250, 100 * "msecs" : 143.835957031250 101 * }, 102 * ... 103 */ 104 105Json::Value* SkFindNamedNode(Json::Value* root, const char name[]); 106class JSONResultsWriter : public ResultsWriter { 107public: 108 explicit JSONResultsWriter(const char filename[]) 109 : fFilename(filename) 110 , fRoot() 111 , fResults(fRoot["results"]) 112 , fBench(NULL) 113 , fConfig(NULL) { 114 } 115 virtual void option(const char name[], const char value[]) { 116 fRoot["options"][name] = value; 117 } 118 virtual void bench(const char name[], int32_t x, int32_t y) { 119 SkString sk_name(name); 120 sk_name.append("_"); 121 sk_name.appendS32(x); 122 sk_name.append("_"); 123 sk_name.appendS32(y); 124 Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str()); 125 fBench = &(*bench_node)["results"]; 126 } 127 virtual void config(const char name[]) { 128 SkASSERT(NULL != fBench); 129 fConfig = SkFindNamedNode(fBench, name); 130 } 131 virtual void timer(const char name[], double ms) { 132 SkASSERT(NULL != fConfig); 133 (*fConfig)[name] = ms; 134 } 135 virtual void end() { 136 SkFILEWStream stream(fFilename.c_str()); 137 stream.writeText(Json::FastWriter().write(fRoot).c_str()); 138 stream.flush(); 139 } 140private: 141 142 SkString fFilename; 143 Json::Value fRoot; 144 Json::Value& fResults; 145 Json::Value* fBench; 146 Json::Value* fConfig; 147}; 148 149#endif // SK_BUILD_JSON_WRITER 150 151/** 152 * This ResultsWriter writes out to multiple ResultsWriters. 153 */ 154class MultiResultsWriter : public ResultsWriter { 155public: 156 MultiResultsWriter() : writers() { 157 }; 158 void add(ResultsWriter* writer) { 159 writers.push_back(writer); 160 } 161 virtual void option(const char name[], const char value[]) { 162 for (int i = 0; i < writers.count(); ++i) { 163 writers[i]->option(name, value); 164 } 165 } 166 virtual void bench(const char name[], int32_t x, int32_t y) { 167 for (int i = 0; i < writers.count(); ++i) { 168 writers[i]->bench(name, x, y); 169 } 170 } 171 virtual void config(const char name[]) { 172 for (int i = 0; i < writers.count(); ++i) { 173 writers[i]->config(name); 174 } 175 } 176 virtual void timer(const char name[], double ms) { 177 for (int i = 0; i < writers.count(); ++i) { 178 writers[i]->timer(name, ms); 179 } 180 } 181 virtual void end() { 182 for (int i = 0; i < writers.count(); ++i) { 183 writers[i]->end(); 184 } 185 } 186private: 187 SkTArray<ResultsWriter *> writers; 188}; 189 190/** 191 * Calls the end() method of T on destruction. 192 */ 193template <typename T> class CallEnd : SkNoncopyable { 194public: 195 CallEnd(T& obj) : fObj(obj) {} 196 ~CallEnd() { fObj.end(); } 197private: 198 T& fObj; 199}; 200 201#endif 202