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