blob: 8e606dceebc5085eb6c40251f600bc365178087d [file] [log] [blame]
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 *
7 * Classes for writing out bench results in various formats.
8 */
tfarinaf168b862014-06-19 12:32:29 -07009
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000010#ifndef SkPictureResultsWriter_DEFINED
11#define SkPictureResultsWriter_DEFINED
12
kelvinly4d1a3642014-06-26 11:26:40 -070013
14#include "PictureRenderer.h"
tfarinaf168b862014-06-19 12:32:29 -070015#include "BenchLogger.h"
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000016#include "ResultsWriter.h"
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000017#include "SkJSONCPP.h"
18#include "SkStream.h"
19#include "SkString.h"
20#include "SkTArray.h"
tfarinaf168b862014-06-19 12:32:29 -070021#include "TimerData.h"
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000022
bungeman60e0fee2015-08-26 05:15:46 -070023#include <stdlib.h>
24
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000025/**
26 * Base class for writing picture bench results.
27 */
28class PictureResultsWriter : SkNoncopyable {
29public:
30 enum TileFlags {kPurging, kAvg};
31
32 PictureResultsWriter() {}
33 virtual ~PictureResultsWriter() {}
34
35 virtual void bench(const char name[], int32_t x, int32_t y) = 0;
kelvinly4d1a3642014-06-26 11:26:40 -070036 virtual void logRenderer(sk_tools::PictureRenderer *pr) = 0;
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000037 virtual void tileMeta(int x, int y, int tx, int ty) = 0;
38 virtual void addTileFlag(PictureResultsWriter::TileFlags flag) = 0;
39 virtual void tileData(
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +000040 TimerData* data,
41 const char format[],
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000042 const TimerData::Result result,
43 uint32_t timerTypes,
44 int numInnerLoops = 1) = 0;
45 virtual void end() = 0;
46};
47
48/**
49 * This class allows bench data to be piped into multiple
50 * PictureResultWriter classes. It does not own any classes
51 * passed to it, so the owner is required to manage any classes
52 * passed to PictureResultsMultiWriter */
53class PictureResultsMultiWriter : public PictureResultsWriter {
54public:
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +000055 PictureResultsMultiWriter()
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000056 : fWriters() {}
57 void add(PictureResultsWriter* newWriter) {
58 fWriters.push_back(newWriter);
59 }
60 virtual ~PictureResultsMultiWriter() {}
mtklein36352bf2015-03-25 18:17:31 -070061 void bench(const char name[], int32_t x, int32_t y) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000062 for(int i=0; i<fWriters.count(); ++i) {
63 fWriters[i]->bench(name, x, y);
64 }
65 }
mtklein36352bf2015-03-25 18:17:31 -070066 void logRenderer(sk_tools::PictureRenderer *pr) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000067 for(int i=0; i<fWriters.count(); ++i) {
kelvinly4d1a3642014-06-26 11:26:40 -070068 fWriters[i]->logRenderer(pr);
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000069 }
70 }
mtklein36352bf2015-03-25 18:17:31 -070071 void tileMeta(int x, int y, int tx, int ty) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000072 for(int i=0; i<fWriters.count(); ++i) {
73 fWriters[i]->tileMeta(x, y, tx, ty);
74 }
75 }
mtklein36352bf2015-03-25 18:17:31 -070076 void addTileFlag(PictureResultsWriter::TileFlags flag) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000077 for(int i=0; i<fWriters.count(); ++i) {
78 fWriters[i]->addTileFlag(flag);
79 }
80 }
81 virtual void tileData(
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +000082 TimerData* data,
83 const char format[],
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000084 const TimerData::Result result,
85 uint32_t timerTypes,
mtklein36352bf2015-03-25 18:17:31 -070086 int numInnerLoops = 1) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000087 for(int i=0; i<fWriters.count(); ++i) {
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +000088 fWriters[i]->tileData(data, format, result, timerTypes,
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000089 numInnerLoops);
90 }
91 }
mtklein36352bf2015-03-25 18:17:31 -070092 void end() override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +000093 for(int i=0; i<fWriters.count(); ++i) {
94 fWriters[i]->end();
95 }
96 }
97private:
98 SkTArray<PictureResultsWriter*> fWriters;
99};
100
101/**
tfarinaf168b862014-06-19 12:32:29 -0700102 * Writes to BenchLogger to mimic original behavior
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000103 */
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +0000104class PictureResultsLoggerWriter : public PictureResultsWriter {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000105private:
106 void logProgress(const char str[]) {
halcanary96fcdcc2015-08-27 07:41:13 -0700107 if(fLogger != nullptr) {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000108 fLogger->logProgress(str);
109 }
110 }
111public:
tfarinaf168b862014-06-19 12:32:29 -0700112 PictureResultsLoggerWriter(BenchLogger* log)
kelvinly4d1a3642014-06-26 11:26:40 -0700113 : fLogger(log), fCurrentLine() {}
mtklein36352bf2015-03-25 18:17:31 -0700114 void bench(const char name[], int32_t x, int32_t y) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000115 SkString result;
116 result.printf("running bench [%i %i] %s ", x, y, name);
117 this->logProgress(result.c_str());
118 }
mtklein36352bf2015-03-25 18:17:31 -0700119 void logRenderer(sk_tools::PictureRenderer* renderer) override {
kelvinly4d1a3642014-06-26 11:26:40 -0700120 fCurrentLine = renderer->getConfigName();
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000121 }
mtklein36352bf2015-03-25 18:17:31 -0700122 void tileMeta(int x, int y, int tx, int ty) override {
kelvinly4d1a3642014-06-26 11:26:40 -0700123 fCurrentLine.appendf(": tile [%i,%i] out of [%i,%i]", x, y, tx, ty);
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000124 }
mtklein36352bf2015-03-25 18:17:31 -0700125 void addTileFlag(PictureResultsWriter::TileFlags flag) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000126 if(flag == PictureResultsWriter::kPurging) {
kelvinly4d1a3642014-06-26 11:26:40 -0700127 fCurrentLine.append(" <withPurging>");
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000128 } else if(flag == PictureResultsWriter::kAvg) {
kelvinly4d1a3642014-06-26 11:26:40 -0700129 fCurrentLine.append(" <averaged>");
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000130 }
131 }
132 virtual void tileData(
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +0000133 TimerData* data,
134 const char format[],
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000135 const TimerData::Result result,
136 uint32_t timerTypes,
mtklein36352bf2015-03-25 18:17:31 -0700137 int numInnerLoops = 1) override {
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000138 SkString results = data->getResult(format, result,
kelvinly4d1a3642014-06-26 11:26:40 -0700139 fCurrentLine.c_str(), timerTypes, numInnerLoops);
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000140 results.append("\n");
141 this->logProgress(results.c_str());
142 }
mtklein36352bf2015-03-25 18:17:31 -0700143 void end() override {}
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000144private:
tfarinaf168b862014-06-19 12:32:29 -0700145 BenchLogger* fLogger;
kelvinly4d1a3642014-06-26 11:26:40 -0700146 SkString fCurrentLine;
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000147};
148
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000149/**
150 * This PictureResultsWriter collects data in a JSON node
151 *
152 * The format is something like
153 * {
154 * benches: [
155 * {
156 * name: "Name_of_test"
157 * tilesets: [
158 * {
159 * name: "Name of the configuration"
160 * tiles: [
161 * {
162 * flags: {
163 * purging: true //Flags for the current tile
164 * // are put here
165 * }
166 * data: {
167 * wsecs: [....] //Actual data ends up here
168 * }
169 * }
170 * ]
171 * }
172 * ]
173 * }
174 * ]
175 * }*/
176
177class PictureJSONResultsWriter : public PictureResultsWriter {
178public:
mtklein1915b622014-08-20 11:45:00 -0700179 PictureJSONResultsWriter(const char filename[],
kelvinly4d1a3642014-06-26 11:26:40 -0700180 const char builderName[],
181 int buildNumber,
182 int timestamp,
183 const char gitHash[],
184 int gitNumber)
185 : fStream(filename) {
186 fBuilderName = SkString(builderName);
187 fBuildNumber = buildNumber;
188 fTimestamp = timestamp;
189 fGitHash = SkString(gitHash);
190 fGitNumber = gitNumber;
mtklein1915b622014-08-20 11:45:00 -0700191 fBuilderData = this->makeBuilderJson();
kelvinly4d1a3642014-06-26 11:26:40 -0700192 }
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000193
mtklein36352bf2015-03-25 18:17:31 -0700194 void bench(const char name[], int32_t x, int32_t y) override {
kelvinly4d1a3642014-06-26 11:26:40 -0700195 fBenchName = SkString(name);
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000196 }
mtklein36352bf2015-03-25 18:17:31 -0700197 void logRenderer(sk_tools::PictureRenderer* pr) override {
kelvinly4d1a3642014-06-26 11:26:40 -0700198 fParams = pr->getJSONConfig();
199 fConfigString = pr->getConfigName();
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000200 }
kelvinly4d1a3642014-06-26 11:26:40 -0700201 // Apparently tiles aren't used, so tileMeta is empty
mtklein36352bf2015-03-25 18:17:31 -0700202 void tileMeta(int x, int y, int tx, int ty) override {}
kelvinly4d1a3642014-06-26 11:26:40 -0700203 // Flags aren't used, so addTileFlag is empty
mtklein36352bf2015-03-25 18:17:31 -0700204 void addTileFlag(PictureResultsWriter::TileFlags flag) override {}
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000205 virtual void tileData(
skia.committer@gmail.com9681eeb2014-05-30 03:06:10 +0000206 TimerData* data,
207 const char format[],
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000208 const TimerData::Result result,
209 uint32_t timerTypes,
mtklein36352bf2015-03-25 18:17:31 -0700210 int numInnerLoops = 1) override {
kelvinly4d1a3642014-06-26 11:26:40 -0700211 Json::Value newData = data->getJSON(timerTypes, result, numInnerLoops);
212 Json::Value combinedParams(fBuilderData);
213 for(Json::ValueIterator iter = fParams.begin(); iter != fParams.end();
214 iter++) {
215 combinedParams[iter.key().asString()]= *iter;
216 }
217 // For each set of timer data
218 for(Json::ValueIterator iter = newData.begin(); iter != newData.end();
219 iter++) {
220 Json::Value data;
221 data["buildNumber"] = fBuildNumber;
222 data["timestamp"] = fTimestamp;
223 data["gitHash"] = fGitHash.c_str();
224 data["gitNumber"] = fGitNumber;
225 data["isTrybot"] = fBuilderName.endsWith("Trybot");
226
227 data["params"] = combinedParams;
228 data["params"]["benchName"] = fBenchName.c_str();
229
230 // Not including skpSize because that's deprecated?
231 data["key"] = this->makeKey(iter.key().asString().c_str()).c_str();
232 // Get the data
233 SkTArray<double> times;
234 Json::Value val = *iter;
235 for(Json::ValueIterator vals = val.begin(); vals != val.end();
236 vals++) {
237 times.push_back((*vals).asDouble());
238 }
mtklein1915b622014-08-20 11:45:00 -0700239 qsort(static_cast<void*>(times.begin()), times.count(),
kelvinly4d1a3642014-06-26 11:26:40 -0700240 sizeof(double), PictureJSONResultsWriter::CompareDoubles);
241 data["value"] = times[static_cast<int>(times.count() * 0.25f)];
242 data["params"]["measurementType"] = iter.key().asString();
243 fStream.writeText(Json::FastWriter().write(data).c_str());
244 }
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000245 }
mtklein36352bf2015-03-25 18:17:31 -0700246 void end() override {
kelvinly4d1a3642014-06-26 11:26:40 -0700247 fStream.flush();
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000248 }
249private:
mtklein1915b622014-08-20 11:45:00 -0700250 Json::Value makeBuilderJson() const {
251 static const int kNumKeys = 6;
252 static const char* kKeys[kNumKeys] = {
253 "role", "os", "model", "gpu", "arch", "configuration"};
254 Json::Value builderData;
255
256 if (!fBuilderName.isEmpty()) {
257 SkTArray<SkString> splitBuilder;
258 SkStrSplit(fBuilderName.c_str(), "-", &splitBuilder);
259 SkASSERT(splitBuilder.count() >= kNumKeys);
260 for (int i = 0; i < kNumKeys && i < splitBuilder.count(); ++i) {
261 builderData[kKeys[i]] = splitBuilder[i].c_str();
262 }
263 builderData["builderName"] = fBuilderName.c_str();
264 if (kNumKeys < splitBuilder.count()) {
265 SkString extras;
266 for (int i = kNumKeys; i < splitBuilder.count(); ++i) {
267 extras.append(splitBuilder[i]);
268 if (i != splitBuilder.count() - 1) {
269 extras.append("-");
270 }
271 }
272 builderData["badParams"] = extras.c_str();
273 }
274 }
275 return builderData;
276 }
277
kelvinly4d1a3642014-06-26 11:26:40 -0700278 static int CompareDoubles(const void* p1, const void* p2) {
279 if(*static_cast<const double*>(p1) < *static_cast<const double*>(p2)) {
280 return -1;
mtklein1915b622014-08-20 11:45:00 -0700281 } else if(*static_cast<const double*>(p1) ==
kelvinly4d1a3642014-06-26 11:26:40 -0700282 *static_cast<const double*>(p2)) {
mtklein1915b622014-08-20 11:45:00 -0700283 return 0;
kelvinly4d1a3642014-06-26 11:26:40 -0700284 } else {
285 return 1;
286 }
287 }
288 SkString makeKey(const char measurementType[]) const {
289 SkString tmp(fBuilderName);
290 tmp.append("_");
291 tmp.append(fBenchName);
292 tmp.append("_");
293 tmp.append(fConfigString);
294 tmp.append("_");
295 tmp.append(measurementType);
296 return tmp;
297 }
298
299 SkFILEWStream fStream;
300 Json::Value fBuilderData;
301 SkString fBenchName;
302 Json::Value fParams;
303
304 SkString fConfigString;
305 SkString fBuilderName;
306 int fBuildNumber;
307 int fTimestamp;
308 SkString fGitHash;
309 int fGitNumber;
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000310};
commit-bot@chromium.org37c772a2014-05-29 17:10:24 +0000311
312#endif