/*
* 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.
*/
#ifndef SkPictureResultsWriter_DEFINED
#define SkPictureResultsWriter_DEFINED
#include "BenchLogger.h"
#include "ResultsWriter.h"
#include "SkJSONCPP.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTArray.h"
#include "TimerData.h"
/**
* 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;
virtual void tileConfig(SkString configName) = 0;
virtual void tileMeta(int x, int y, int tx, int ty) = 0;
virtual void addTileFlag(PictureResultsWriter::TileFlags flag) = 0;
virtual void tileData(
TimerData* data,
const char format[],
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:
PictureResultsMultiWriter()
: fWriters() {}
void add(PictureResultsWriter* newWriter) {
fWriters.push_back(newWriter);
}
virtual ~PictureResultsMultiWriter() {}
virtual void bench(const char name[], int32_t x, int32_t y) {
for(int i=0; i<fWriters.count(); ++i) {
fWriters[i]->bench(name, x, y);
}
}
virtual void tileConfig(SkString configName) {
for(int i=0; i<fWriters.count(); ++i) {
fWriters[i]->tileConfig(configName);
}
}
virtual void tileMeta(int x, int y, int tx, int ty) {
for(int i=0; i<fWriters.count(); ++i) {
fWriters[i]->tileMeta(x, y, tx, ty);
}
}
virtual void addTileFlag(PictureResultsWriter::TileFlags flag) {
for(int i=0; i<fWriters.count(); ++i) {
fWriters[i]->addTileFlag(flag);
}
}
virtual void tileData(
TimerData* data,
const char format[],
const TimerData::Result result,
uint32_t timerTypes,
int numInnerLoops = 1) {
for(int i=0; i<fWriters.count(); ++i) {
fWriters[i]->tileData(data, format, result, timerTypes,
numInnerLoops);
}
}
virtual void end() {
for(int i=0; i<fWriters.count(); ++i) {
fWriters[i]->end();
}
}
private:
SkTArray<PictureResultsWriter*> fWriters;
};
/**
* Writes to BenchLogger to mimic original behavior
*/
class PictureResultsLoggerWriter : public PictureResultsWriter {
private:
void logProgress(const char str[]) {
if(fLogger != NULL) {
fLogger->logProgress(str);
}
}
public:
PictureResultsLoggerWriter(BenchLogger* log)
: fLogger(log), currentLine() {}
virtual void bench(const char name[], int32_t x, int32_t y) {
SkString result;
result.printf("running bench [%i %i] %s ", x, y, name);
this->logProgress(result.c_str());
}
virtual void tileConfig(SkString configName) {
currentLine = configName;
}
virtual void tileMeta(int x, int y, int tx, int ty) {
currentLine.appendf(": tile [%i,%i] out of [%i,%i]", x, y, tx, ty);
}
virtual void addTileFlag(PictureResultsWriter::TileFlags flag) {
if(flag == PictureResultsWriter::kPurging) {
currentLine.append(" <withPurging>");
} else if(flag == PictureResultsWriter::kAvg) {
currentLine.append(" <averaged>");
}
}
virtual void tileData(
TimerData* data,
const char format[],
const TimerData::Result result,
uint32_t timerTypes,
int numInnerLoops = 1) {
SkString results = data->getResult(format, result,
currentLine.c_str(), timerTypes, numInnerLoops);
results.append("\n");
this->logProgress(results.c_str());
}
virtual void end() {}
private:
BenchLogger* fLogger;
SkString currentLine;
};
/**
* 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:
PictureJSONResultsWriter(const char filename[])
: fFilename(filename),
fRoot(),
fCurrentBench(NULL),
fCurrentTileSet(NULL),
fCurrentTile(NULL) {}
virtual void bench(const char name[], int32_t x, int32_t y) {
SkString sk_name(name);
sk_name.append("_");
sk_name.appendS32(x);
sk_name.append("_");
sk_name.appendS32(y);
Json::Value* bench_node = SkFindNamedNode(&fRoot["benches"], sk_name.c_str());
fCurrentBench = &(*bench_node)["tileSets"];
}
virtual void tileConfig(SkString configName) {
SkASSERT(fCurrentBench != NULL);
fCurrentTileSet = SkFindNamedNode(fCurrentBench, configName.c_str());
fCurrentTile = &(*fCurrentTileSet)["tiles"][0];
}
virtual void tileMeta(int x, int y, int tx, int ty) {
SkASSERT(fCurrentTileSet != NULL);
(*fCurrentTileSet)["tx"] = tx;
(*fCurrentTileSet)["ty"] = ty;
fCurrentTile = &(*fCurrentTileSet)["tiles"][x+tx*y];
}
virtual void addTileFlag(PictureResultsWriter::TileFlags flag) {
SkASSERT(fCurrentTile != NULL);
if(flag == PictureResultsWriter::kPurging) {
(*fCurrentTile)["flags"]["purging"] = true;
} else if(flag == PictureResultsWriter::kAvg) {
(*fCurrentTile)["flags"]["averaged"] = true;
}
}
virtual void tileData(
TimerData* data,
const char format[],
const TimerData::Result result,
uint32_t timerTypes,
int numInnerLoops = 1) {
SkASSERT(fCurrentTile != NULL);
(*fCurrentTile)["data"] = data->getJSON(timerTypes, result, numInnerLoops);
}
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 *fCurrentBench;
Json::Value *fCurrentTileSet;
Json::Value *fCurrentTile;
};
#endif