Add JSON logging support to bench_pictures by adding a PictureResultsWriter class...
[platform/upstream/libSkiaSharp.git] / bench / ResultsWriter.h
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 #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
105 Json::Value* SkFindNamedNode(Json::Value* root, const char name[]);
106 class JSONResultsWriter : public ResultsWriter {
107 public:
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     }
140 private:
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  */
154 class MultiResultsWriter : public ResultsWriter {
155 public:
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     }
186 private:
187     SkTArray<ResultsWriter *> writers;
188 };
189
190 /**
191  * Calls the end() method of T on destruction.
192  */
193 template <typename T> class CallEnd : SkNoncopyable {
194 public:
195     CallEnd(T& obj) : fObj(obj) {}
196     ~CallEnd() { fObj.end(); }
197 private:
198     T&  fObj;
199 };
200
201 #endif