2014-05-29 17:10:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2014 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
|
|
|
|
2014-05-29 17:10:24 +00:00
|
|
|
#ifndef SkPictureResultsWriter_DEFINED
|
|
|
|
#define SkPictureResultsWriter_DEFINED
|
|
|
|
|
2014-06-26 18:26:40 +00:00
|
|
|
|
|
|
|
#include "PictureRenderer.h"
|
2014-06-19 19:32:29 +00:00
|
|
|
#include "BenchLogger.h"
|
2014-05-29 17:10:24 +00:00
|
|
|
#include "ResultsWriter.h"
|
|
|
|
#include "SkJSONCPP.h"
|
|
|
|
#include "SkStream.h"
|
|
|
|
#include "SkString.h"
|
|
|
|
#include "SkTArray.h"
|
2014-06-19 19:32:29 +00:00
|
|
|
#include "TimerData.h"
|
2014-05-29 17:10:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for writing picture bench results.
|
|
|
|
*/
|
|
|
|
class PictureResultsWriter : SkNoncopyable {
|
|
|
|
public:
|
|
|
|
enum TileFlags {kPurging, kAvg};
|
|
|
|
|
|
|
|
PictureResultsWriter() {}
|
|
|
|
virtual ~PictureResultsWriter() {}
|
|
|
|
|
|
|
|
virtual void bench(const char name[], int32_t x, int32_t y) = 0;
|
2014-06-26 18:26:40 +00:00
|
|
|
virtual void logRenderer(sk_tools::PictureRenderer *pr) = 0;
|
2014-05-29 17:10:24 +00:00
|
|
|
virtual void tileMeta(int x, int y, int tx, int ty) = 0;
|
|
|
|
virtual void addTileFlag(PictureResultsWriter::TileFlags flag) = 0;
|
|
|
|
virtual void tileData(
|
2014-05-30 03:06:10 +00:00
|
|
|
TimerData* data,
|
|
|
|
const char format[],
|
2014-05-29 17:10:24 +00:00
|
|
|
const TimerData::Result result,
|
|
|
|
uint32_t timerTypes,
|
|
|
|
int numInnerLoops = 1) = 0;
|
|
|
|
virtual void end() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class allows bench data to be piped into multiple
|
|
|
|
* PictureResultWriter classes. It does not own any classes
|
|
|
|
* passed to it, so the owner is required to manage any classes
|
|
|
|
* passed to PictureResultsMultiWriter */
|
|
|
|
class PictureResultsMultiWriter : public PictureResultsWriter {
|
|
|
|
public:
|
2014-05-30 03:06:10 +00:00
|
|
|
PictureResultsMultiWriter()
|
2014-05-29 17:10:24 +00:00
|
|
|
: fWriters() {}
|
|
|
|
void add(PictureResultsWriter* newWriter) {
|
|
|
|
fWriters.push_back(newWriter);
|
|
|
|
}
|
|
|
|
virtual ~PictureResultsMultiWriter() {}
|
2015-03-26 01:17:31 +00:00
|
|
|
void bench(const char name[], int32_t x, int32_t y) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
for(int i=0; i<fWriters.count(); ++i) {
|
|
|
|
fWriters[i]->bench(name, x, y);
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void logRenderer(sk_tools::PictureRenderer *pr) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
for(int i=0; i<fWriters.count(); ++i) {
|
2014-06-26 18:26:40 +00:00
|
|
|
fWriters[i]->logRenderer(pr);
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void tileMeta(int x, int y, int tx, int ty) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
for(int i=0; i<fWriters.count(); ++i) {
|
|
|
|
fWriters[i]->tileMeta(x, y, tx, ty);
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void addTileFlag(PictureResultsWriter::TileFlags flag) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
for(int i=0; i<fWriters.count(); ++i) {
|
|
|
|
fWriters[i]->addTileFlag(flag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virtual void tileData(
|
2014-05-30 03:06:10 +00:00
|
|
|
TimerData* data,
|
|
|
|
const char format[],
|
2014-05-29 17:10:24 +00:00
|
|
|
const TimerData::Result result,
|
|
|
|
uint32_t timerTypes,
|
2015-03-26 01:17:31 +00:00
|
|
|
int numInnerLoops = 1) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
for(int i=0; i<fWriters.count(); ++i) {
|
2014-05-30 03:06:10 +00:00
|
|
|
fWriters[i]->tileData(data, format, result, timerTypes,
|
2014-05-29 17:10:24 +00:00
|
|
|
numInnerLoops);
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void end() override {
|
2014-05-29 17:10:24 +00:00
|
|
|
for(int i=0; i<fWriters.count(); ++i) {
|
|
|
|
fWriters[i]->end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
SkTArray<PictureResultsWriter*> fWriters;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2014-06-19 19:32:29 +00:00
|
|
|
* Writes to BenchLogger to mimic original behavior
|
2014-05-29 17:10:24 +00:00
|
|
|
*/
|
2014-05-30 03:06:10 +00:00
|
|
|
class PictureResultsLoggerWriter : public PictureResultsWriter {
|
2014-05-29 17:10:24 +00:00
|
|
|
private:
|
|
|
|
void logProgress(const char str[]) {
|
|
|
|
if(fLogger != NULL) {
|
|
|
|
fLogger->logProgress(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public:
|
2014-06-19 19:32:29 +00:00
|
|
|
PictureResultsLoggerWriter(BenchLogger* log)
|
2014-06-26 18:26:40 +00:00
|
|
|
: fLogger(log), fCurrentLine() {}
|
2015-03-26 01:17:31 +00:00
|
|
|
void bench(const char name[], int32_t x, int32_t y) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
SkString result;
|
|
|
|
result.printf("running bench [%i %i] %s ", x, y, name);
|
|
|
|
this->logProgress(result.c_str());
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void logRenderer(sk_tools::PictureRenderer* renderer) override {
|
2014-06-26 18:26:40 +00:00
|
|
|
fCurrentLine = renderer->getConfigName();
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void tileMeta(int x, int y, int tx, int ty) override {
|
2014-06-26 18:26:40 +00:00
|
|
|
fCurrentLine.appendf(": tile [%i,%i] out of [%i,%i]", x, y, tx, ty);
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void addTileFlag(PictureResultsWriter::TileFlags flag) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
if(flag == PictureResultsWriter::kPurging) {
|
2014-06-26 18:26:40 +00:00
|
|
|
fCurrentLine.append(" <withPurging>");
|
2014-05-29 17:10:24 +00:00
|
|
|
} else if(flag == PictureResultsWriter::kAvg) {
|
2014-06-26 18:26:40 +00:00
|
|
|
fCurrentLine.append(" <averaged>");
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
virtual void tileData(
|
2014-05-30 03:06:10 +00:00
|
|
|
TimerData* data,
|
|
|
|
const char format[],
|
2014-05-29 17:10:24 +00:00
|
|
|
const TimerData::Result result,
|
|
|
|
uint32_t timerTypes,
|
2015-03-26 01:17:31 +00:00
|
|
|
int numInnerLoops = 1) override {
|
2014-05-29 17:10:24 +00:00
|
|
|
SkString results = data->getResult(format, result,
|
2014-06-26 18:26:40 +00:00
|
|
|
fCurrentLine.c_str(), timerTypes, numInnerLoops);
|
2014-05-29 17:10:24 +00:00
|
|
|
results.append("\n");
|
|
|
|
this->logProgress(results.c_str());
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void end() override {}
|
2014-05-29 17:10:24 +00:00
|
|
|
private:
|
2014-06-19 19:32:29 +00:00
|
|
|
BenchLogger* fLogger;
|
2014-06-26 18:26:40 +00:00
|
|
|
SkString fCurrentLine;
|
2014-05-29 17:10:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This PictureResultsWriter collects data in a JSON node
|
|
|
|
*
|
|
|
|
* The format is something like
|
|
|
|
* {
|
|
|
|
* benches: [
|
|
|
|
* {
|
|
|
|
* name: "Name_of_test"
|
|
|
|
* tilesets: [
|
|
|
|
* {
|
|
|
|
* name: "Name of the configuration"
|
|
|
|
* tiles: [
|
|
|
|
* {
|
|
|
|
* flags: {
|
|
|
|
* purging: true //Flags for the current tile
|
|
|
|
* // are put here
|
|
|
|
* }
|
|
|
|
* data: {
|
|
|
|
* wsecs: [....] //Actual data ends up here
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ]
|
|
|
|
* }
|
|
|
|
* ]
|
|
|
|
* }
|
|
|
|
* ]
|
|
|
|
* }*/
|
|
|
|
|
|
|
|
class PictureJSONResultsWriter : public PictureResultsWriter {
|
|
|
|
public:
|
2014-08-20 18:45:00 +00:00
|
|
|
PictureJSONResultsWriter(const char filename[],
|
2014-06-26 18:26:40 +00:00
|
|
|
const char builderName[],
|
|
|
|
int buildNumber,
|
|
|
|
int timestamp,
|
|
|
|
const char gitHash[],
|
|
|
|
int gitNumber)
|
|
|
|
: fStream(filename) {
|
|
|
|
fBuilderName = SkString(builderName);
|
|
|
|
fBuildNumber = buildNumber;
|
|
|
|
fTimestamp = timestamp;
|
|
|
|
fGitHash = SkString(gitHash);
|
|
|
|
fGitNumber = gitNumber;
|
2014-08-20 18:45:00 +00:00
|
|
|
fBuilderData = this->makeBuilderJson();
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
2014-06-26 18:26:40 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void bench(const char name[], int32_t x, int32_t y) override {
|
2014-06-26 18:26:40 +00:00
|
|
|
fBenchName = SkString(name);
|
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void logRenderer(sk_tools::PictureRenderer* pr) override {
|
2014-06-26 18:26:40 +00:00
|
|
|
fParams = pr->getJSONConfig();
|
|
|
|
fConfigString = pr->getConfigName();
|
|
|
|
}
|
|
|
|
// Apparently tiles aren't used, so tileMeta is empty
|
2015-03-26 01:17:31 +00:00
|
|
|
void tileMeta(int x, int y, int tx, int ty) override {}
|
2014-06-26 18:26:40 +00:00
|
|
|
// Flags aren't used, so addTileFlag is empty
|
2015-03-26 01:17:31 +00:00
|
|
|
void addTileFlag(PictureResultsWriter::TileFlags flag) override {}
|
2014-05-29 17:10:24 +00:00
|
|
|
virtual void tileData(
|
2014-05-30 03:06:10 +00:00
|
|
|
TimerData* data,
|
|
|
|
const char format[],
|
2014-05-29 17:10:24 +00:00
|
|
|
const TimerData::Result result,
|
|
|
|
uint32_t timerTypes,
|
2015-03-26 01:17:31 +00:00
|
|
|
int numInnerLoops = 1) override {
|
2014-06-26 18:26:40 +00:00
|
|
|
Json::Value newData = data->getJSON(timerTypes, result, numInnerLoops);
|
|
|
|
Json::Value combinedParams(fBuilderData);
|
|
|
|
for(Json::ValueIterator iter = fParams.begin(); iter != fParams.end();
|
|
|
|
iter++) {
|
|
|
|
combinedParams[iter.key().asString()]= *iter;
|
|
|
|
}
|
|
|
|
// For each set of timer data
|
|
|
|
for(Json::ValueIterator iter = newData.begin(); iter != newData.end();
|
|
|
|
iter++) {
|
|
|
|
Json::Value data;
|
|
|
|
data["buildNumber"] = fBuildNumber;
|
|
|
|
data["timestamp"] = fTimestamp;
|
|
|
|
data["gitHash"] = fGitHash.c_str();
|
|
|
|
data["gitNumber"] = fGitNumber;
|
|
|
|
data["isTrybot"] = fBuilderName.endsWith("Trybot");
|
|
|
|
|
|
|
|
data["params"] = combinedParams;
|
|
|
|
data["params"]["benchName"] = fBenchName.c_str();
|
|
|
|
|
|
|
|
// Not including skpSize because that's deprecated?
|
|
|
|
data["key"] = this->makeKey(iter.key().asString().c_str()).c_str();
|
|
|
|
// Get the data
|
|
|
|
SkTArray<double> times;
|
|
|
|
Json::Value val = *iter;
|
|
|
|
for(Json::ValueIterator vals = val.begin(); vals != val.end();
|
|
|
|
vals++) {
|
|
|
|
times.push_back((*vals).asDouble());
|
|
|
|
}
|
2014-08-20 18:45:00 +00:00
|
|
|
qsort(static_cast<void*>(times.begin()), times.count(),
|
2014-06-26 18:26:40 +00:00
|
|
|
sizeof(double), PictureJSONResultsWriter::CompareDoubles);
|
|
|
|
data["value"] = times[static_cast<int>(times.count() * 0.25f)];
|
|
|
|
data["params"]["measurementType"] = iter.key().asString();
|
|
|
|
fStream.writeText(Json::FastWriter().write(data).c_str());
|
|
|
|
}
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
2015-03-26 01:17:31 +00:00
|
|
|
void end() override {
|
2014-06-26 18:26:40 +00:00
|
|
|
fStream.flush();
|
2014-05-29 17:10:24 +00:00
|
|
|
}
|
|
|
|
private:
|
2014-08-20 18:45:00 +00:00
|
|
|
Json::Value makeBuilderJson() const {
|
|
|
|
static const int kNumKeys = 6;
|
|
|
|
static const char* kKeys[kNumKeys] = {
|
|
|
|
"role", "os", "model", "gpu", "arch", "configuration"};
|
|
|
|
Json::Value builderData;
|
|
|
|
|
|
|
|
if (!fBuilderName.isEmpty()) {
|
|
|
|
SkTArray<SkString> splitBuilder;
|
|
|
|
SkStrSplit(fBuilderName.c_str(), "-", &splitBuilder);
|
|
|
|
SkASSERT(splitBuilder.count() >= kNumKeys);
|
|
|
|
for (int i = 0; i < kNumKeys && i < splitBuilder.count(); ++i) {
|
|
|
|
builderData[kKeys[i]] = splitBuilder[i].c_str();
|
|
|
|
}
|
|
|
|
builderData["builderName"] = fBuilderName.c_str();
|
|
|
|
if (kNumKeys < splitBuilder.count()) {
|
|
|
|
SkString extras;
|
|
|
|
for (int i = kNumKeys; i < splitBuilder.count(); ++i) {
|
|
|
|
extras.append(splitBuilder[i]);
|
|
|
|
if (i != splitBuilder.count() - 1) {
|
|
|
|
extras.append("-");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
builderData["badParams"] = extras.c_str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return builderData;
|
|
|
|
}
|
|
|
|
|
2014-06-26 18:26:40 +00:00
|
|
|
static int CompareDoubles(const void* p1, const void* p2) {
|
|
|
|
if(*static_cast<const double*>(p1) < *static_cast<const double*>(p2)) {
|
|
|
|
return -1;
|
2014-08-20 18:45:00 +00:00
|
|
|
} else if(*static_cast<const double*>(p1) ==
|
2014-06-26 18:26:40 +00:00
|
|
|
*static_cast<const double*>(p2)) {
|
2014-08-20 18:45:00 +00:00
|
|
|
return 0;
|
2014-06-26 18:26:40 +00:00
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SkString makeKey(const char measurementType[]) const {
|
|
|
|
SkString tmp(fBuilderName);
|
|
|
|
tmp.append("_");
|
|
|
|
tmp.append(fBenchName);
|
|
|
|
tmp.append("_");
|
|
|
|
tmp.append(fConfigString);
|
|
|
|
tmp.append("_");
|
|
|
|
tmp.append(measurementType);
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkFILEWStream fStream;
|
|
|
|
Json::Value fBuilderData;
|
|
|
|
SkString fBenchName;
|
|
|
|
Json::Value fParams;
|
|
|
|
|
|
|
|
SkString fConfigString;
|
|
|
|
SkString fBuilderName;
|
|
|
|
int fBuildNumber;
|
|
|
|
int fTimestamp;
|
|
|
|
SkString fGitHash;
|
|
|
|
int fGitNumber;
|
2014-05-29 17:10:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|