OLD | NEW |
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 <ctype.h> | 8 #include <ctype.h> |
9 | 9 |
10 #include "Benchmark.h" | 10 #include "Benchmark.h" |
11 #include "CrashHandler.h" | 11 #include "CrashHandler.h" |
12 #include "ResultsWriter.h" | 12 #include "ResultsWriter.h" |
13 #include "Stats.h" | 13 #include "Stats.h" |
14 #include "Timer.h" | 14 #include "Timer.h" |
15 | 15 |
16 #include "SkCanvas.h" | 16 #include "SkCanvas.h" |
17 #include "SkCommandLineFlags.h" | 17 #include "SkCommandLineFlags.h" |
18 #include "SkForceLinking.h" | 18 #include "SkForceLinking.h" |
19 #include "SkGraphics.h" | 19 #include "SkGraphics.h" |
20 #include "SkString.h" | 20 #include "SkString.h" |
21 #include "SkSurface.h" | 21 #include "SkSurface.h" |
22 | 22 |
23 #if SK_SUPPORT_GPU | 23 #if SK_SUPPORT_GPU |
24 #include "GrContextFactory.h" | 24 #include "GrContextFactory.h" |
25 GrContextFactory gGrFactory; | 25 GrContextFactory gGrFactory; |
26 #endif | 26 #endif |
27 | 27 |
28 __SK_FORCE_IMAGE_DECODER_LINKING; | 28 __SK_FORCE_IMAGE_DECODER_LINKING; |
29 | 29 |
| 30 #if SK_DEBUG |
| 31 DEFINE_bool(runOnce, true, "Run each benchmark just once?"); |
| 32 #else |
| 33 DEFINE_bool(runOnce, false, "Run each benchmark just once?"); |
| 34 #endif |
| 35 |
30 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); | 36 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); |
31 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead."); | 37 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead."); |
32 DEFINE_double(overheadGoal, 0.0001, | 38 DEFINE_double(overheadGoal, 0.0001, |
33 "Loop until timer overhead is at most this fraction of our measurm
ents."); | 39 "Loop until timer overhead is at most this fraction of our measurm
ents."); |
34 DEFINE_string(match, "", "The usual filters on file names of benchmarks to measu
re."); | 40 DEFINE_string(match, "", "The usual filters on file names of benchmarks to measu
re."); |
35 DEFINE_bool2(quiet, q, false, "Print only bench name and minimum sample."); | 41 DEFINE_bool2(quiet, q, false, "Print only bench name and minimum sample."); |
36 DEFINE_bool2(verbose, v, false, "Print all samples."); | 42 DEFINE_bool2(verbose, v, false, "Print all samples."); |
37 DEFINE_string(config, "nonrendering 8888 gpu", "Configs to measure. Options: " | 43 DEFINE_string(config, "nonrendering 8888 gpu", "Configs to measure. Options: " |
38 "565 8888 gpu nonrendering debug nullgpu msaa4 msaa16 nvprmsaa4 nv
prmsaa16 angle"); | 44 "565 8888 gpu nonrendering debug nullgpu msaa4 msaa16 nvprmsaa4 nv
prmsaa16 angle"); |
39 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); | 45 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 // | 103 // |
98 // Doing some math, we get: | 104 // Doing some math, we get: |
99 // | 105 // |
100 // (overhead / FLAGS_overheadGoal) - overhead | 106 // (overhead / FLAGS_overheadGoal) - overhead |
101 // ------------------------------------------ < N | 107 // ------------------------------------------ < N |
102 // bench_plus_overhead - overhead) | 108 // bench_plus_overhead - overhead) |
103 // | 109 // |
104 // Luckily, this also works well in practice. :) | 110 // Luckily, this also works well in practice. :) |
105 const double numer = overhead / FLAGS_overheadGoal - overhead; | 111 const double numer = overhead / FLAGS_overheadGoal - overhead; |
106 const double denom = bench_plus_overhead - overhead; | 112 const double denom = bench_plus_overhead - overhead; |
107 const int loops = (int)ceil(numer / denom); | 113 const int loops = FLAGS_runOnce ? 1 : (int)ceil(numer / denom); |
108 | 114 |
109 for (int i = 0; i < FLAGS_samples; i++) { | 115 for (int i = 0; i < FLAGS_samples; i++) { |
110 samples[i] = time(loops, bench, canvas, NULL) / loops; | 116 samples[i] = time(loops, bench, canvas, NULL) / loops; |
111 } | 117 } |
112 return loops; | 118 return loops; |
113 } | 119 } |
114 | 120 |
115 #if SK_SUPPORT_GPU | 121 #if SK_SUPPORT_GPU |
116 static int gpu_bench(SkGLContextHelper* gl, | 122 static int gpu_bench(SkGLContextHelper* gl, |
117 Benchmark* bench, | 123 Benchmark* bench, |
118 SkCanvas* canvas, | 124 SkCanvas* canvas, |
119 double* samples) { | 125 double* samples) { |
120 // Make sure we're done with whatever came before. | 126 // Make sure we're done with whatever came before. |
121 SK_GL(*gl, Finish()); | 127 SK_GL(*gl, Finish()); |
122 | 128 |
123 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp
uMs. | 129 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp
uMs. |
124 int loops = 1; | 130 int loops = 1; |
125 double elapsed = 0; | 131 if (!FLAGS_runOnce) { |
126 do { | 132 double elapsed = 0; |
127 loops *= 2; | 133 do { |
128 // If the GPU lets frames lag at all, we need to make sure we're timing | 134 loops *= 2; |
129 // _this_ round, not still timing last round. We force this by looping | 135 // If the GPU lets frames lag at all, we need to make sure we're tim
ing |
130 // more times than any reasonable GPU will allow frames to lag. | 136 // _this_ round, not still timing last round. We force this by loop
ing |
131 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { | 137 // more times than any reasonable GPU will allow frames to lag. |
132 elapsed = time(loops, bench, canvas, gl); | 138 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { |
133 } | 139 elapsed = time(loops, bench, canvas, gl); |
134 } while (elapsed < FLAGS_gpuMs); | 140 } |
| 141 } while (elapsed < FLAGS_gpuMs); |
135 | 142 |
136 // We've overshot at least a little. Scale back linearly. | 143 // We've overshot at least a little. Scale back linearly. |
137 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed); | 144 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed); |
138 | 145 |
139 // Might as well make sure we're not still timing our calibration. | 146 // Might as well make sure we're not still timing our calibration. |
140 SK_GL(*gl, Finish()); | 147 SK_GL(*gl, Finish()); |
| 148 } |
141 | 149 |
142 // Pretty much the same deal as the calibration: do some warmup to make | 150 // Pretty much the same deal as the calibration: do some warmup to make |
143 // sure we're timing steady-state pipelined frames. | 151 // sure we're timing steady-state pipelined frames. |
144 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { | 152 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { |
145 time(loops, bench, canvas, gl); | 153 time(loops, bench, canvas, gl); |
146 } | 154 } |
147 | 155 |
148 // Now, actually do the timing! | 156 // Now, actually do the timing! |
149 for (int i = 0; i < FLAGS_samples; i++) { | 157 for (int i = 0; i < FLAGS_samples; i++) { |
150 samples[i] = time(loops, bench, canvas, gl) / loops; | 158 samples[i] = time(loops, bench, canvas, gl) / loops; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 log->option("build", "RELEASE"); | 253 log->option("build", "RELEASE"); |
246 #endif | 254 #endif |
247 } | 255 } |
248 | 256 |
249 int tool_main(int argc, char** argv); | 257 int tool_main(int argc, char** argv); |
250 int tool_main(int argc, char** argv) { | 258 int tool_main(int argc, char** argv) { |
251 SetupCrashHandler(); | 259 SetupCrashHandler(); |
252 SkAutoGraphics ag; | 260 SkAutoGraphics ag; |
253 SkCommandLineFlags::Parse(argc, argv); | 261 SkCommandLineFlags::Parse(argc, argv); |
254 | 262 |
| 263 if (FLAGS_runOnce) { |
| 264 FLAGS_samples = 1; |
| 265 FLAGS_gpuFrameLag = 0; |
| 266 } |
| 267 |
255 MultiResultsWriter log; | 268 MultiResultsWriter log; |
256 SkAutoTDelete<JSONResultsWriter> json; | 269 SkAutoTDelete<JSONResultsWriter> json; |
257 if (!FLAGS_outResultsFile.isEmpty()) { | 270 if (!FLAGS_outResultsFile.isEmpty()) { |
258 json.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0]))); | 271 json.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0]))); |
259 log.add(json.get()); | 272 log.add(json.get()); |
260 } | 273 } |
261 CallEnd<MultiResultsWriter> ender(log); | 274 CallEnd<MultiResultsWriter> ender(log); |
262 fill_static_options(&log); | 275 fill_static_options(&log); |
263 | 276 |
264 const double overhead = estimate_timer_overhead(); | 277 const double overhead = estimate_timer_overhead(); |
265 SkAutoTMalloc<double> samples(FLAGS_samples); | 278 SkAutoTMalloc<double> samples(FLAGS_samples); |
266 | 279 |
267 if (FLAGS_verbose) { | 280 if (FLAGS_runOnce) { |
| 281 SkDebugf("--runOnce is true; times would only be misleading so we won't
print them.\n"); |
| 282 } else if (FLAGS_verbose) { |
268 // No header. | 283 // No header. |
269 } else if (FLAGS_quiet) { | 284 } else if (FLAGS_quiet) { |
270 SkDebugf("median\tbench\tconfig\n"); | 285 SkDebugf("median\tbench\tconfig\n"); |
271 } else { | 286 } else { |
272 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\
n"); | 287 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\
n"); |
273 } | 288 } |
274 | 289 |
275 for (const BenchRegistry* r = BenchRegistry::Head(); r != NULL; r = r->next(
)) { | 290 for (const BenchRegistry* r = BenchRegistry::Head(); r != NULL; r = r->next(
)) { |
276 SkAutoTDelete<Benchmark> bench(r->factory()(NULL)); | 291 SkAutoTDelete<Benchmark> bench(r->factory()(NULL)); |
277 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { | 292 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { |
(...skipping 20 matching lines...) Expand all Loading... |
298 | 313 |
299 const char* config = targets[j]->config; | 314 const char* config = targets[j]->config; |
300 | 315 |
301 log.config(config); | 316 log.config(config); |
302 log.timer("min_ms", stats.min); | 317 log.timer("min_ms", stats.min); |
303 log.timer("median_ms", stats.median); | 318 log.timer("median_ms", stats.median); |
304 log.timer("mean_ms", stats.mean); | 319 log.timer("mean_ms", stats.mean); |
305 log.timer("max_ms", stats.max); | 320 log.timer("max_ms", stats.max); |
306 log.timer("stddev_ms", sqrt(stats.var)); | 321 log.timer("stddev_ms", sqrt(stats.var)); |
307 | 322 |
308 if (FLAGS_verbose) { | 323 if (FLAGS_runOnce) { |
| 324 if (targets.count() == 1) { |
| 325 config = ""; // Only print the config if we run the same ben
ch on more than one. |
| 326 } |
| 327 SkDebugf("%s\t%s\n", bench->getName(), config); |
| 328 } else if (FLAGS_verbose) { |
309 for (int i = 0; i < FLAGS_samples; i++) { | 329 for (int i = 0; i < FLAGS_samples; i++) { |
310 SkDebugf("%s ", humanize(samples[i]).c_str()); | 330 SkDebugf("%s ", humanize(samples[i]).c_str()); |
311 } | 331 } |
312 SkDebugf("%s\n", bench->getName()); | 332 SkDebugf("%s\n", bench->getName()); |
313 } else if (FLAGS_quiet) { | 333 } else if (FLAGS_quiet) { |
314 if (targets.count() == 1) { | 334 if (targets.count() == 1) { |
315 config = ""; // Only print the config if we run the same ben
ch on more than one. | 335 config = ""; // Only print the config if we run the same ben
ch on more than one. |
316 } | 336 } |
317 SkDebugf("%s\t%s\t%s\n", humanize(stats.median).c_str(), bench->
getName(), config); | 337 SkDebugf("%s\t%s\t%s\n", humanize(stats.median).c_str(), bench->
getName(), config); |
318 } else { | 338 } else { |
(...skipping 15 matching lines...) Expand all Loading... |
334 } | 354 } |
335 | 355 |
336 return 0; | 356 return 0; |
337 } | 357 } |
338 | 358 |
339 #if !defined SK_BUILD_FOR_IOS | 359 #if !defined SK_BUILD_FOR_IOS |
340 int main(int argc, char * const argv[]) { | 360 int main(int argc, char * const argv[]) { |
341 return tool_main(argc, (char**) argv); | 361 return tool_main(argc, (char**) argv); |
342 } | 362 } |
343 #endif | 363 #endif |
OLD | NEW |