Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2013 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 
      8 #include "BenchTimer.h"
      9 #include "Benchmark.h"
     10 #include "LazyDecodeBitmap.h"
     11 #include "PictureBenchmark.h"
     12 #include "PictureRenderer.h"
     13 #include "SkCommandLineFlags.h"
     14 #include "SkForceLinking.h"
     15 #include "SkGraphics.h"
     16 #include "SkStream.h"
     17 #include "SkString.h"
     18 #include "SkTArray.h"
     19 
     20 typedef sk_tools::PictureRenderer::BBoxHierarchyType BBoxType;
     21 static const int kBBoxTypeCount = sk_tools::PictureRenderer::kLast_BBoxHierarchyType + 1;
     22 
     23 
     24 DEFINE_string2(skps, r, "", "The list of SKPs to benchmark.");
     25 DEFINE_string(bb_types, "", "The set of bbox types to test. If empty, all are tested. "
     26                        "Should be one or more of none, quadtree, rtree, tilegrid.");
     27 DEFINE_int32(record, 100, "Number of times to record each SKP.");
     28 DEFINE_int32(playback, 1, "Number of times to playback each SKP.");
     29 DEFINE_int32(tilesize, 256, "The size of a tile.");
     30 
     31 struct Measurement {
     32     SkString fName;
     33     double fRecordAverage[kBBoxTypeCount];
     34     double fPlaybackAverage[kBBoxTypeCount];
     35 };
     36 
     37 const char* kBBoxHierarchyTypeNames[kBBoxTypeCount] = {
     38     "none", // kNone_BBoxHierarchyType
     39     "quadtree", // kQuadTree_BBoxHierarchyType
     40     "rtree", // kRTree_BBoxHierarchyType
     41     "tilegrid", // kTileGrid_BBoxHierarchyType
     42 };
     43 
     44 static SkPicture* pic_from_path(const char path[]) {
     45     SkFILEStream stream(path);
     46     if (!stream.isValid()) {
     47         SkDebugf("-- Can't open '%s'\n", path);
     48         return NULL;
     49     }
     50     return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap);
     51 }
     52 
     53 /**
     54  * This function is the sink to which all work ends up going.
     55  * @param renderer The renderer to use to perform the work.
     56  *                 To measure rendering, use a TiledPictureRenderer.
     57  *                 To measure recording, use a RecordPictureRenderer.
     58  * @param bBoxType The bounding box hierarchy type to use.
     59  * @param pic The picture to draw to the renderer.
     60  * @param numRepeats The number of times to repeat the draw.
     61  * @param timer The timer used to benchmark the work.
     62  */
     63 static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
     64         BBoxType bBoxType,
     65         SkPicture* pic,
     66         const int numRepeats,
     67         BenchTimer* timer) {
     68     renderer->setBBoxHierarchyType(bBoxType);
     69     renderer->setGridSize(FLAGS_tilesize, FLAGS_tilesize);
     70     renderer->init(pic, NULL, NULL, NULL, false);
     71 
     72     SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats);
     73     for (int i = 0; i < numRepeats; ++i) {
     74         renderer->setup();
     75         // Render once to fill caches
     76         renderer->render();
     77         // Render again to measure
     78         timer->start();
     79         renderer->render();
     80         timer->end();
     81     }
     82 }
     83 
     84 int tool_main(int argc, char** argv);
     85 int tool_main(int argc, char** argv) {
     86     SkCommandLineFlags::Parse(argc, argv);
     87     SkAutoGraphics ag;
     88     bool includeBBoxType[kBBoxTypeCount];
     89     for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
     90         includeBBoxType[bBoxType] = (FLAGS_bb_types.count() == 0) ||
     91             FLAGS_bb_types.contains(kBBoxHierarchyTypeNames[bBoxType]);
     92     }
     93     // go through all the pictures
     94     SkTArray<Measurement> measurements;
     95     for (int index = 0; index < FLAGS_skps.count(); ++index) {
     96         const char* path = FLAGS_skps[index];
     97         SkPicture* picture = pic_from_path(path);
     98         if (NULL == picture) {
     99             SkDebugf("Couldn't create picture. Ignoring path: %s\n", path);
    100             continue;
    101         }
    102         SkDebugf("Benchmarking path: %s\n", path);
    103         Measurement& measurement = measurements.push_back();
    104         measurement.fName = path;
    105         for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
    106             if (!includeBBoxType[bBoxType]) { continue; }
    107             if (FLAGS_playback > 0) {
    108                 sk_tools::TiledPictureRenderer playbackRenderer;
    109                 BenchTimer playbackTimer;
    110                 do_benchmark_work(&playbackRenderer, (BBoxType)bBoxType,
    111                                   picture, FLAGS_playback, &playbackTimer);
    112                 measurement.fPlaybackAverage[bBoxType] = playbackTimer.fCpu;
    113             }
    114             if (FLAGS_record > 0) {
    115                 sk_tools::RecordPictureRenderer recordRenderer;
    116                 BenchTimer recordTimer;
    117                 do_benchmark_work(&recordRenderer, (BBoxType)bBoxType,
    118                                   picture, FLAGS_record, &recordTimer);
    119                 measurement.fRecordAverage[bBoxType] = recordTimer.fCpu;
    120             }
    121         }
    122     }
    123 
    124     Measurement globalMeasurement;
    125     for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
    126         if (!includeBBoxType[bBoxType]) { continue; }
    127         globalMeasurement.fPlaybackAverage[bBoxType] = 0;
    128         globalMeasurement.fRecordAverage[bBoxType] = 0;
    129         for (int index = 0; index < measurements.count(); ++index) {
    130             const Measurement& measurement = measurements[index];
    131             globalMeasurement.fPlaybackAverage[bBoxType] +=
    132                 measurement.fPlaybackAverage[bBoxType];
    133             globalMeasurement.fRecordAverage[bBoxType] +=
    134                 measurement.fRecordAverage[bBoxType];
    135         }
    136         globalMeasurement.fPlaybackAverage[bBoxType] /= measurements.count();
    137         globalMeasurement.fRecordAverage[bBoxType] /= measurements.count();
    138     }
    139 
    140     // Output gnuplot readable histogram data..
    141     const char* pbTitle = "bbh_shootout_playback.dat";
    142     const char* recTitle = "bbh_shootout_record.dat";
    143     SkFILEWStream playbackOut(pbTitle);
    144     SkFILEWStream recordOut(recTitle);
    145     recordOut.writeText("# ");
    146     playbackOut.writeText("# ");
    147     SkDebugf("---\n");
    148     for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
    149         if (!includeBBoxType[bBoxType]) { continue; }
    150         SkString out;
    151         out.printf("%s ", kBBoxHierarchyTypeNames[bBoxType]);
    152         recordOut.writeText(out.c_str());
    153         playbackOut.writeText(out.c_str());
    154 
    155         if (FLAGS_record > 0) {
    156             SkDebugf("Average %s recording time: %.3fms\n",
    157                 kBBoxHierarchyTypeNames[bBoxType],
    158                 globalMeasurement.fRecordAverage[bBoxType]);
    159         }
    160         if (FLAGS_playback > 0) {
    161             SkDebugf("Average %s playback time: %.3fms\n",
    162                 kBBoxHierarchyTypeNames[bBoxType],
    163                 globalMeasurement.fPlaybackAverage[bBoxType]);
    164         }
    165     }
    166     recordOut.writeText("\n");
    167     playbackOut.writeText("\n");
    168     // Write to file, and save recording averages.
    169     for (int index = 0; index < measurements.count(); ++index) {
    170         const Measurement& measurement = measurements[index];
    171         SkString pbLine;
    172         SkString recLine;
    173 
    174         pbLine.printf("%d", index);
    175         recLine.printf("%d", index);
    176         for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
    177             if (!includeBBoxType[bBoxType]) { continue; }
    178             pbLine.appendf(" %f", measurement.fPlaybackAverage[bBoxType]);
    179             recLine.appendf(" %f", measurement.fRecordAverage[bBoxType]);
    180         }
    181         pbLine.appendf("\n");
    182         recLine.appendf("\n");
    183         playbackOut.writeText(pbLine.c_str());
    184         recordOut.writeText(recLine.c_str());
    185     }
    186     SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle);
    187     return 0;
    188 }
    189 
    190 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
    191 int main(int argc, char** argv) {
    192     return tool_main(argc, argv);
    193 }
    194 #endif
    195