OLD | NEW |
(Empty) | |
| 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 "Timer.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_BBoxHierarchy
Type + 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 te
sted. " |
| 26 "Should be one or more of none, 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 "rtree", // kRTree_BBoxHierarchyType |
| 40 }; |
| 41 |
| 42 static SkPicture* pic_from_path(const char path[]) { |
| 43 SkFILEStream stream(path); |
| 44 if (!stream.isValid()) { |
| 45 SkDebugf("-- Can't open '%s'\n", path); |
| 46 return NULL; |
| 47 } |
| 48 return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap); |
| 49 } |
| 50 |
| 51 /** |
| 52 * This function is the sink to which all work ends up going. |
| 53 * @param renderer The renderer to use to perform the work. |
| 54 * To measure rendering, use a TiledPictureRenderer. |
| 55 * To measure recording, use a RecordPictureRenderer. |
| 56 * @param bBoxType The bounding box hierarchy type to use. |
| 57 * @param pic The picture to draw to the renderer. |
| 58 * @param numRepeats The number of times to repeat the draw. |
| 59 * @param timer The timer used to benchmark the work. |
| 60 */ |
| 61 static void do_benchmark_work(sk_tools::PictureRenderer* renderer, |
| 62 BBoxType bBoxType, |
| 63 SkPicture* pic, |
| 64 const int numRepeats, |
| 65 Timer* timer) { |
| 66 renderer->setBBoxHierarchyType(bBoxType); |
| 67 renderer->init(pic, NULL, NULL, NULL, false, false); |
| 68 |
| 69 SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats); |
| 70 for (int i = 0; i < numRepeats; ++i) { |
| 71 renderer->setup(); |
| 72 // Render once to fill caches |
| 73 renderer->render(); |
| 74 // Render again to measure |
| 75 timer->start(); |
| 76 renderer->render(); |
| 77 timer->end(); |
| 78 } |
| 79 } |
| 80 |
| 81 int tool_main(int argc, char** argv); |
| 82 int tool_main(int argc, char** argv) { |
| 83 SkCommandLineFlags::Parse(argc, argv); |
| 84 SkAutoGraphics ag; |
| 85 bool includeBBoxType[kBBoxTypeCount]; |
| 86 for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
| 87 includeBBoxType[bBoxType] = (FLAGS_bb_types.count() == 0) || |
| 88 FLAGS_bb_types.contains(kBBoxHierarchyTypeNames[bBoxType]); |
| 89 } |
| 90 // go through all the pictures |
| 91 SkTArray<Measurement> measurements; |
| 92 for (int index = 0; index < FLAGS_skps.count(); ++index) { |
| 93 const char* path = FLAGS_skps[index]; |
| 94 SkPicture* picture = pic_from_path(path); |
| 95 if (NULL == picture) { |
| 96 SkDebugf("Couldn't create picture. Ignoring path: %s\n", path); |
| 97 continue; |
| 98 } |
| 99 SkDebugf("Benchmarking path: %s\n", path); |
| 100 Measurement& measurement = measurements.push_back(); |
| 101 measurement.fName = path; |
| 102 for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
| 103 if (!includeBBoxType[bBoxType]) { continue; } |
| 104 if (FLAGS_playback > 0) { |
| 105 #if SK_SUPPORT_GPU |
| 106 GrContext::Options grContextOpts; |
| 107 sk_tools::TiledPictureRenderer playbackRenderer(grContextOpts); |
| 108 #else |
| 109 sk_tools::TiledPictureRenderer playbackRenderer; |
| 110 #endif |
| 111 Timer playbackTimer; |
| 112 do_benchmark_work(&playbackRenderer, (BBoxType)bBoxType, |
| 113 picture, FLAGS_playback, &playbackTimer); |
| 114 measurement.fPlaybackAverage[bBoxType] = playbackTimer.fCpu; |
| 115 } |
| 116 if (FLAGS_record > 0) { |
| 117 #if SK_SUPPORT_GPU |
| 118 GrContext::Options grContextOpts; |
| 119 sk_tools::RecordPictureRenderer recordRenderer(grContextOpts); |
| 120 #else |
| 121 sk_tools::RecordPictureRenderer recordRenderer; |
| 122 #endif |
| 123 Timer recordTimer; |
| 124 do_benchmark_work(&recordRenderer, (BBoxType)bBoxType, |
| 125 picture, FLAGS_record, &recordTimer); |
| 126 measurement.fRecordAverage[bBoxType] = recordTimer.fCpu; |
| 127 } |
| 128 } |
| 129 } |
| 130 |
| 131 Measurement globalMeasurement; |
| 132 for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
| 133 if (!includeBBoxType[bBoxType]) { continue; } |
| 134 globalMeasurement.fPlaybackAverage[bBoxType] = 0; |
| 135 globalMeasurement.fRecordAverage[bBoxType] = 0; |
| 136 for (int index = 0; index < measurements.count(); ++index) { |
| 137 const Measurement& measurement = measurements[index]; |
| 138 globalMeasurement.fPlaybackAverage[bBoxType] += |
| 139 measurement.fPlaybackAverage[bBoxType]; |
| 140 globalMeasurement.fRecordAverage[bBoxType] += |
| 141 measurement.fRecordAverage[bBoxType]; |
| 142 } |
| 143 globalMeasurement.fPlaybackAverage[bBoxType] /= measurements.count(); |
| 144 globalMeasurement.fRecordAverage[bBoxType] /= measurements.count(); |
| 145 } |
| 146 |
| 147 // Output gnuplot readable histogram data.. |
| 148 const char* pbTitle = "bbh_shootout_playback.dat"; |
| 149 const char* recTitle = "bbh_shootout_record.dat"; |
| 150 SkFILEWStream playbackOut(pbTitle); |
| 151 SkFILEWStream recordOut(recTitle); |
| 152 recordOut.writeText("# "); |
| 153 playbackOut.writeText("# "); |
| 154 SkDebugf("---\n"); |
| 155 for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
| 156 if (!includeBBoxType[bBoxType]) { continue; } |
| 157 SkString out; |
| 158 out.printf("%s ", kBBoxHierarchyTypeNames[bBoxType]); |
| 159 recordOut.writeText(out.c_str()); |
| 160 playbackOut.writeText(out.c_str()); |
| 161 |
| 162 if (FLAGS_record > 0) { |
| 163 SkDebugf("Average %s recording time: %.3fms\n", |
| 164 kBBoxHierarchyTypeNames[bBoxType], |
| 165 globalMeasurement.fRecordAverage[bBoxType]); |
| 166 } |
| 167 if (FLAGS_playback > 0) { |
| 168 SkDebugf("Average %s playback time: %.3fms\n", |
| 169 kBBoxHierarchyTypeNames[bBoxType], |
| 170 globalMeasurement.fPlaybackAverage[bBoxType]); |
| 171 } |
| 172 } |
| 173 recordOut.writeText("\n"); |
| 174 playbackOut.writeText("\n"); |
| 175 // Write to file, and save recording averages. |
| 176 for (int index = 0; index < measurements.count(); ++index) { |
| 177 const Measurement& measurement = measurements[index]; |
| 178 SkString pbLine; |
| 179 SkString recLine; |
| 180 |
| 181 pbLine.printf("%d", index); |
| 182 recLine.printf("%d", index); |
| 183 for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) { |
| 184 if (!includeBBoxType[bBoxType]) { continue; } |
| 185 pbLine.appendf(" %f", measurement.fPlaybackAverage[bBoxType]); |
| 186 recLine.appendf(" %f", measurement.fRecordAverage[bBoxType]); |
| 187 } |
| 188 pbLine.appendf("\n"); |
| 189 recLine.appendf("\n"); |
| 190 playbackOut.writeText(pbLine.c_str()); |
| 191 recordOut.writeText(recLine.c_str()); |
| 192 } |
| 193 SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitl
e); |
| 194 return 0; |
| 195 } |
| 196 |
| 197 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
| 198 int main(int argc, char** argv) { |
| 199 return tool_main(argc, argv); |
| 200 } |
| 201 #endif |
OLD | NEW |