Home | History | Annotate | Download | only in tools
      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 
     30     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:
     53     PictureResultsMultiWriter()
     54         : fWriters() {}
     55     void add(PictureResultsWriter* newWriter) {
     56         fWriters.push_back(newWriter);
     57     }
     58     virtual ~PictureResultsMultiWriter() {}
     59     virtual void bench(const char name[], int32_t x, int32_t y) SK_OVERRIDE {
     60         for(int i=0; i<fWriters.count(); ++i) {
     61             fWriters[i]->bench(name, x, y);
     62         }
     63     }
     64     virtual void logRenderer(sk_tools::PictureRenderer *pr) SK_OVERRIDE {
     65         for(int i=0; i<fWriters.count(); ++i) {
     66             fWriters[i]->logRenderer(pr);
     67         }
     68     }
     69     virtual void tileMeta(int x, int y, int tx, int ty) SK_OVERRIDE {
     70         for(int i=0; i<fWriters.count(); ++i) {
     71             fWriters[i]->tileMeta(x, y, tx, ty);
     72         }
     73     }
     74     virtual void addTileFlag(PictureResultsWriter::TileFlags flag) SK_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) SK_OVERRIDE {
     85         for(int i=0; i<fWriters.count(); ++i) {
     86             fWriters[i]->tileData(data, format, result, timerTypes,
     87                                  numInnerLoops);
     88         }
     89     }
     90    virtual void end() SK_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:
    104     void logProgress(const char str[]) {
    105         if(fLogger != NULL) {
    106             fLogger->logProgress(str);
    107         }
    108     }
    109 public:
    110     PictureResultsLoggerWriter(BenchLogger* log)
    111           : fLogger(log), fCurrentLine() {}
    112     virtual void bench(const char name[], int32_t x, int32_t y) SK_OVERRIDE {
    113         SkString result;
    114         result.printf("running bench [%i %i] %s ", x, y, name);
    115         this->logProgress(result.c_str());
    116     }
    117     virtual void logRenderer(sk_tools::PictureRenderer* renderer) SK_OVERRIDE {
    118         fCurrentLine = renderer->getConfigName();
    119     }
    120     virtual void tileMeta(int x, int y, int tx, int ty) SK_OVERRIDE {
    121         fCurrentLine.appendf(": tile [%i,%i] out of [%i,%i]", x, y, tx, ty);
    122     }
    123     virtual void addTileFlag(PictureResultsWriter::TileFlags flag) SK_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) SK_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     }
    141     virtual void end() {}
    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:
    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 
    192     virtual void bench(const char name[], int32_t x, int32_t y) SK_OVERRIDE {
    193         fBenchName = SkString(name);
    194     }
    195     virtual void logRenderer(sk_tools::PictureRenderer* pr) SK_OVERRIDE {
    196         fParams = pr->getJSONConfig();
    197         fConfigString = pr->getConfigName();
    198     }
    199     // Apparently tiles aren't used, so tileMeta is empty
    200     virtual void tileMeta(int x, int y, int tx, int ty) SK_OVERRIDE {}
    201     // Flags aren't used, so addTileFlag is empty
    202     virtual void addTileFlag(PictureResultsWriter::TileFlags flag) SK_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) SK_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     }
    244     virtual void end() SK_OVERRIDE {
    245        fStream.flush();
    246     }
    247 private:
    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 
    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     }
    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