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 "include/core/SkString.h" 14 #include "include/core/SkTypes.h" 15 #include "src/core/SkOSFile.h" 16 #include "src/utils/SkJSONWriter.h" 17 18 /** 19 NanoJSONResultsWriter helps nanobench writes the test results out in the following format: 20 21 { 22 "key": { 23 "arch": "Arm7", 24 "gpu": "SGX540", 25 "os": "Android", 26 "model": "GalaxyNexus", 27 } 28 "gitHash": "d1830323662ae8ae06908b97f15180fd25808894", 29 "build_number": "1234", 30 "results" : { 31 "Xfermode_Luminosity_640_480" : { 32 "8888" : { 33 "median_ms" : 143.188128906250, 34 "min_ms" : 143.835957031250, 35 ... 36 }, 37 ... 38 */ 39 class NanoJSONResultsWriter : public SkJSONWriter { 40 public: NanoJSONResultsWriter(SkWStream * stream,Mode mode)41 NanoJSONResultsWriter(SkWStream* stream, Mode mode) : SkJSONWriter(stream, mode) {} 42 beginBench(const char * name,int32_t x,int32_t y)43 void beginBench(const char* name, int32_t x, int32_t y) { 44 SkString id = SkStringPrintf("%s_%d_%d", name, x, y); 45 this->beginObject(id.c_str()); 46 } 47 endBench()48 void endBench() { this->endObject(); } 49 appendMetric(const char * name,double value)50 void appendMetric(const char* name, double value) { 51 // Don't record if nan, or -nan. 52 if (!sk_double_isnan(value)) { 53 this->appendDoubleDigits(name, value, 16); 54 } 55 } 56 }; 57 58 /** 59 NanoFILEAppendAndCloseStream: re-open the file, append the data, then close on every write() call. 60 61 The purpose of this class is to not keep the file handle open between JSON flushes. SkJSONWriter 62 uses a 32k in-memory cache already, so it only flushes occasionally and is well equipped for a 63 steam like this. 64 65 See: https://b.corp.google.com/issues/143074513 66 */ 67 class NanoFILEAppendAndCloseStream : public SkWStream { 68 public: NanoFILEAppendAndCloseStream(const char * filePath)69 NanoFILEAppendAndCloseStream(const char* filePath) : fFilePath(filePath) { 70 // Open the file as "write" to ensure it exists and clear any contents before we begin 71 // appending. 72 FILE* file = sk_fopen(fFilePath.c_str(), kWrite_SkFILE_Flag); 73 if (!file) { 74 SkDebugf("Failed to open file %s for write.\n", fFilePath.c_str()); 75 fFilePath.reset(); 76 return; 77 } 78 sk_fclose(file); 79 } 80 bytesWritten()81 size_t bytesWritten() const override { return fBytesWritten; } 82 write(const void * buffer,size_t size)83 bool write(const void* buffer, size_t size) override { 84 if (fFilePath.isEmpty()) { 85 return false; 86 } 87 88 FILE* file = sk_fopen(fFilePath.c_str(), kAppend_SkFILE_Flag); 89 if (!file) { 90 SkDebugf("Failed to open file %s for append.\n", fFilePath.c_str()); 91 return false; 92 } 93 94 size_t bytesWritten = sk_fwrite(buffer, size, file); 95 fBytesWritten += bytesWritten; 96 sk_fclose(file); 97 98 if (bytesWritten != size) { 99 SkDebugf("NanoFILEAppendAndCloseStream failed writing %d bytes (wrote %d instead)\n", 100 size, bytesWritten); 101 return false; 102 } 103 104 return true; 105 } 106 flush()107 void flush() override {} 108 109 private: 110 SkString fFilePath; 111 size_t fBytesWritten = 0; 112 }; 113 114 #endif 115