2013-12-03 18:16:48 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2014-06-19 19:32:29 +00:00
|
|
|
|
2013-12-03 18:16:48 +00:00
|
|
|
#ifndef SkResultsWriter_DEFINED
|
|
|
|
#define SkResultsWriter_DEFINED
|
|
|
|
|
2014-06-19 19:32:29 +00:00
|
|
|
#include "BenchLogger.h"
|
2013-12-03 18:16:48 +00:00
|
|
|
#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() {};
|
|
|
|
|
2014-07-17 20:14:16 +00:00
|
|
|
// Records one key value pair that makes up a unique identifier for this run.
|
|
|
|
// All keys must be set before calling bench().
|
|
|
|
virtual void key(const char name[], const char value[]) = 0;
|
|
|
|
|
2013-12-03 18:16:48 +00:00
|
|
|
// 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;
|
|
|
|
|
2014-07-17 20:14:16 +00:00
|
|
|
// Records the options for a configuration, such as "GL_RENDERER".
|
|
|
|
virtual void configOption(const char name[], const char* value) = 0;
|
|
|
|
|
2013-12-03 18:16:48 +00:00
|
|
|
// 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:
|
2014-06-19 19:32:29 +00:00
|
|
|
explicit LoggerResultsWriter(BenchLogger& logger, const char* timeFormat)
|
2013-12-03 18:16:48 +00:00
|
|
|
: fLogger(logger)
|
|
|
|
, fTimeFormat(timeFormat) {
|
|
|
|
fLogger.logProgress("skia bench:");
|
|
|
|
}
|
2014-07-17 20:14:16 +00:00
|
|
|
virtual void key(const char name[], const char value[]) {
|
|
|
|
// Don't log keys to keep microbench output unchanged.
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
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));
|
|
|
|
}
|
2014-07-17 20:14:16 +00:00
|
|
|
virtual void configOption(const char name[], const char* value) {
|
|
|
|
// Don't log configOptions to keep microbench output unchanged.
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
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:
|
2014-06-19 19:32:29 +00:00
|
|
|
BenchLogger& fLogger;
|
2013-12-03 18:16:48 +00:00
|
|
|
const char* fTimeFormat;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This ResultsWriter handles writing out the results in JSON.
|
|
|
|
*
|
2014-05-20 17:35:10 +00:00
|
|
|
* The output looks like (except compressed to a single line):
|
2013-12-03 18:16:48 +00:00
|
|
|
*
|
|
|
|
* {
|
|
|
|
* "options" : {
|
|
|
|
* "alpha" : "0xFF",
|
|
|
|
* "scale" : "0",
|
|
|
|
* ...
|
|
|
|
* "system" : "UNIX"
|
|
|
|
* },
|
2014-05-20 17:35:10 +00:00
|
|
|
* "results" : [
|
|
|
|
* {
|
|
|
|
* "name" : "Xfermode_Luminosity_640_480",
|
|
|
|
* "results" : [
|
|
|
|
* {
|
|
|
|
* "name": "565",
|
2013-12-03 18:16:48 +00:00
|
|
|
* "cmsecs" : 143.188128906250,
|
|
|
|
* "msecs" : 143.835957031250
|
|
|
|
* },
|
|
|
|
* ...
|
|
|
|
*/
|
2014-05-27 21:51:38 +00:00
|
|
|
|
2014-05-29 17:10:24 +00:00
|
|
|
Json::Value* SkFindNamedNode(Json::Value* root, const char name[]);
|
2014-06-26 18:26:40 +00:00
|
|
|
Json::Value SkMakeBuilderJSON(const SkString &buildername);
|
|
|
|
|
2014-05-29 17:10:24 +00:00
|
|
|
class JSONResultsWriter : public ResultsWriter {
|
2013-12-03 18:16:48 +00:00
|
|
|
public:
|
|
|
|
explicit JSONResultsWriter(const char filename[])
|
|
|
|
: fFilename(filename)
|
|
|
|
, fRoot()
|
|
|
|
, fResults(fRoot["results"])
|
|
|
|
, fBench(NULL)
|
|
|
|
, fConfig(NULL) {
|
|
|
|
}
|
2014-07-17 20:14:16 +00:00
|
|
|
virtual void key(const char name[], const char value[]) {
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
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) {
|
2014-05-20 17:35:10 +00:00
|
|
|
SkString sk_name(name);
|
|
|
|
sk_name.append("_");
|
|
|
|
sk_name.appendS32(x);
|
|
|
|
sk_name.append("_");
|
|
|
|
sk_name.appendS32(y);
|
2014-05-29 17:10:24 +00:00
|
|
|
Json::Value* bench_node = SkFindNamedNode(&fResults, sk_name.c_str());
|
2014-05-19 17:29:01 +00:00
|
|
|
fBench = &(*bench_node)["results"];
|
2013-12-03 18:16:48 +00:00
|
|
|
}
|
|
|
|
virtual void config(const char name[]) {
|
|
|
|
SkASSERT(NULL != fBench);
|
2014-05-29 17:10:24 +00:00
|
|
|
fConfig = SkFindNamedNode(fBench, name);
|
2013-12-03 18:16:48 +00:00
|
|
|
}
|
2014-07-17 20:14:16 +00:00
|
|
|
virtual void configOption(const char name[], const char* value) {
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
NanoJSONResultsWriter writes the test results out in the following
|
|
|
|
format:
|
|
|
|
|
|
|
|
{
|
|
|
|
"key": {
|
|
|
|
"arch": "Arm7",
|
|
|
|
"gpu": "SGX540",
|
|
|
|
"os": "Android",
|
|
|
|
"model": "GalaxyNexus",
|
|
|
|
}
|
|
|
|
"options": {
|
|
|
|
"GL_Version": "3.1",
|
|
|
|
...
|
|
|
|
},
|
|
|
|
"gitHash": "d1830323662ae8ae06908b97f15180fd25808894",
|
|
|
|
"results" : {
|
|
|
|
"Xfermode_Luminosity_640_480" : {
|
|
|
|
"8888" : {
|
|
|
|
"median_ms" : 143.188128906250,
|
|
|
|
"min_ms" : 143.835957031250,
|
|
|
|
...
|
|
|
|
},
|
|
|
|
...
|
|
|
|
*/
|
|
|
|
class NanoJSONResultsWriter : public ResultsWriter {
|
|
|
|
public:
|
|
|
|
explicit NanoJSONResultsWriter(const char filename[], const char gitHash[])
|
|
|
|
: fFilename(filename)
|
|
|
|
, fRoot()
|
|
|
|
, fResults(fRoot["results"])
|
|
|
|
, fBench(NULL)
|
|
|
|
, fConfig(NULL) {
|
|
|
|
fRoot["gitHash"] = gitHash;
|
|
|
|
}
|
|
|
|
virtual void key(const char name[], const char value[]) {
|
|
|
|
fRoot["key"][name] = value;
|
|
|
|
}
|
|
|
|
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 id = SkStringPrintf( "%s_%d_%d", name, x, y);
|
|
|
|
fResults[id.c_str()] = Json::Value(Json::objectValue);
|
|
|
|
fBench = &fResults[id.c_str()];
|
|
|
|
}
|
|
|
|
virtual void config(const char name[]) {
|
|
|
|
SkASSERT(NULL != fBench);
|
|
|
|
fConfig = &(*fBench)[name];
|
|
|
|
}
|
|
|
|
virtual void configOption(const char name[], const char* value) {
|
|
|
|
(*fConfig)["options"][name] = value;
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
virtual void timer(const char name[], double ms) {
|
2014-07-17 20:14:16 +00:00
|
|
|
// Don't record if nan, or -nan.
|
|
|
|
if (sk_double_isnan(ms)) {
|
|
|
|
return;
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
SkASSERT(NULL != fConfig);
|
|
|
|
(*fConfig)[name] = ms;
|
|
|
|
}
|
|
|
|
virtual void end() {
|
|
|
|
SkFILEWStream stream(fFilename.c_str());
|
2014-05-20 17:35:10 +00:00
|
|
|
stream.writeText(Json::FastWriter().write(fRoot).c_str());
|
2013-12-03 18:16:48 +00:00
|
|
|
stream.flush();
|
|
|
|
}
|
|
|
|
private:
|
2014-05-20 17:35:10 +00:00
|
|
|
|
2013-12-03 18:16:48 +00:00
|
|
|
SkString fFilename;
|
|
|
|
Json::Value fRoot;
|
|
|
|
Json::Value& fResults;
|
|
|
|
Json::Value* fBench;
|
|
|
|
Json::Value* fConfig;
|
|
|
|
};
|
|
|
|
|
2014-07-17 20:14:16 +00:00
|
|
|
|
2013-12-03 18:16:48 +00:00
|
|
|
/**
|
|
|
|
* This ResultsWriter writes out to multiple ResultsWriters.
|
|
|
|
*/
|
|
|
|
class MultiResultsWriter : public ResultsWriter {
|
|
|
|
public:
|
|
|
|
MultiResultsWriter() : writers() {
|
|
|
|
};
|
|
|
|
void add(ResultsWriter* writer) {
|
|
|
|
writers.push_back(writer);
|
|
|
|
}
|
2014-07-17 20:14:16 +00:00
|
|
|
virtual void key(const char name[], const char value[]) {
|
|
|
|
for (int i = 0; i < writers.count(); ++i) {
|
|
|
|
writers[i]->key(name, value);
|
|
|
|
}
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2014-07-17 20:14:16 +00:00
|
|
|
virtual void configOption(const char name[], const char* value) {
|
|
|
|
for (int i = 0; i < writers.count(); ++i) {
|
|
|
|
writers[i]->configOption(name, value);
|
|
|
|
}
|
|
|
|
}
|
2013-12-03 18:16:48 +00:00
|
|
|
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
|