2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 * Classes for writing out bench results in various formats.
10 #ifndef SkResultsWriter_DEFINED
11 #define SkResultsWriter_DEFINED
13 #include "BenchLogger.h"
14 #include "SkJSONCPP.h"
21 * Base class for writing out the bench results.
23 * TODO(jcgregorio) Add info if tests fail to converge?
25 class ResultsWriter : SkNoncopyable {
27 virtual ~ResultsWriter() {};
29 // Records one key value pair that makes up a unique identifier for this run.
30 // All keys must be set before calling bench().
31 virtual void key(const char name[], const char value[]) = 0;
33 // Records one option set for this run. All options must be set before
35 virtual void option(const char name[], const char value[]) = 0;
37 // Denotes the start of a specific benchmark. Once bench is called,
38 // then config and timer can be called multiple times to record runs.
39 virtual void bench(const char name[], int32_t x, int32_t y) = 0;
41 // Records the specific configuration a bench is run under, such as "8888".
42 virtual void config(const char name[]) = 0;
44 // Records the options for a configuration, such as "GL_RENDERER".
45 virtual void configOption(const char name[], const char* value) = 0;
47 // Records a single test metric.
48 virtual void timer(const char name[], double ms) = 0;
50 // Call when all results are finished.
51 virtual void end() = 0;
55 * This ResultsWriter handles writing out the human readable format of the
58 class LoggerResultsWriter : public ResultsWriter {
60 explicit LoggerResultsWriter(BenchLogger& logger, const char* timeFormat)
62 , fTimeFormat(timeFormat) {
63 fLogger.logProgress("skia bench:");
65 virtual void key(const char name[], const char value[]) {
66 // Don't log keys to keep microbench output unchanged.
68 virtual void option(const char name[], const char value[]) {
69 fLogger.logProgress(SkStringPrintf(" %s=%s", name, value));
71 virtual void bench(const char name[], int32_t x, int32_t y) {
72 fLogger.logProgress(SkStringPrintf(
73 "\nrunning bench [%3d %3d] %40s", x, y, name));
75 virtual void config(const char name[]) {
76 fLogger.logProgress(SkStringPrintf(" %s:", name));
78 virtual void configOption(const char name[], const char* value) {
79 // Don't log configOptions to keep microbench output unchanged.
81 virtual void timer(const char name[], double ms) {
82 fLogger.logProgress(SkStringPrintf(" %s = ", name));
83 fLogger.logProgress(SkStringPrintf(fTimeFormat, ms));
86 fLogger.logProgress("\n");
90 const char* fTimeFormat;
94 * This ResultsWriter handles writing out the results in JSON.
96 * The output looks like (except compressed to a single line):
107 * "name" : "Xfermode_Luminosity_640_480",
111 * "cmsecs" : 143.188128906250,
112 * "msecs" : 143.835957031250
117 Json::Value* SkFindNamedNode(Json::Value* root, const char name[]);
118 Json::Value SkMakeBuilderJSON(const SkString &buildername);
120 class JSONResultsWriter : public ResultsWriter {
122 explicit JSONResultsWriter(const char filename[])
123 : fFilename(filename)
125 , fResults(fRoot["results"])
129 virtual void key(const char name[], const char value[]) {
131 virtual void option(const char name[], const char value[]) {
132 fRoot["options"][name] = value;
134 virtual void bench(const char name[], int32_t x, int32_t y) {
135 SkString sk_name(name);
137 sk_name.appendS32(x);
139 sk_name.appendS32(y);
140 Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str());
141 fBench = &(*bench_node)["results"];
143 virtual void config(const char name[]) {
144 SkASSERT(NULL != fBench);
145 fConfig = SkFindNamedNode(fBench, name);
147 virtual void configOption(const char name[], const char* value) {
149 virtual void timer(const char name[], double ms) {
150 SkASSERT(NULL != fConfig);
151 (*fConfig)[name] = ms;
154 SkFILEWStream stream(fFilename.c_str());
155 stream.writeText(Json::FastWriter().write(fRoot).c_str());
162 Json::Value& fResults;
164 Json::Value* fConfig;
168 NanoJSONResultsWriter writes the test results out in the following
176 "model": "GalaxyNexus",
182 "gitHash": "d1830323662ae8ae06908b97f15180fd25808894",
184 "Xfermode_Luminosity_640_480" : {
186 "median_ms" : 143.188128906250,
187 "min_ms" : 143.835957031250,
192 class NanoJSONResultsWriter : public ResultsWriter {
194 explicit NanoJSONResultsWriter(const char filename[], const char gitHash[])
195 : fFilename(filename)
197 , fResults(fRoot["results"])
200 fRoot["gitHash"] = gitHash;
202 virtual void key(const char name[], const char value[]) {
203 fRoot["key"][name] = value;
205 virtual void option(const char name[], const char value[]) {
206 fRoot["options"][name] = value;
208 virtual void bench(const char name[], int32_t x, int32_t y) {
209 SkString id = SkStringPrintf( "%s_%d_%d", name, x, y);
210 fResults[id.c_str()] = Json::Value(Json::objectValue);
211 fBench = &fResults[id.c_str()];
213 virtual void config(const char name[]) {
214 SkASSERT(NULL != fBench);
215 fConfig = &(*fBench)[name];
217 virtual void configOption(const char name[], const char* value) {
218 (*fConfig)["options"][name] = value;
220 virtual void timer(const char name[], double ms) {
221 // Don't record if nan, or -nan.
222 if (sk_double_isnan(ms)) {
225 SkASSERT(NULL != fConfig);
226 (*fConfig)[name] = ms;
229 SkFILEWStream stream(fFilename.c_str());
230 stream.writeText(Json::FastWriter().write(fRoot).c_str());
237 Json::Value& fResults;
239 Json::Value* fConfig;
244 * This ResultsWriter writes out to multiple ResultsWriters.
246 class MultiResultsWriter : public ResultsWriter {
248 MultiResultsWriter() : writers() {
250 void add(ResultsWriter* writer) {
251 writers.push_back(writer);
253 virtual void key(const char name[], const char value[]) {
254 for (int i = 0; i < writers.count(); ++i) {
255 writers[i]->key(name, value);
258 virtual void option(const char name[], const char value[]) {
259 for (int i = 0; i < writers.count(); ++i) {
260 writers[i]->option(name, value);
263 virtual void bench(const char name[], int32_t x, int32_t y) {
264 for (int i = 0; i < writers.count(); ++i) {
265 writers[i]->bench(name, x, y);
268 virtual void config(const char name[]) {
269 for (int i = 0; i < writers.count(); ++i) {
270 writers[i]->config(name);
273 virtual void configOption(const char name[], const char* value) {
274 for (int i = 0; i < writers.count(); ++i) {
275 writers[i]->configOption(name, value);
278 virtual void timer(const char name[], double ms) {
279 for (int i = 0; i < writers.count(); ++i) {
280 writers[i]->timer(name, ms);
284 for (int i = 0; i < writers.count(); ++i) {
289 SkTArray<ResultsWriter *> writers;
293 * Calls the end() method of T on destruction.
295 template <typename T> class CallEnd : SkNoncopyable {
297 CallEnd(T& obj) : fObj(obj) {}
298 ~CallEnd() { fObj.end(); }