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