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"
|
2015-08-20 16:12:39 +00:00
|
|
|
#include "SkOSFile.h"
|
2016-11-07 23:05:29 +00:00
|
|
|
#include "SkOSPath.h"
|
2013-12-03 18:16:48 +00:00
|
|
|
#include "SkStream.h"
|
|
|
|
#include "SkString.h"
|
|
|
|
#include "SkTypes.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for writing out the bench results.
|
|
|
|
*
|
2014-08-20 18:45:00 +00:00
|
|
|
* Default implementation does nothing.
|
2013-12-03 18:16:48 +00:00
|
|
|
*/
|
|
|
|
class ResultsWriter : SkNoncopyable {
|
|
|
|
public:
|
2014-08-20 18:45:00 +00:00
|
|
|
virtual ~ResultsWriter() {}
|
2013-12-03 18:16:48 +00:00
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
// Record one key value pair that makes up a unique key for this type of run, e.g.
|
|
|
|
// builder name, machine type, Debug/Release, etc.
|
|
|
|
virtual void key(const char name[], const char value[]) {}
|
2014-07-17 20:14:16 +00:00
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
// Record one key value pair that describes the run instance, e.g. git hash, build number.
|
|
|
|
virtual void property(const char name[], const char value[]) {}
|
2013-12-03 18:16:48 +00:00
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
// Denote the start of a specific benchmark. Once bench is called,
|
Upload picture byte size and op count metrics for SKP recording.
Look okay?
{
"results" : {
"desk_amazon.skp_1264_3999" : {
"nonrendering" : {
"bytes" : 75656,
"max_ms" : 1.150187,
"mean_ms" : 1.150187,
"median_ms" : 1.150187,
"min_ms" : 1.150187,
"ops" : 659,
"options" : {
"bench_type" : "recording",
"clip" : "0 0 1000 1000",
"name" : "desk_amazon.skp",
"scale" : "1",
"source_type" : "skp"
}
}
},
...
BUG=skia:
Review URL: https://codereview.chromium.org/773323002
2014-12-04 16:46:51 +00:00
|
|
|
// then config and metric can be called multiple times to record runs.
|
2014-08-20 18:45:00 +00:00
|
|
|
virtual void bench(const char name[], int32_t x, int32_t y) {}
|
2013-12-03 18:16:48 +00:00
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
// Record the specific configuration a bench is run under, such as "8888".
|
|
|
|
virtual void config(const char name[]) {}
|
2013-12-03 18:16:48 +00:00
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
// Record the options for a configuration, such as "GL_RENDERER".
|
|
|
|
virtual void configOption(const char name[], const char* value) {}
|
2014-07-17 20:14:16 +00:00
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
// Record a single test metric.
|
Upload picture byte size and op count metrics for SKP recording.
Look okay?
{
"results" : {
"desk_amazon.skp_1264_3999" : {
"nonrendering" : {
"bytes" : 75656,
"max_ms" : 1.150187,
"mean_ms" : 1.150187,
"median_ms" : 1.150187,
"min_ms" : 1.150187,
"ops" : 659,
"options" : {
"bench_type" : "recording",
"clip" : "0 0 1000 1000",
"name" : "desk_amazon.skp",
"scale" : "1",
"source_type" : "skp"
}
}
},
...
BUG=skia:
Review URL: https://codereview.chromium.org/773323002
2014-12-04 16:46:51 +00:00
|
|
|
virtual void metric(const char name[], double ms) {}
|
2014-10-14 15:40:43 +00:00
|
|
|
|
2016-12-06 18:53:52 +00:00
|
|
|
// Record a list of test metrics.
|
|
|
|
virtual void metrics(const char name[], const SkTArray<double>& array) {}
|
|
|
|
|
2014-10-14 15:40:43 +00:00
|
|
|
// Flush to storage now please.
|
|
|
|
virtual void flush() {}
|
2014-07-17 20:14:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
NanoJSONResultsWriter writes the test results out in the following
|
|
|
|
format:
|
|
|
|
|
|
|
|
{
|
|
|
|
"key": {
|
|
|
|
"arch": "Arm7",
|
|
|
|
"gpu": "SGX540",
|
|
|
|
"os": "Android",
|
|
|
|
"model": "GalaxyNexus",
|
|
|
|
}
|
|
|
|
"gitHash": "d1830323662ae8ae06908b97f15180fd25808894",
|
2014-08-20 18:45:00 +00:00
|
|
|
"build_number": "1234",
|
2014-07-17 20:14:16 +00:00
|
|
|
"results" : {
|
|
|
|
"Xfermode_Luminosity_640_480" : {
|
|
|
|
"8888" : {
|
|
|
|
"median_ms" : 143.188128906250,
|
|
|
|
"min_ms" : 143.835957031250,
|
|
|
|
...
|
|
|
|
},
|
|
|
|
...
|
|
|
|
*/
|
|
|
|
class NanoJSONResultsWriter : public ResultsWriter {
|
|
|
|
public:
|
2014-08-20 18:45:00 +00:00
|
|
|
explicit NanoJSONResultsWriter(const char filename[])
|
2014-07-17 20:14:16 +00:00
|
|
|
: fFilename(filename)
|
|
|
|
, fRoot()
|
|
|
|
, fResults(fRoot["results"])
|
2015-08-27 14:41:13 +00:00
|
|
|
, fBench(nullptr)
|
|
|
|
, fConfig(nullptr) {}
|
2014-08-20 18:45:00 +00:00
|
|
|
|
|
|
|
~NanoJSONResultsWriter() {
|
2014-10-14 15:40:43 +00:00
|
|
|
this->flush();
|
2014-07-17 20:14:16 +00:00
|
|
|
}
|
2014-08-20 18:45:00 +00:00
|
|
|
|
|
|
|
// Added under "key".
|
2015-12-02 17:05:37 +00:00
|
|
|
void key(const char name[], const char value[]) override {
|
2014-07-17 20:14:16 +00:00
|
|
|
fRoot["key"][name] = value;
|
|
|
|
}
|
2014-08-20 18:45:00 +00:00
|
|
|
// Inserted directly into the root.
|
2015-12-02 17:05:37 +00:00
|
|
|
void property(const char name[], const char value[]) override {
|
2014-08-20 18:45:00 +00:00
|
|
|
fRoot[name] = value;
|
2014-07-17 20:14:16 +00:00
|
|
|
}
|
2015-12-02 17:05:37 +00:00
|
|
|
void bench(const char name[], int32_t x, int32_t y) override {
|
2014-07-17 20:14:16 +00:00
|
|
|
SkString id = SkStringPrintf( "%s_%d_%d", name, x, y);
|
|
|
|
fResults[id.c_str()] = Json::Value(Json::objectValue);
|
|
|
|
fBench = &fResults[id.c_str()];
|
|
|
|
}
|
2015-12-02 17:05:37 +00:00
|
|
|
void config(const char name[]) override {
|
2014-09-05 20:34:00 +00:00
|
|
|
SkASSERT(fBench);
|
2014-07-17 20:14:16 +00:00
|
|
|
fConfig = &(*fBench)[name];
|
|
|
|
}
|
2015-12-02 17:05:37 +00:00
|
|
|
void configOption(const char name[], const char* value) override {
|
2014-07-17 20:14:16 +00:00
|
|
|
(*fConfig)["options"][name] = value;
|
|
|
|
}
|
2015-12-02 17:05:37 +00:00
|
|
|
void metric(const char name[], double ms) override {
|
2014-07-17 20:14:16 +00:00
|
|
|
// Don't record if nan, or -nan.
|
|
|
|
if (sk_double_isnan(ms)) {
|
|
|
|
return;
|
|
|
|
}
|
2014-09-05 20:34:00 +00:00
|
|
|
SkASSERT(fConfig);
|
2013-12-03 18:16:48 +00:00
|
|
|
(*fConfig)[name] = ms;
|
|
|
|
}
|
2016-12-06 18:53:52 +00:00
|
|
|
void metrics(const char name[], const SkTArray<double>& array) override {
|
|
|
|
SkASSERT(fConfig);
|
|
|
|
Json::Value value = Json::Value(Json::arrayValue);
|
|
|
|
value.resize(array.count());
|
|
|
|
for (int i = 0; i < array.count(); i++) {
|
|
|
|
// Don't care about nan-ness.
|
|
|
|
value[i] = array[i];
|
|
|
|
}
|
|
|
|
(*fConfig)[name] = std::move(value);
|
|
|
|
}
|
2014-05-20 17:35:10 +00:00
|
|
|
|
2014-10-14 15:40:43 +00:00
|
|
|
// Flush to storage now please.
|
2015-12-02 17:05:37 +00:00
|
|
|
void flush() override {
|
2015-08-20 16:12:39 +00:00
|
|
|
SkString dirname = SkOSPath::Dirname(fFilename.c_str());
|
|
|
|
if (!sk_exists(dirname.c_str(), kWrite_SkFILE_Flag)) {
|
|
|
|
if (!sk_mkdir(dirname.c_str())) {
|
|
|
|
SkDebugf("Failed to create directory.");
|
|
|
|
}
|
|
|
|
}
|
2014-10-14 15:40:43 +00:00
|
|
|
SkFILEWStream stream(fFilename.c_str());
|
|
|
|
stream.writeText(Json::StyledWriter().write(fRoot).c_str());
|
|
|
|
stream.flush();
|
|
|
|
}
|
|
|
|
|
2014-08-20 18:45:00 +00:00
|
|
|
private:
|
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
|
|
|
#endif
|