ResultsWriter.h revision 877a52ae61f41f0b519a906ed2460d44746de8e1
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
10#ifndef SkResultsWriter_DEFINED
11#define SkResultsWriter_DEFINED
12
13#include "BenchLogger.h"
14#include "SkJSONCPP.h"
15#include "SkOSFile.h"
16#include "SkStream.h"
17#include "SkString.h"
18#include "SkTArray.h"
19#include "SkTypes.h"
20
21/**
22 * Base class for writing out the bench results.
23 *
24 * Default implementation does nothing.
25 */
26class ResultsWriter : SkNoncopyable {
27public:
28    virtual ~ResultsWriter() {}
29
30    // Record one key value pair that makes up a unique key for this type of run, e.g.
31    // builder name, machine type, Debug/Release, etc.
32    virtual void key(const char name[], const char value[]) {}
33
34    // Record one key value pair that describes the run instance, e.g. git hash, build number.
35    virtual void property(const char name[], const char value[]) {}
36
37    // Denote the start of a specific benchmark. Once bench is called,
38    // then config and metric can be called multiple times to record runs.
39    virtual void bench(const char name[], int32_t x, int32_t y) {}
40
41    // Record the specific configuration a bench is run under, such as "8888".
42    virtual void config(const char name[]) {}
43
44    // Record the options for a configuration, such as "GL_RENDERER".
45    virtual void configOption(const char name[], const char* value) {}
46
47    // Record a single test metric.
48    virtual void metric(const char name[], double ms) {}
49
50    // Flush to storage now please.
51    virtual void flush() {}
52};
53
54/**
55 NanoJSONResultsWriter writes the test results out in the following
56 format:
57
58 {
59    "key": {
60      "arch": "Arm7",
61      "gpu": "SGX540",
62      "os": "Android",
63      "model": "GalaxyNexus",
64    }
65    "gitHash": "d1830323662ae8ae06908b97f15180fd25808894",
66    "build_number": "1234",
67    "results" : {
68        "Xfermode_Luminosity_640_480" : {
69           "8888" : {
70                 "median_ms" : 143.188128906250,
71                 "min_ms" : 143.835957031250,
72                 ...
73              },
74          ...
75*/
76class NanoJSONResultsWriter : public ResultsWriter {
77public:
78    explicit NanoJSONResultsWriter(const char filename[])
79        : fFilename(filename)
80        , fRoot()
81        , fResults(fRoot["results"])
82        , fBench(NULL)
83        , fConfig(NULL) {}
84
85    ~NanoJSONResultsWriter() {
86        this->flush();
87    }
88
89    // Added under "key".
90    virtual void key(const char name[], const char value[]) {
91        fRoot["key"][name] = value;
92    }
93    // Inserted directly into the root.
94    virtual void property(const char name[], const char value[]) {
95        fRoot[name] = value;
96    }
97    virtual void bench(const char name[], int32_t x, int32_t y) {
98        SkString id = SkStringPrintf( "%s_%d_%d", name, x, y);
99        fResults[id.c_str()] = Json::Value(Json::objectValue);
100        fBench = &fResults[id.c_str()];
101    }
102    virtual void config(const char name[]) {
103        SkASSERT(fBench);
104        fConfig = &(*fBench)[name];
105    }
106    virtual void configOption(const char name[], const char* value) {
107        (*fConfig)["options"][name] = value;
108    }
109    virtual void metric(const char name[], double ms) {
110        // Don't record if nan, or -nan.
111        if (sk_double_isnan(ms)) {
112            return;
113        }
114        SkASSERT(fConfig);
115        (*fConfig)[name] = ms;
116    }
117
118    // Flush to storage now please.
119    virtual void flush() {
120        SkString dirname = SkOSPath::Dirname(fFilename.c_str());
121        if (!sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) {
122            if (!sk_mkdir(dirname.c_str())) {
123                SkDebugf("Failed to create directory.");
124            }
125        }
126        SkFILEWStream stream(fFilename.c_str());
127        stream.writeText(Json::StyledWriter().write(fRoot).c_str());
128        stream.flush();
129    }
130
131private:
132    SkString fFilename;
133    Json::Value fRoot;
134    Json::Value& fResults;
135    Json::Value* fBench;
136    Json::Value* fConfig;
137};
138
139
140#endif
141