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