aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/ResultsWriter.h186
-rw-r--r--bench/benchmain.cpp79
-rw-r--r--gm/gm_expectations.h12
-rw-r--r--gm/gmmain.cpp12
-rw-r--r--gyp/bench.gyp1
-rw-r--r--include/utils/SkJSONCPP.h26
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