diff options
-rw-r--r-- | bench/ResultsWriter.h | 186 | ||||
-rw-r--r-- | bench/benchmain.cpp | 79 | ||||
-rw-r--r-- | gm/gm_expectations.h | 12 | ||||
-rw-r--r-- | gm/gmmain.cpp | 12 | ||||
-rw-r--r-- | gyp/bench.gyp | 1 | ||||
-rw-r--r-- | include/utils/SkJSONCPP.h | 26 |
6 files changed, 252 insertions, 64 deletions
diff --git a/bench/ResultsWriter.h b/bench/ResultsWriter.h new file mode 100644 index 0000000000..29d3d1df41 --- /dev/null +++ b/bench/ResultsWriter.h @@ -0,0 +1,186 @@ +/* + * 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 "SkBenchLogger.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(SkBenchLogger& 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: + SkBenchLogger& fLogger; + const char* fTimeFormat; +}; + +/** + * This ResultsWriter handles writing out the results in JSON. + * + * The output looks like: + * + * { + * "options" : { + * "alpha" : "0xFF", + * "scale" : "0", + * ... + * "system" : "UNIX" + * }, + * "results" : { + * "Xfermode_Luminosity_640_480" : { + * "565" : { + * "cmsecs" : 143.188128906250, + * "msecs" : 143.835957031250 + * }, + * ... + */ +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) { + fBench = &fResults[SkStringPrintf( "%s_%d_%d", name, x, y).c_str()]; + } + virtual void config(const char name[]) { + SkASSERT(NULL != fBench); + fConfig = &(*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(fRoot.toStyledString().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 diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 697f4fb6cc..59c48dbb86 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -6,6 +6,7 @@ */ #include "BenchTimer.h" +#include "ResultsWriter.h" #include "SkBenchLogger.h" #include "SkBenchmark.h" #include "SkBitmapDevice.h" @@ -275,6 +276,7 @@ DEFINE_double(error, 0.01, DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); DEFINE_bool2(verbose, v, false, "Print more."); DEFINE_string2(resourcePath, i, NULL, "directory for test resources."); +DEFINE_string(outResultsFile, "", "If given, the results will be written to the file in JSON format."); // Has this bench converged? First arguments are milliseconds / loop iteration, // last is overall runtime in milliseconds. @@ -296,12 +298,23 @@ int tool_main(int argc, char** argv) { SkCommandLineFlags::Parse(argc, argv); // First, parse some flags. - SkBenchLogger logger; if (FLAGS_logFile.count()) { logger.SetLogFile(FLAGS_logFile[0]); } + LoggerResultsWriter logWriter(logger, FLAGS_timeFormat[0]); + MultiResultsWriter writer; + writer.add(&logWriter); + SkAutoTDelete<JSONResultsWriter> jsonWriter; + if (FLAGS_outResultsFile.count()) { + jsonWriter.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0]))); + writer.add(jsonWriter.get()); + } + // Instantiate after all the writers have been added to writer so that we + // call close() before their destructors are called on the way out. + CallEnd<MultiResultsWriter> ender(writer); + const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF; SkTriState::State dither = SkTriState::kDefault; for (size_t i = 0; i < 3; i++) { @@ -384,36 +397,39 @@ int tool_main(int argc, char** argv) { logger.logError("bench was built in Debug mode, so we're going to hide the times." " It's for your own good!\n"); } - SkString str("skia bench:"); - str.appendf(" mode=%s", FLAGS_mode[0]); - str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s", - alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither]); - str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_clip); + writer.option("mode", FLAGS_mode[0]); + writer.option("alpha", SkStringPrintf("0x%02X", alpha).c_str()); + writer.option("antialias", SkStringPrintf("%d", FLAGS_forceAA).c_str()); + writer.option("filter", SkStringPrintf("%d", FLAGS_forceFilter).c_str()); + writer.option("dither", SkTriState::Name[dither]); + + writer.option("rotate", SkStringPrintf("%d", FLAGS_rotate).c_str()); + writer.option("scale", SkStringPrintf("%d", FLAGS_scale).c_str()); + writer.option("clip", SkStringPrintf("%d", FLAGS_clip).c_str()); #if defined(SK_SCALAR_IS_FIXED) - str.append(" scalar=fixed"); + writer.option("scalar", "fixed"); #else - str.append(" scalar=float"); + writer.option("scalar", "float"); #endif #if defined(SK_BUILD_FOR_WIN32) - str.append(" system=WIN32"); + writer.option("system", "WIN32"); #elif defined(SK_BUILD_FOR_MAC) - str.append(" system=MAC"); + writer.option("system", "MAC"); #elif defined(SK_BUILD_FOR_ANDROID) - str.append(" system=ANDROID"); + writer.option("system", "ANDROID"); #elif defined(SK_BUILD_FOR_UNIX) - str.append(" system=UNIX"); + writer.option("system", "UNIX"); #else - str.append(" system=other"); + writer.option("system", "other"); #endif #if defined(SK_DEBUG) - str.append(" DEBUG"); + writer.option("build", "DEBUG"); +#else + writer.option("build", "RELEASE"); #endif - str.append("\n"); - logger.logProgress(str); - // Set texture cache limits if non-default. for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { @@ -440,21 +456,9 @@ int tool_main(int argc, char** argv) { #endif } - // Find the longest name of the benches we're going to run to make the output pretty. - Iter names; - SkBenchmark* bench; - size_t longestName = 0; - while ((bench = names.next()) != NULL) { - SkAutoTUnref<SkBenchmark> benchUnref(bench); - if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { - continue; - } - const size_t length = strlen(bench->getName()); - longestName = length > longestName ? length : longestName; - } - // Run each bench in each configuration it supports and we asked for. Iter iter; + SkBenchmark* bench; while ((bench = iter.next()) != NULL) { SkAutoTUnref<SkBenchmark> benchUnref(bench); if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { @@ -537,10 +541,7 @@ int tool_main(int argc, char** argv) { if (!loggedBenchName) { loggedBenchName = true; - SkString str; - str.printf("running bench [%3d %3d] %*s ", - dim.fX, dim.fY, (int)longestName, bench->getName()); - logger.logProgress(str); + writer.bench(bench->getName(), dim.fX, dim.fY); } #if SK_SUPPORT_GPU @@ -679,18 +680,12 @@ int tool_main(int argc, char** argv) { {'g', "gmsecs", normalize * timer.fGpu}, }; - SkString result; - result.appendf(" %s:", config.name); + writer.config(config.name); for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) { if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) { - result.appendf(" %s = ", times[i].longName); - result.appendf(FLAGS_timeFormat[0], times[i].ms); + writer.timer(times[i].longName, times[i].ms); } } - logger.logProgress(result); - } - if (loggedBenchName) { - logger.logProgress("\n"); } } #if SK_SUPPORT_GPU diff --git a/gm/gm_expectations.h b/gm/gm_expectations.h index 5ff009e167..c6a2693b17 100644 --- a/gm/gm_expectations.h +++ b/gm/gm_expectations.h @@ -11,22 +11,12 @@ #include "SkBitmap.h" #include "SkBitmapHasher.h" #include "SkData.h" +#include "SkJSONCPP.h" #include "SkOSFile.h" #include "SkRefCnt.h" #include "SkStream.h" #include "SkTArray.h" -#ifdef SK_BUILD_FOR_WIN - // json includes xlocale which generates warning 4530 because we're compiling without - // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 - #pragma warning(push) - #pragma warning(disable : 4530) -#endif -#include "json/reader.h" -#include "json/value.h" -#ifdef SK_BUILD_FOR_WIN - #pragma warning(pop) -#endif namespace skiagm { diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index 86a346da66..c4283a8422 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -30,6 +30,7 @@ #include "SkGraphics.h" #include "SkImageDecoder.h" #include "SkImageEncoder.h" +#include "SkJSONCPP.h" #include "SkOSFile.h" #include "SkPDFRasterizer.h" #include "SkPicture.h" @@ -50,17 +51,6 @@ static const bool kDebugOnly = false; __SK_FORCE_IMAGE_DECODER_LINKING; -#ifdef SK_BUILD_FOR_WIN - // json includes xlocale which generates warning 4530 because we're compiling without - // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 - #pragma warning(push) - #pragma warning(disable : 4530) -#endif -#include "json/value.h" -#ifdef SK_BUILD_FOR_WIN - #pragma warning(pop) -#endif - #if SK_SUPPORT_GPU #include "GrContextFactory.h" #include "SkGpuDevice.h" diff --git a/gyp/bench.gyp b/gyp/bench.gyp index 2a852b7ddf..5f38b0949d 100644 --- a/gyp/bench.gyp +++ b/gyp/bench.gyp @@ -17,6 +17,7 @@ 'skia_lib.gyp:skia_lib', 'bench_timer', 'flags.gyp:flags', + 'jsoncpp.gyp:jsoncpp', ], 'sources': [ '../bench/AAClipBench.cpp', diff --git a/include/utils/SkJSONCPP.h b/include/utils/SkJSONCPP.h new file mode 100644 index 0000000000..8dbb40c91b --- /dev/null +++ b/include/utils/SkJSONCPP.h @@ -0,0 +1,26 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * A common place to put the jsoncpp library includes, as opposed to littering + * the pragmas repeatedly through our code. + */ +#ifndef SkJSONCPP_DEFINED +#define SkJSONCPP_DEFINED + +#ifdef SK_BUILD_FOR_WIN + // json includes xlocale which generates warning 4530 because we're + // compiling without exceptions; + // see https://code.google.com/p/skia/issues/detail?id=1067 + #pragma warning(push) + #pragma warning(disable : 4530) +#endif +#include "json/reader.h" +#include "json/value.h" +#ifdef SK_BUILD_FOR_WIN + #pragma warning(pop) +#endif + +#endif |