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 "SkStream.h" 16 #include "SkString.h" 17 #include "SkTArray.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: ~ResultsWriter()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. key(const char name[],const char value[])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. property(const char name[],const char value[])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 timer can be called multiple times to record runs. bench(const char name[],int32_t x,int32_t y)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". config(const char name[])41 virtual void config(const char name[]) {} 42 43 // Record the options for a configuration, such as "GL_RENDERER". configOption(const char name[],const char * value)44 virtual void configOption(const char name[], const char* value) {} 45 46 // Record a single test metric. timer(const char name[],double ms)47 virtual void timer(const char name[], double ms) {} 48 }; 49 50 /** 51 NanoJSONResultsWriter writes the test results out in the following 52 format: 53 54 { 55 "key": { 56 "arch": "Arm7", 57 "gpu": "SGX540", 58 "os": "Android", 59 "model": "GalaxyNexus", 60 } 61 "gitHash": "d1830323662ae8ae06908b97f15180fd25808894", 62 "build_number": "1234", 63 "results" : { 64 "Xfermode_Luminosity_640_480" : { 65 "8888" : { 66 "median_ms" : 143.188128906250, 67 "min_ms" : 143.835957031250, 68 ... 69 }, 70 ... 71 */ 72 class NanoJSONResultsWriter : public ResultsWriter { 73 public: NanoJSONResultsWriter(const char filename[])74 explicit NanoJSONResultsWriter(const char filename[]) 75 : fFilename(filename) 76 , fRoot() 77 , fResults(fRoot["results"]) 78 , fBench(NULL) 79 , fConfig(NULL) {} 80 ~NanoJSONResultsWriter()81 ~NanoJSONResultsWriter() { 82 SkFILEWStream stream(fFilename.c_str()); 83 stream.writeText(Json::StyledWriter().write(fRoot).c_str()); 84 stream.flush(); 85 } 86 87 // Added under "key". key(const char name[],const char value[])88 virtual void key(const char name[], const char value[]) { 89 fRoot["key"][name] = value; 90 } 91 // Inserted directly into the root. property(const char name[],const char value[])92 virtual void property(const char name[], const char value[]) { 93 fRoot[name] = value; 94 } bench(const char name[],int32_t x,int32_t y)95 virtual void bench(const char name[], int32_t x, int32_t y) { 96 SkString id = SkStringPrintf( "%s_%d_%d", name, x, y); 97 fResults[id.c_str()] = Json::Value(Json::objectValue); 98 fBench = &fResults[id.c_str()]; 99 } config(const char name[])100 virtual void config(const char name[]) { 101 SkASSERT(fBench); 102 fConfig = &(*fBench)[name]; 103 } configOption(const char name[],const char * value)104 virtual void configOption(const char name[], const char* value) { 105 (*fConfig)["options"][name] = value; 106 } timer(const char name[],double ms)107 virtual void timer(const char name[], double ms) { 108 // Don't record if nan, or -nan. 109 if (sk_double_isnan(ms)) { 110 return; 111 } 112 SkASSERT(fConfig); 113 (*fConfig)[name] = ms; 114 } 115 116 private: 117 SkString fFilename; 118 Json::Value fRoot; 119 Json::Value& fResults; 120 Json::Value* fBench; 121 Json::Value* fConfig; 122 }; 123 124 125 #endif 126