blob: dc45f192f5eecfba97ee21d7ca50d044f249313a [file] [log] [blame]
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +00001/*
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 */
tfarinaf168b862014-06-19 12:32:29 -07009
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000010#ifndef SkResultsWriter_DEFINED
11#define SkResultsWriter_DEFINED
12
tfarinaf168b862014-06-19 12:32:29 -070013#include "BenchLogger.h"
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000014#include "SkJSONCPP.h"
15#include "SkStream.h"
16#include "SkString.h"
17#include "SkTArray.h"
18#include "SkTypes.h"
19
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000020/**
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
jcgregoriobf5e5232014-07-17 13:14:16 -070029 // 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;
32
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000033 // Records one option set for this run. All options must be set before
34 // calling bench().
35 virtual void option(const char name[], const char value[]) = 0;
36
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;
40
41 // Records the specific configuration a bench is run under, such as "8888".
42 virtual void config(const char name[]) = 0;
43
jcgregoriobf5e5232014-07-17 13:14:16 -070044 // Records the options for a configuration, such as "GL_RENDERER".
45 virtual void configOption(const char name[], const char* value) = 0;
46
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000047 // Records a single test metric.
48 virtual void timer(const char name[], double ms) = 0;
49
50 // Call when all results are finished.
51 virtual void end() = 0;
52};
53
54/**
55 * This ResultsWriter handles writing out the human readable format of the
56 * bench results.
57 */
58class LoggerResultsWriter : public ResultsWriter {
59public:
tfarinaf168b862014-06-19 12:32:29 -070060 explicit LoggerResultsWriter(BenchLogger& logger, const char* timeFormat)
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000061 : fLogger(logger)
62 , fTimeFormat(timeFormat) {
63 fLogger.logProgress("skia bench:");
64 }
jcgregoriobf5e5232014-07-17 13:14:16 -070065 virtual void key(const char name[], const char value[]) {
66 // Don't log keys to keep microbench output unchanged.
67 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000068 virtual void option(const char name[], const char value[]) {
69 fLogger.logProgress(SkStringPrintf(" %s=%s", name, value));
70 }
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));
74 }
75 virtual void config(const char name[]) {
76 fLogger.logProgress(SkStringPrintf(" %s:", name));
77 }
jcgregoriobf5e5232014-07-17 13:14:16 -070078 virtual void configOption(const char name[], const char* value) {
79 // Don't log configOptions to keep microbench output unchanged.
80 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000081 virtual void timer(const char name[], double ms) {
82 fLogger.logProgress(SkStringPrintf(" %s = ", name));
83 fLogger.logProgress(SkStringPrintf(fTimeFormat, ms));
84 }
85 virtual void end() {
86 fLogger.logProgress("\n");
87 }
88private:
tfarinaf168b862014-06-19 12:32:29 -070089 BenchLogger& fLogger;
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000090 const char* fTimeFormat;
91};
92
93/**
94 * This ResultsWriter handles writing out the results in JSON.
95 *
commit-bot@chromium.org97133ad2014-05-20 17:35:10 +000096 * The output looks like (except compressed to a single line):
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +000097 *
98 * {
99 * "options" : {
100 * "alpha" : "0xFF",
101 * "scale" : "0",
102 * ...
103 * "system" : "UNIX"
104 * },
commit-bot@chromium.org97133ad2014-05-20 17:35:10 +0000105 * "results" : [
106 * {
107 * "name" : "Xfermode_Luminosity_640_480",
108 * "results" : [
109 * {
110 * "name": "565",
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000111 * "cmsecs" : 143.188128906250,
112 * "msecs" : 143.835957031250
113 * },
114 * ...
115 */
commit-bot@chromium.org293a4b32014-05-27 21:51:38 +0000116
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000117Json::Value* SkFindNamedNode(Json::Value* root, const char name[]);
kelvinly4d1a3642014-06-26 11:26:40 -0700118Json::Value SkMakeBuilderJSON(const SkString &buildername);
119
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000120class JSONResultsWriter : public ResultsWriter {
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000121public:
122 explicit JSONResultsWriter(const char filename[])
123 : fFilename(filename)
124 , fRoot()
125 , fResults(fRoot["results"])
126 , fBench(NULL)
127 , fConfig(NULL) {
128 }
jcgregoriobf5e5232014-07-17 13:14:16 -0700129 virtual void key(const char name[], const char value[]) {
130 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000131 virtual void option(const char name[], const char value[]) {
132 fRoot["options"][name] = value;
133 }
134 virtual void bench(const char name[], int32_t x, int32_t y) {
commit-bot@chromium.org97133ad2014-05-20 17:35:10 +0000135 SkString sk_name(name);
136 sk_name.append("_");
137 sk_name.appendS32(x);
138 sk_name.append("_");
139 sk_name.appendS32(y);
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000140 Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str());
commit-bot@chromium.org71e55762014-05-19 17:29:01 +0000141 fBench = &(*bench_node)["results"];
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000142 }
143 virtual void config(const char name[]) {
144 SkASSERT(NULL != fBench);
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000145 fConfig = SkFindNamedNode(fBench, name);
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000146 }
jcgregoriobf5e5232014-07-17 13:14:16 -0700147 virtual void configOption(const char name[], const char* value) {
148 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000149 virtual void timer(const char name[], double ms) {
150 SkASSERT(NULL != fConfig);
151 (*fConfig)[name] = ms;
152 }
153 virtual void end() {
154 SkFILEWStream stream(fFilename.c_str());
commit-bot@chromium.org97133ad2014-05-20 17:35:10 +0000155 stream.writeText(Json::FastWriter().write(fRoot).c_str());
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000156 stream.flush();
157 }
158private:
commit-bot@chromium.org97133ad2014-05-20 17:35:10 +0000159
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000160 SkString fFilename;
161 Json::Value fRoot;
162 Json::Value& fResults;
163 Json::Value* fBench;
164 Json::Value* fConfig;
165};
166
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000167/**
jcgregoriobf5e5232014-07-17 13:14:16 -0700168 NanoJSONResultsWriter writes the test results out in the following
169 format:
170
171 {
172 "key": {
173 "arch": "Arm7",
174 "gpu": "SGX540",
175 "os": "Android",
176 "model": "GalaxyNexus",
177 }
178 "options": {
179 "GL_Version": "3.1",
180 ...
181 },
182 "gitHash": "d1830323662ae8ae06908b97f15180fd25808894",
183 "results" : {
184 "Xfermode_Luminosity_640_480" : {
185 "8888" : {
186 "median_ms" : 143.188128906250,
187 "min_ms" : 143.835957031250,
188 ...
189 },
190 ...
191*/
192class NanoJSONResultsWriter : public ResultsWriter {
193public:
194 explicit NanoJSONResultsWriter(const char filename[], const char gitHash[])
195 : fFilename(filename)
196 , fRoot()
197 , fResults(fRoot["results"])
198 , fBench(NULL)
199 , fConfig(NULL) {
200 fRoot["gitHash"] = gitHash;
201 }
202 virtual void key(const char name[], const char value[]) {
203 fRoot["key"][name] = value;
204 }
205 virtual void option(const char name[], const char value[]) {
206 fRoot["options"][name] = value;
207 }
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()];
212 }
213 virtual void config(const char name[]) {
214 SkASSERT(NULL != fBench);
215 fConfig = &(*fBench)[name];
216 }
217 virtual void configOption(const char name[], const char* value) {
218 (*fConfig)["options"][name] = value;
219 }
220 virtual void timer(const char name[], double ms) {
221 // Don't record if nan, or -nan.
222 if (sk_double_isnan(ms)) {
223 return;
224 }
225 SkASSERT(NULL != fConfig);
226 (*fConfig)[name] = ms;
227 }
228 virtual void end() {
229 SkFILEWStream stream(fFilename.c_str());
230 stream.writeText(Json::FastWriter().write(fRoot).c_str());
231 stream.flush();
232 }
233private:
234
235 SkString fFilename;
236 Json::Value fRoot;
237 Json::Value& fResults;
238 Json::Value* fBench;
239 Json::Value* fConfig;
240};
241
242
243/**
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000244 * This ResultsWriter writes out to multiple ResultsWriters.
245 */
246class MultiResultsWriter : public ResultsWriter {
247public:
248 MultiResultsWriter() : writers() {
249 };
250 void add(ResultsWriter* writer) {
251 writers.push_back(writer);
252 }
jcgregoriobf5e5232014-07-17 13:14:16 -0700253 virtual void key(const char name[], const char value[]) {
254 for (int i = 0; i < writers.count(); ++i) {
255 writers[i]->key(name, value);
256 }
257 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000258 virtual void option(const char name[], const char value[]) {
259 for (int i = 0; i < writers.count(); ++i) {
260 writers[i]->option(name, value);
261 }
262 }
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);
266 }
267 }
268 virtual void config(const char name[]) {
269 for (int i = 0; i < writers.count(); ++i) {
270 writers[i]->config(name);
271 }
272 }
jcgregoriobf5e5232014-07-17 13:14:16 -0700273 virtual void configOption(const char name[], const char* value) {
274 for (int i = 0; i < writers.count(); ++i) {
275 writers[i]->configOption(name, value);
276 }
277 }
commit-bot@chromium.orge3bb3bc2013-12-03 18:16:48 +0000278 virtual void timer(const char name[], double ms) {
279 for (int i = 0; i < writers.count(); ++i) {
280 writers[i]->timer(name, ms);
281 }
282 }
283 virtual void end() {
284 for (int i = 0; i < writers.count(); ++i) {
285 writers[i]->end();
286 }
287 }
288private:
289 SkTArray<ResultsWriter *> writers;
290};
291
292/**
293 * Calls the end() method of T on destruction.
294 */
295template <typename T> class CallEnd : SkNoncopyable {
296public:
297 CallEnd(T& obj) : fObj(obj) {}
298 ~CallEnd() { fObj.end(); }
299private:
300 T& fObj;
301};
302
303#endif