Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: tools/bench_record.cpp

Issue 338203002: Refine bench_record and bench_playback: (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« tools/bench_playback.cpp ('K') | « tools/bench_playback.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "BenchTimer.h"
9 #include "SkCommandLineFlags.h" 8 #include "SkCommandLineFlags.h"
10 #include "SkForceLinking.h" 9 #include "SkForceLinking.h"
11 #include "SkGraphics.h" 10 #include "SkGraphics.h"
12 #include "SkOSFile.h" 11 #include "SkOSFile.h"
13 #include "SkPicture.h" 12 #include "SkPicture.h"
14 #include "SkPictureRecorder.h" 13 #include "SkPictureRecorder.h"
15 #include "SkRecording.h" 14 #include "SkRecording.h"
16 #include "SkStream.h" 15 #include "SkStream.h"
17 #include "SkString.h" 16 #include "SkString.h"
17
18 #include "BenchTimer.h"
18 #include "LazyDecodeBitmap.h" 19 #include "LazyDecodeBitmap.h"
20 #include "Stats.h"
21
22 typedef WallTimer Timer;
19 23
20 __SK_FORCE_IMAGE_DECODER_LINKING; 24 __SK_FORCE_IMAGE_DECODER_LINKING;
21 25
22 // Just reading all the SKPs takes about 2 seconds for me, which is the same as about 100 loops of
23 // rerecording all the SKPs. So we default to --loops=900, which makes ~90% of our time spent in
24 // recording, and this should take ~20 seconds to run.
25
26 DEFINE_string2(skps, r, "skps", "Directory containing SKPs to read and re-record ."); 26 DEFINE_string2(skps, r, "skps", "Directory containing SKPs to read and re-record .");
27 DEFINE_int32(loops, 900, "Number of times to re-record each SKP."); 27 DEFINE_int32(samples, 10, "Number of times to re-record each SKP.");
28 DEFINE_bool(endRecording, true, "If false, don't time SkPicture::endRecording()" );
29 DEFINE_int32(nullSize, 1000, "Pretend dimension of null source picture.");
30 DEFINE_int32(tileGridSize, 512, "Set the tile grid size. Has no effect if bbh is not set to tilegrid."); 28 DEFINE_int32(tileGridSize, 512, "Set the tile grid size. Has no effect if bbh is not set to tilegrid.");
31 DEFINE_string(bbh, "", "Turn on the bbh and select the type, one of rtree, tileg rid, quadtree"); 29 DEFINE_string(bbh, "", "Turn on the bbh and select the type, one of rtree, tileg rid, quadtree");
32 DEFINE_bool(skr, false, "Record SKR instead of SKP."); 30 DEFINE_bool(skr, false, "Record SKR instead of SKP.");
33 DEFINE_string(match, "", "The usual filters on file names of SKPs to bench."); 31 DEFINE_string(match, "", "The usual filters on file names of SKPs to bench.");
34 DEFINE_string(timescale, "us", "Print times in ms, us, or ns"); 32 DEFINE_string(timescale, "us", "Print times in ms, us, or ns");
33 DEFINE_double(overheadGoal, 0.0001,
34 "Try to make timer overhead at most this fraction of our sample me asurements.");
35 DEFINE_int32(verbose, 0, "0: print min sample; "
36 "1: print min, mean, max and noise indication "
37 "2: print all samples");
35 38
36 static double scale_time(double ms) { 39 static double timescale() {
37 if (FLAGS_timescale.contains("us")) ms *= 1000; 40 if (FLAGS_timescale.contains("us")) return 1000;
38 if (FLAGS_timescale.contains("ns")) ms *= 1000000; 41 if (FLAGS_timescale.contains("ns")) return 1000000;
39 return ms; 42 return 1;
40 } 43 }
41 44
42 static SkBBHFactory* parse_FLAGS_bbh() { 45 static SkBBHFactory* parse_FLAGS_bbh() {
43 if (FLAGS_bbh.isEmpty()) { 46 if (FLAGS_bbh.isEmpty()) {
44 return NULL; 47 return NULL;
45 } 48 }
46 49
47 if (FLAGS_bbh.contains("rtree")) { 50 if (FLAGS_bbh.contains("rtree")) {
48 return SkNEW(SkRTreeFactory); 51 return SkNEW(SkRTreeFactory);
49 } 52 }
50 if (FLAGS_bbh.contains("tilegrid")) { 53 if (FLAGS_bbh.contains("tilegrid")) {
51 SkTileGridFactory::TileGridInfo info; 54 SkTileGridFactory::TileGridInfo info;
52 info.fTileInterval.set(FLAGS_tileGridSize, FLAGS_tileGridSize); 55 info.fTileInterval.set(FLAGS_tileGridSize, FLAGS_tileGridSize);
53 info.fMargin.setEmpty(); 56 info.fMargin.setEmpty();
54 info.fOffset.setZero(); 57 info.fOffset.setZero();
55 return SkNEW_ARGS(SkTileGridFactory, (info)); 58 return SkNEW_ARGS(SkTileGridFactory, (info));
56 } 59 }
57 if (FLAGS_bbh.contains("quadtree")) { 60 if (FLAGS_bbh.contains("quadtree")) {
58 return SkNEW(SkQuadTreeFactory); 61 return SkNEW(SkQuadTreeFactory);
59 } 62 }
60 SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid, quadtree.\n", FLAGS_bbh[0]); 63 SkDebugf("Invalid bbh type %s, must be one of rtree, tilegrid, quadtree.\n", FLAGS_bbh[0]);
61 return NULL; 64 return NULL;
62 } 65 }
63 66
64 static void bench_record(SkPicture* src, const char* name, SkBBHFactory* bbhFact ory) { 67 static void rerecord(const SkPicture& src, SkBBHFactory* bbhFactory) {
65 BenchTimer timer; 68 if (FLAGS_skr) {
66 timer.start(); 69 EXPERIMENTAL::SkRecording recording(src.width(), src.height());
67 const int width = src ? src->width() : FLAGS_nullSize; 70 src.draw(recording.canvas());
68 const int height = src ? src->height() : FLAGS_nullSize; 71 // Release and delete the SkPlayback so that recording optimizes its SkR ecord.
72 SkDELETE(recording.releasePlayback());
73 } else {
74 SkPictureRecorder recorder;
75 src.draw(recorder.beginRecording(src.width(), src.height(), bbhFactory)) ;
76 SkAutoTUnref<SkPicture> dst(recorder.endRecording());
77 }
78 }
69 79
70 for (int i = 0; i < FLAGS_loops; i++) { 80 static void bench_record(const SkPicture& src,
71 if (FLAGS_skr) { 81 const double timerOverhead,
72 EXPERIMENTAL::SkRecording recording(width, height); 82 const char* name,
73 if (NULL != src) { 83 SkBBHFactory* bbhFactory) {
74 src->draw(recording.canvas()); 84 // Rerecord once to warm up any caches. Otherwise the first sample can be v ery noisy.
75 } 85 rerecord(src, bbhFactory);
76 // Release and delete the SkPlayback so that recording optimizes its SkRecord. 86
77 SkDELETE(recording.releasePlayback()); 87 // Rerecord once to see how many times we should loop to make timer overhead insignificant.
78 } else { 88 Timer timer;
79 SkPictureRecorder recorder; 89 do {
80 SkCanvas* canvas = recorder.beginRecording(width, height, bbhFactory ); 90 timer.start(timescale());
81 if (NULL != src) { 91 rerecord(src, bbhFactory);
82 src->draw(canvas); 92 timer.end();
83 } 93 } while (timer.fWall < timerOverhead); // Loop just in case something biza rre happens.
84 if (FLAGS_endRecording) { 94
85 SkAutoTUnref<SkPicture> dst(recorder.endRecording()); 95 // We want (timer overhead / measurement) to be less than FLAGS_overheadGoal .
86 } 96 // So in each sample, we'll loop enough times to have made that true for our first measurement.
97 const int loops = (int)ceil(timerOverhead / timer.fWall / FLAGS_overheadGoal );
98
99 SkAutoTMalloc<double> samples(FLAGS_samples);
100 for (int i = 0; i < FLAGS_samples; i++) {
101 timer.start(timescale());
102 for (int j = 0; j < loops; j++) {
103 rerecord(src, bbhFactory);
87 } 104 }
105 timer.end();
106 samples[i] = timer.fWall / loops;
88 } 107 }
89 timer.end();
90 108
91 const double msPerLoop = timer.fCpu / (double)FLAGS_loops; 109 Stats stats(samples.get(), FLAGS_samples);
92 printf("%f\t%s\n", scale_time(msPerLoop), name); 110 if (FLAGS_verbose == 0) {
111 printf("%g\t%s\n", stats.min, name);
112 } else if (FLAGS_verbose == 1) {
113 // Get a rough idea of how noisy the measurements were.
114 const double noisePercent = 100 * sqrt(stats.var) / stats.mean;
115 printf("%g\t%g\t%g\t±%.0f%%\t%s\n", stats.min, stats.mean, stats.max, no isePercent, name);
116 } else if (FLAGS_verbose == 2) {
117 printf("%s", name);
118 for (int i = 0; i < FLAGS_samples; i++) {
119 printf("\t%g", samples[i]);
120 }
121 printf("\n");
122 }
93 } 123 }
94 124
95 int tool_main(int argc, char** argv); 125 int tool_main(int argc, char** argv);
96 int tool_main(int argc, char** argv) { 126 int tool_main(int argc, char** argv) {
97 SkCommandLineFlags::Parse(argc, argv); 127 SkCommandLineFlags::Parse(argc, argv);
98 SkAutoGraphics autoGraphics; 128 SkAutoGraphics autoGraphics;
99 129
100 if (FLAGS_bbh.count() > 1) { 130 if (FLAGS_bbh.count() > 1) {
101 SkDebugf("Multiple bbh arguments supplied.\n"); 131 SkDebugf("Multiple bbh arguments supplied.\n");
102 return 1; 132 return 1;
103 } 133 }
104 134
105 SkAutoTDelete<SkBBHFactory> bbhFactory(parse_FLAGS_bbh()); 135 SkAutoTDelete<SkBBHFactory> bbhFactory(parse_FLAGS_bbh());
106 bench_record(NULL, "NULL", bbhFactory.get()); 136
107 if (FLAGS_skps.isEmpty()) { 137 // Each run will use this timer overhead estimate to guess how many times it should run.
108 return 0; 138 static const int kOverheadLoops = 10000000;
139 Timer timer;
140 double overheadEstimate = 0.0;
141 for (int i = 0; i < kOverheadLoops; i++) {
142 timer.start(timescale());
143 timer.end();
144 overheadEstimate += timer.fWall;
109 } 145 }
146 overheadEstimate /= kOverheadLoops;
110 147
111 SkOSFile::Iter it(FLAGS_skps[0], ".skp"); 148 SkOSFile::Iter it(FLAGS_skps[0], ".skp");
112 SkString filename; 149 SkString filename;
113 bool failed = false; 150 bool failed = false;
114 while (it.next(&filename)) { 151 while (it.next(&filename)) {
115 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) { 152 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
116 continue; 153 continue;
117 } 154 }
118 155
119 const SkString path = SkOSPath::SkPathJoin(FLAGS_skps[0], filename.c_str ()); 156 const SkString path = SkOSPath::SkPathJoin(FLAGS_skps[0], filename.c_str ());
120 157
121 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str())); 158 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path.c_str()));
122 if (!stream) { 159 if (!stream) {
123 SkDebugf("Could not read %s.\n", path.c_str()); 160 SkDebugf("Could not read %s.\n", path.c_str());
124 failed = true; 161 failed = true;
125 continue; 162 continue;
126 } 163 }
127 SkAutoTUnref<SkPicture> src( 164 SkAutoTUnref<SkPicture> src(
128 SkPicture::CreateFromStream(stream, sk_tools::LazyDecodeBitmap)); 165 SkPicture::CreateFromStream(stream, sk_tools::LazyDecodeBitmap));
129 if (!src) { 166 if (!src) {
130 SkDebugf("Could not read %s as an SkPicture.\n", path.c_str()); 167 SkDebugf("Could not read %s as an SkPicture.\n", path.c_str());
131 failed = true; 168 failed = true;
132 continue; 169 continue;
133 } 170 }
134 bench_record(src, filename.c_str(), bbhFactory.get()); 171 bench_record(*src, overheadEstimate, filename.c_str(), bbhFactory.get()) ;
135 } 172 }
136 return failed ? 1 : 0; 173 return failed ? 1 : 0;
137 } 174 }
138 175
139 #if !defined SK_BUILD_FOR_IOS 176 #if !defined SK_BUILD_FOR_IOS
140 int main(int argc, char * const argv[]) { 177 int main(int argc, char * const argv[]) {
141 return tool_main(argc, (char**) argv); 178 return tool_main(argc, (char**) argv);
142 } 179 }
143 #endif 180 #endif
OLDNEW
« tools/bench_playback.cpp ('K') | « tools/bench_playback.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698