1e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org/*
2e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org * Copyright 2013 Google Inc.
3e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org *
4e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
5e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org * found in the LICENSE file.
6e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org *
7e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org * Classes for writing out bench results in various formats.
8e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org */
9f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina
10e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#ifndef SkResultsWriter_DEFINED
11e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#define SkResultsWriter_DEFINED
12e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
13f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina#include "BenchLogger.h"
14e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#include "SkJSONCPP.h"
15877a52ae61f41f0b519a906ed2460d44746de8e1borenet#include "SkOSFile.h"
16e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#include "SkStream.h"
17e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#include "SkString.h"
18e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#include "SkTypes.h"
19e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
20e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org/**
21e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org * Base class for writing out the bench results.
22e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org *
231915b62637bea20e1471a8a358b22e9e47a4a385mtklein * Default implementation does nothing.
24e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org */
25e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.orgclass ResultsWriter : SkNoncopyable {
26e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.orgpublic:
271915b62637bea20e1471a8a358b22e9e47a4a385mtklein    virtual ~ResultsWriter() {}
28e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
291915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Record one key value pair that makes up a unique key for this type of run, e.g.
301915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // builder name, machine type, Debug/Release, etc.
311915b62637bea20e1471a8a358b22e9e47a4a385mtklein    virtual void key(const char name[], const char value[]) {}
32bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio
331915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Record one key value pair that describes the run instance, e.g. git hash, build number.
341915b62637bea20e1471a8a358b22e9e47a4a385mtklein    virtual void property(const char name[], const char value[]) {}
35e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
361915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Denote the start of a specific benchmark. Once bench is called,
37051e56df8f14fae68f0e990f78b85494c2ce4a6bmtklein    // then config and metric can be called multiple times to record runs.
381915b62637bea20e1471a8a358b22e9e47a4a385mtklein    virtual void bench(const char name[], int32_t x, int32_t y) {}
39e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
401915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Record the specific configuration a bench is run under, such as "8888".
411915b62637bea20e1471a8a358b22e9e47a4a385mtklein    virtual void config(const char name[]) {}
42e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
431915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Record the options for a configuration, such as "GL_RENDERER".
441915b62637bea20e1471a8a358b22e9e47a4a385mtklein    virtual void configOption(const char name[], const char* value) {}
45bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio
461915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Record a single test metric.
47051e56df8f14fae68f0e990f78b85494c2ce4a6bmtklein    virtual void metric(const char name[], double ms) {}
48e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein
49e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein    // Flush to storage now please.
50e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein    virtual void flush() {}
51bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio};
52bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio
53bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio/**
54bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio NanoJSONResultsWriter writes the test results out in the following
55bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio format:
56bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio
57bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio {
58bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    "key": {
59bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio      "arch": "Arm7",
60bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio      "gpu": "SGX540",
61bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio      "os": "Android",
62bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio      "model": "GalaxyNexus",
63bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
64bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    "gitHash": "d1830323662ae8ae06908b97f15180fd25808894",
651915b62637bea20e1471a8a358b22e9e47a4a385mtklein    "build_number": "1234",
66bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    "results" : {
67bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        "Xfermode_Luminosity_640_480" : {
68bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio           "8888" : {
69bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio                 "median_ms" : 143.188128906250,
70bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio                 "min_ms" : 143.835957031250,
71bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio                 ...
72bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio              },
73bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio          ...
74bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio*/
75bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorioclass NanoJSONResultsWriter : public ResultsWriter {
76bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregoriopublic:
771915b62637bea20e1471a8a358b22e9e47a4a385mtklein    explicit NanoJSONResultsWriter(const char filename[])
78bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        : fFilename(filename)
79bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        , fRoot()
80bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        , fResults(fRoot["results"])
8196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        , fBench(nullptr)
8296fcdcc219d2a0d3579719b84b28bede76efba64halcanary        , fConfig(nullptr) {}
831915b62637bea20e1471a8a358b22e9e47a4a385mtklein
841915b62637bea20e1471a8a358b22e9e47a4a385mtklein    ~NanoJSONResultsWriter() {
85e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein        this->flush();
86bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
871915b62637bea20e1471a8a358b22e9e47a4a385mtklein
881915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Added under "key".
89e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void key(const char name[], const char value[]) override {
90bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        fRoot["key"][name] = value;
91bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
921915b62637bea20e1471a8a358b22e9e47a4a385mtklein    // Inserted directly into the root.
93e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void property(const char name[], const char value[]) override {
941915b62637bea20e1471a8a358b22e9e47a4a385mtklein        fRoot[name] = value;
95bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
96e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void bench(const char name[], int32_t x, int32_t y) override {
97bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        SkString id = SkStringPrintf( "%s_%d_%d", name, x, y);
98bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        fResults[id.c_str()] = Json::Value(Json::objectValue);
99bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        fBench = &fResults[id.c_str()];
100bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
101e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void config(const char name[]) override {
10249f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(fBench);
103bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        fConfig = &(*fBench)[name];
104bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
105e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void configOption(const char name[], const char* value) override {
106bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        (*fConfig)["options"][name] = value;
107bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio    }
108e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void metric(const char name[], double ms) override {
109bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        // Don't record if nan, or -nan.
110bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        if (sk_double_isnan(ms)) {
111bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio            return;
112bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio        }
11349f085dddff10473b6ebf832a974288300224e60bsalomon        SkASSERT(fConfig);
114e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org        (*fConfig)[name] = ms;
115e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org    }
11697133ade536f6333a2dbaec8be6f8347bb12bd79commit-bot@chromium.org
117e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein    // Flush to storage now please.
118e45c81c8f3bb62e45f2ff3b8772b4b23f1ddc6cajoshualitt    void flush() override {
119877a52ae61f41f0b519a906ed2460d44746de8e1borenet        SkString dirname = SkOSPath::Dirname(fFilename.c_str());
120877a52ae61f41f0b519a906ed2460d44746de8e1borenet        if (!sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) {
121877a52ae61f41f0b519a906ed2460d44746de8e1borenet            if (!sk_mkdir(dirname.c_str())) {
122877a52ae61f41f0b519a906ed2460d44746de8e1borenet                SkDebugf("Failed to create directory.");
123877a52ae61f41f0b519a906ed2460d44746de8e1borenet            }
124877a52ae61f41f0b519a906ed2460d44746de8e1borenet        }
125e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein        SkFILEWStream stream(fFilename.c_str());
126e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein        stream.writeText(Json::StyledWriter().write(fRoot).c_str());
127e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein        stream.flush();
128e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein    }
129e070c2bf54c451f0126d4ffb3a48bffe1fbfa437mtklein
1301915b62637bea20e1471a8a358b22e9e47a4a385mtkleinprivate:
131e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org    SkString fFilename;
132e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org    Json::Value fRoot;
133e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org    Json::Value& fResults;
134e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org    Json::Value* fBench;
135e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org    Json::Value* fConfig;
136e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org};
137e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org
138bf5e5237b8f5dc9288d72e90864d6ba8d4bfbb72jcgregorio
139e3bb3bce3e9c1f3bc8ee779b1b3383c18e560bcecommit-bot@chromium.org#endif
140