• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
9 
10 #ifndef SkPictureResultsWriter_DEFINED
11 #define SkPictureResultsWriter_DEFINED
12 
13 
14 #include "PictureRenderer.h"
15 #include "BenchLogger.h"
16 #include "ResultsWriter.h"
17 #include "SkJSONCPP.h"
18 #include "SkStream.h"
19 #include "SkString.h"
20 #include "SkTArray.h"
21 #include "TimerData.h"
22 
23 /**
24  * Base class for writing picture bench results.
25  */
26 class PictureResultsWriter : SkNoncopyable {
27 public:
28     enum TileFlags {kPurging, kAvg};
29 
PictureResultsWriter()30     PictureResultsWriter() {}
~PictureResultsWriter()31     virtual ~PictureResultsWriter() {}
32 
33     virtual void bench(const char name[], int32_t x, int32_t y) = 0;
34     virtual void logRenderer(sk_tools::PictureRenderer *pr) = 0;
35     virtual void tileMeta(int x, int y, int tx, int ty) = 0;
36     virtual void addTileFlag(PictureResultsWriter::TileFlags flag) = 0;
37     virtual void tileData(
38             TimerData* data,
39             const char format[],
40             const TimerData::Result result,
41             uint32_t timerTypes,
42             int numInnerLoops = 1) = 0;
43    virtual void end() = 0;
44 };
45 
46 /**
47  * This class allows bench data to be piped into multiple
48  * PictureResultWriter classes. It does not own any classes
49  * passed to it, so the owner is required to manage any classes
50  * passed to PictureResultsMultiWriter */
51 class PictureResultsMultiWriter : public PictureResultsWriter {
52 public:
PictureResultsMultiWriter()53     PictureResultsMultiWriter()
54         : fWriters() {}
add(PictureResultsWriter * newWriter)55     void add(PictureResultsWriter* newWriter) {
56         fWriters.push_back(newWriter);
57     }
~PictureResultsMultiWriter()58     virtual ~PictureResultsMultiWriter() {}
bench(const char name[],int32_t x,int32_t y)59     void bench(const char name[], int32_t x, int32_t y) override {
60         for(int i=0; i<fWriters.count(); ++i) {
61             fWriters[i]->bench(name, x, y);
62         }
63     }
logRenderer(sk_tools::PictureRenderer * pr)64     void logRenderer(sk_tools::PictureRenderer *pr) override {
65         for(int i=0; i<fWriters.count(); ++i) {
66             fWriters[i]->logRenderer(pr);
67         }
68     }
tileMeta(int x,int y,int tx,int ty)69     void tileMeta(int x, int y, int tx, int ty) override {
70         for(int i=0; i<fWriters.count(); ++i) {
71             fWriters[i]->tileMeta(x, y, tx, ty);
72         }
73     }
addTileFlag(PictureResultsWriter::TileFlags flag)74     void addTileFlag(PictureResultsWriter::TileFlags flag) override {
75         for(int i=0; i<fWriters.count(); ++i) {
76             fWriters[i]->addTileFlag(flag);
77         }
78     }
79     virtual void tileData(
80             TimerData* data,
81             const char format[],
82             const TimerData::Result result,
83             uint32_t timerTypes,
84             int numInnerLoops = 1) override {
85         for(int i=0; i<fWriters.count(); ++i) {
86             fWriters[i]->tileData(data, format, result, timerTypes,
87                                  numInnerLoops);
88         }
89     }
end()90    void end() override {
91         for(int i=0; i<fWriters.count(); ++i) {
92             fWriters[i]->end();
93         }
94    }
95 private:
96     SkTArray<PictureResultsWriter*> fWriters;
97 };
98 
99 /**
100  * Writes to BenchLogger to mimic original behavior
101  */
102 class PictureResultsLoggerWriter : public PictureResultsWriter {
103 private:
logProgress(const char str[])104     void logProgress(const char str[]) {
105         if(fLogger != NULL) {
106             fLogger->logProgress(str);
107         }
108     }
109 public:
PictureResultsLoggerWriter(BenchLogger * log)110     PictureResultsLoggerWriter(BenchLogger* log)
111           : fLogger(log), fCurrentLine() {}
bench(const char name[],int32_t x,int32_t y)112     void bench(const char name[], int32_t x, int32_t y) override {
113         SkString result;
114         result.printf("running bench [%i %i] %s ", x, y, name);
115         this->logProgress(result.c_str());
116     }
logRenderer(sk_tools::PictureRenderer * renderer)117     void logRenderer(sk_tools::PictureRenderer* renderer) override {
118         fCurrentLine = renderer->getConfigName();
119     }
tileMeta(int x,int y,int tx,int ty)120     void tileMeta(int x, int y, int tx, int ty) override {
121         fCurrentLine.appendf(": tile [%i,%i] out of [%i,%i]", x, y, tx, ty);
122     }
addTileFlag(PictureResultsWriter::TileFlags flag)123     void addTileFlag(PictureResultsWriter::TileFlags flag) override {
124         if(flag == PictureResultsWriter::kPurging) {
125             fCurrentLine.append(" <withPurging>");
126         } else if(flag == PictureResultsWriter::kAvg) {
127             fCurrentLine.append(" <averaged>");
128         }
129     }
130     virtual void tileData(
131             TimerData* data,
132             const char format[],
133             const TimerData::Result result,
134             uint32_t timerTypes,
135             int numInnerLoops = 1) override {
136         SkString results = data->getResult(format, result,
137                 fCurrentLine.c_str(), timerTypes, numInnerLoops);
138         results.append("\n");
139         this->logProgress(results.c_str());
140     }
end()141     void end() override {}
142 private:
143     BenchLogger* fLogger;
144     SkString fCurrentLine;
145 };
146 
147 /**
148  * This PictureResultsWriter collects data in a JSON node
149  *
150  * The format is something like
151  * {
152  *      benches: [
153  *          {
154  *              name: "Name_of_test"
155  *              tilesets: [
156  *                  {
157  *                      name: "Name of the configuration"
158  *                      tiles: [
159  *                          {
160  *                              flags: {
161  *                                  purging: true //Flags for the current tile
162  *                                              // are put here
163  *                              }
164  *                              data: {
165  *                                  wsecs: [....] //Actual data ends up here
166  *                              }
167  *                          }
168  *                      ]
169  *                  }
170  *              ]
171  *          }
172  *      ]
173  * }*/
174 
175 class PictureJSONResultsWriter : public PictureResultsWriter {
176 public:
PictureJSONResultsWriter(const char filename[],const char builderName[],int buildNumber,int timestamp,const char gitHash[],int gitNumber)177     PictureJSONResultsWriter(const char filename[],
178                              const char builderName[],
179                              int buildNumber,
180                              int timestamp,
181                              const char gitHash[],
182                              int gitNumber)
183         : fStream(filename) {
184         fBuilderName = SkString(builderName);
185         fBuildNumber = buildNumber;
186         fTimestamp = timestamp;
187         fGitHash = SkString(gitHash);
188         fGitNumber = gitNumber;
189         fBuilderData = this->makeBuilderJson();
190     }
191 
bench(const char name[],int32_t x,int32_t y)192     void bench(const char name[], int32_t x, int32_t y) override {
193         fBenchName = SkString(name);
194     }
logRenderer(sk_tools::PictureRenderer * pr)195     void logRenderer(sk_tools::PictureRenderer* pr) override {
196         fParams = pr->getJSONConfig();
197         fConfigString = pr->getConfigName();
198     }
199     // Apparently tiles aren't used, so tileMeta is empty
tileMeta(int x,int y,int tx,int ty)200     void tileMeta(int x, int y, int tx, int ty) override {}
201     // Flags aren't used, so addTileFlag is empty
addTileFlag(PictureResultsWriter::TileFlags flag)202     void addTileFlag(PictureResultsWriter::TileFlags flag) override {}
203     virtual void tileData(
204             TimerData* data,
205             const char format[],
206             const TimerData::Result result,
207             uint32_t timerTypes,
208             int numInnerLoops = 1) override {
209         Json::Value newData = data->getJSON(timerTypes, result, numInnerLoops);
210         Json::Value combinedParams(fBuilderData);
211         for(Json::ValueIterator iter = fParams.begin(); iter != fParams.end();
212                 iter++) {
213             combinedParams[iter.key().asString()]= *iter;
214         }
215         // For each set of timer data
216         for(Json::ValueIterator iter = newData.begin(); iter != newData.end();
217                 iter++) {
218             Json::Value data;
219             data["buildNumber"] = fBuildNumber;
220             data["timestamp"] = fTimestamp;
221             data["gitHash"] = fGitHash.c_str();
222             data["gitNumber"] = fGitNumber;
223             data["isTrybot"] = fBuilderName.endsWith("Trybot");
224 
225             data["params"] = combinedParams;
226             data["params"]["benchName"] = fBenchName.c_str();
227 
228             // Not including skpSize because that's deprecated?
229             data["key"] = this->makeKey(iter.key().asString().c_str()).c_str();
230             // Get the data
231             SkTArray<double> times;
232             Json::Value val = *iter;
233             for(Json::ValueIterator vals = val.begin(); vals != val.end();
234                     vals++) {
235                 times.push_back((*vals).asDouble());
236             }
237             qsort(static_cast<void*>(times.begin()), times.count(),
238                     sizeof(double), PictureJSONResultsWriter::CompareDoubles);
239             data["value"] = times[static_cast<int>(times.count() * 0.25f)];
240             data["params"]["measurementType"] = iter.key().asString();
241             fStream.writeText(Json::FastWriter().write(data).c_str());
242         }
243     }
end()244     void end() override {
245        fStream.flush();
246     }
247 private:
makeBuilderJson()248     Json::Value makeBuilderJson() const {
249         static const int kNumKeys = 6;
250         static const char* kKeys[kNumKeys] = {
251             "role", "os", "model", "gpu", "arch", "configuration"};
252         Json::Value builderData;
253 
254         if (!fBuilderName.isEmpty()) {
255             SkTArray<SkString> splitBuilder;
256             SkStrSplit(fBuilderName.c_str(), "-", &splitBuilder);
257             SkASSERT(splitBuilder.count() >= kNumKeys);
258             for (int i = 0; i < kNumKeys && i < splitBuilder.count(); ++i) {
259                 builderData[kKeys[i]] = splitBuilder[i].c_str();
260             }
261             builderData["builderName"] = fBuilderName.c_str();
262             if (kNumKeys < splitBuilder.count()) {
263                 SkString extras;
264                 for (int i = kNumKeys; i < splitBuilder.count(); ++i) {
265                     extras.append(splitBuilder[i]);
266                     if (i != splitBuilder.count() - 1) {
267                         extras.append("-");
268                     }
269                 }
270                 builderData["badParams"] = extras.c_str();
271             }
272         }
273         return builderData;
274     }
275 
CompareDoubles(const void * p1,const void * p2)276     static int CompareDoubles(const void* p1, const void* p2) {
277         if(*static_cast<const double*>(p1) < *static_cast<const double*>(p2)) {
278             return -1;
279         } else if(*static_cast<const double*>(p1) ==
280                 *static_cast<const double*>(p2)) {
281             return 0;
282         } else {
283             return 1;
284         }
285     }
makeKey(const char measurementType[])286     SkString makeKey(const char measurementType[]) const {
287         SkString tmp(fBuilderName);
288         tmp.append("_");
289         tmp.append(fBenchName);
290         tmp.append("_");
291         tmp.append(fConfigString);
292         tmp.append("_");
293         tmp.append(measurementType);
294         return tmp;
295     }
296 
297     SkFILEWStream   fStream;
298     Json::Value     fBuilderData;
299     SkString        fBenchName;
300     Json::Value     fParams;
301 
302     SkString        fConfigString;
303     SkString        fBuilderName;
304     int             fBuildNumber;
305     int             fTimestamp;
306     SkString        fGitHash;
307     int             fGitNumber;
308 };
309 
310 #endif
311