/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Classes for writing out bench results in various formats. */ #ifndef SkResultsWriter_DEFINED #define SkResultsWriter_DEFINED #include "BenchLogger.h" #include "SkJSONCPP.h" #include "SkStream.h" #include "SkString.h" #include "SkTArray.h" #include "SkTypes.h" /** * Base class for writing out the bench results. * * TODO(jcgregorio) Add info if tests fail to converge? */ class ResultsWriter : SkNoncopyable { public: virtual ~ResultsWriter() {}; // Records one option set for this run. All options must be set before // calling bench(). virtual void option(const char name[], const char value[]) = 0; // Denotes the start of a specific benchmark. Once bench is called, // then config and timer can be called multiple times to record runs. virtual void bench(const char name[], int32_t x, int32_t y) = 0; // Records the specific configuration a bench is run under, such as "8888". virtual void config(const char name[]) = 0; // Records a single test metric. virtual void timer(const char name[], double ms) = 0; // Call when all results are finished. virtual void end() = 0; }; /** * This ResultsWriter handles writing out the human readable format of the * bench results. */ class LoggerResultsWriter : public ResultsWriter { public: explicit LoggerResultsWriter(BenchLogger& logger, const char* timeFormat) : fLogger(logger) , fTimeFormat(timeFormat) { fLogger.logProgress("skia bench:"); } virtual void option(const char name[], const char value[]) { fLogger.logProgress(SkStringPrintf(" %s=%s", name, value)); } virtual void bench(const char name[], int32_t x, int32_t y) { fLogger.logProgress(SkStringPrintf( "\nrunning bench [%3d %3d] %40s", x, y, name)); } virtual void config(const char name[]) { fLogger.logProgress(SkStringPrintf(" %s:", name)); } virtual void timer(const char name[], double ms) { fLogger.logProgress(SkStringPrintf(" %s = ", name)); fLogger.logProgress(SkStringPrintf(fTimeFormat, ms)); } virtual void end() { fLogger.logProgress("\n"); } private: BenchLogger& fLogger; const char* fTimeFormat; }; /** * This ResultsWriter handles writing out the results in JSON. * * The output looks like (except compressed to a single line): * * { * "options" : { * "alpha" : "0xFF", * "scale" : "0", * ... * "system" : "UNIX" * }, * "results" : [ * { * "name" : "Xfermode_Luminosity_640_480", * "results" : [ * { * "name": "565", * "cmsecs" : 143.188128906250, * "msecs" : 143.835957031250 * }, * ... */ Json::Value* SkFindNamedNode(Json::Value* root, const char name[]); class JSONResultsWriter : public ResultsWriter { public: explicit JSONResultsWriter(const char filename[]) : fFilename(filename) , fRoot() , fResults(fRoot["results"]) , fBench(NULL) , fConfig(NULL) { } virtual void option(const char name[], const char value[]) { fRoot["options"][name] = value; } virtual void bench(const char name[], int32_t x, int32_t y) { SkString sk_name(name); sk_name.append("_"); sk_name.appendS32(x); sk_name.append("_"); sk_name.appendS32(y); Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str()); fBench = &(*bench_node)["results"]; } virtual void config(const char name[]) { SkASSERT(NULL != fBench); fConfig = SkFindNamedNode(fBench, name); } virtual void timer(const char name[], double ms) { SkASSERT(NULL != fConfig); (*fConfig)[name] = ms; } virtual void end() { SkFILEWStream stream(fFilename.c_str()); stream.writeText(Json::FastWriter().write(fRoot).c_str()); stream.flush(); } private: SkString fFilename; Json::Value fRoot; Json::Value& fResults; Json::Value* fBench; Json::Value* fConfig; }; /** * This ResultsWriter writes out to multiple ResultsWriters. */ class MultiResultsWriter : public ResultsWriter { public: MultiResultsWriter() : writers() { }; void add(ResultsWriter* writer) { writers.push_back(writer); } virtual void option(const char name[], const char value[]) { for (int i = 0; i < writers.count(); ++i) { writers[i]->option(name, value); } } virtual void bench(const char name[], int32_t x, int32_t y) { for (int i = 0; i < writers.count(); ++i) { writers[i]->bench(name, x, y); } } virtual void config(const char name[]) { for (int i = 0; i < writers.count(); ++i) { writers[i]->config(name); } } virtual void timer(const char name[], double ms) { for (int i = 0; i < writers.count(); ++i) { writers[i]->timer(name, ms); } } virtual void end() { for (int i = 0; i < writers.count(); ++i) { writers[i]->end(); } } private: SkTArray<ResultsWriter *> writers; }; /** * Calls the end() method of T on destruction. */ template <typename T> class CallEnd : SkNoncopyable { public: CallEnd(T& obj) : fObj(obj) {} ~CallEnd() { fObj.end(); } private: T& fObj; }; #endif