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" |
(...skipping 13 matching lines...) Expand all Loading... | |
24 #include "SkSurface.h" | 24 #include "SkSurface.h" |
25 | 25 |
26 #if SK_SUPPORT_GPU | 26 #if SK_SUPPORT_GPU |
27 #include "gl/GrGLDefines.h" | 27 #include "gl/GrGLDefines.h" |
28 #include "GrContextFactory.h" | 28 #include "GrContextFactory.h" |
29 GrContextFactory gGrFactory; | 29 GrContextFactory gGrFactory; |
30 #endif | 30 #endif |
31 | 31 |
32 __SK_FORCE_IMAGE_DECODER_LINKING; | 32 __SK_FORCE_IMAGE_DECODER_LINKING; |
33 | 33 |
34 #if SK_DEBUG | 34 static const int kAutoTuneLoops = -1; |
35 DEFINE_bool(runOnce, true, "Run each benchmark just once?"); | 35 |
36 static const int kDefaultLoops = | |
37 #ifdef SK_DEBUG | |
38 1; | |
36 #else | 39 #else |
37 DEFINE_bool(runOnce, false, "Run each benchmark just once?"); | 40 kAutoTuneLoops; |
38 #endif | 41 #endif |
39 | 42 |
43 static SkString loops_help_txt() { | |
44 SkString help; | |
45 help.printf("Number of times to run each bench. Set this to %d to auto-" | |
46 "tune for each bench. Timings are only reported when auto-tuning .", | |
47 kAutoTuneLoops); | |
48 return help; | |
49 } | |
50 | |
51 DEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str()); | |
52 | |
53 DEFINE_string2(writePath, w, "", "If set, write benches here as .pngs."); | |
54 | |
40 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); | 55 DEFINE_int32(samples, 10, "Number of samples to measure for each bench."); |
41 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead."); | 56 DEFINE_int32(overheadLoops, 100000, "Loops to estimate timer overhead."); |
42 DEFINE_double(overheadGoal, 0.0001, | 57 DEFINE_double(overheadGoal, 0.0001, |
43 "Loop until timer overhead is at most this fraction of our measurm ents."); | 58 "Loop until timer overhead is at most this fraction of our measurm ents."); |
44 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); | 59 DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); |
45 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allow s to lag."); | 60 DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allow s to lag."); |
46 | 61 |
47 DEFINE_string(outResultsFile, "", "If given, write results here as JSON."); | 62 DEFINE_string(outResultsFile, "", "If given, write results here as JSON."); |
48 DEFINE_int32(maxCalibrationAttempts, 3, | 63 DEFINE_int32(maxCalibrationAttempts, 3, |
49 "Try up to this many times to guess loops for a bench, or skip the bench."); | 64 "Try up to this many times to guess loops for a bench, or skip the bench."); |
50 DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this."); | 65 DEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this."); |
51 DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON."); | 66 DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON."); |
52 DEFINE_string(gitHash, "", "Git hash to add to JSON."); | 67 DEFINE_string(gitHash, "", "Git hash to add to JSON."); |
53 | 68 |
54 DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs."); | 69 DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs."); |
55 DEFINE_string(scales, "1.0", "Space-separated scales for SKPs."); | 70 DEFINE_string(scales, "1.0", "Space-separated scales for SKPs."); |
56 | 71 |
57 static SkString humanize(double ms) { | 72 static SkString humanize(double ms) { |
58 if (ms > 1e+3) return SkStringPrintf("%.3gs", ms/1e3); | 73 if (ms > 1e+3) return SkStringPrintf("%.3gs", ms/1e3); |
59 if (ms < 1e-3) return SkStringPrintf("%.3gns", ms*1e6); | 74 if (ms < 1e-3) return SkStringPrintf("%.3gns", ms*1e6); |
60 #ifdef SK_BUILD_FOR_WIN | 75 #ifdef SK_BUILD_FOR_WIN |
61 if (ms < 1) return SkStringPrintf("%.3gus", ms*1e3); | 76 if (ms < 1) return SkStringPrintf("%.3gus", ms*1e3); |
62 #else | 77 #else |
63 if (ms < 1) return SkStringPrintf("%.3gµs", ms*1e3); | 78 if (ms < 1) return SkStringPrintf("%.3gµs", ms*1e3); |
64 #endif | 79 #endif |
65 return SkStringPrintf("%.3gms", ms); | 80 return SkStringPrintf("%.3gms", ms); |
66 } | 81 } |
67 #define HUMANIZE(ms) humanize(ms).c_str() | 82 #define HUMANIZE(ms) humanize(ms).c_str() |
68 | 83 |
69 static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHel per* gl) { | 84 static double time(int loops, Benchmark* bench, SkCanvas* canvas, SkGLContextHel per* gl) { |
mtklein
2014/08/07 20:13:11
might put the if (canvas) { canvas->clear(white);
bsalomon
2014/08/07 20:18:07
Done.
| |
70 WallTimer timer; | 85 WallTimer timer; |
71 timer.start(); | 86 timer.start(); |
72 if (bench) { | 87 if (bench) { |
73 bench->draw(loops, canvas); | 88 bench->draw(loops, canvas); |
74 } | 89 } |
75 if (canvas) { | 90 if (canvas) { |
76 canvas->flush(); | 91 canvas->flush(); |
77 } | 92 } |
78 #if SK_SUPPORT_GPU | 93 #if SK_SUPPORT_GPU |
79 if (gl) { | 94 if (gl) { |
(...skipping 18 matching lines...) Expand all Loading... | |
98 SkDebugf("ERROR: clamping loops from %d to 1.\n", loops); | 113 SkDebugf("ERROR: clamping loops from %d to 1.\n", loops); |
99 return 1; | 114 return 1; |
100 } | 115 } |
101 if (loops > FLAGS_maxLoops) { | 116 if (loops > FLAGS_maxLoops) { |
102 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loo ps, FLAGS_maxLoops); | 117 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loo ps, FLAGS_maxLoops); |
103 return FLAGS_maxLoops; | 118 return FLAGS_maxLoops; |
104 } | 119 } |
105 return loops; | 120 return loops; |
106 } | 121 } |
107 | 122 |
123 static bool write_canvas_png(SkCanvas* canvas, const SkString& filename) { | |
124 if (filename.isEmpty()) { | |
125 return false; | |
126 } | |
127 if (kUnknown_SkColorType == canvas->imageInfo().fColorType) { | |
128 return false; | |
129 } | |
130 SkBitmap bmp; | |
131 bmp.setInfo(canvas->imageInfo()); | |
132 if (!canvas->readPixels(&bmp, 0, 0)) { | |
133 SkDebugf("Can't read canvas pixels.\n"); | |
134 return false; | |
135 } | |
136 SkString dir = SkOSPath::Dirname(filename.c_str()); | |
137 if (!sk_mkdir(dir.c_str())) { | |
138 SkDebugf("Can't make dir %s.\n", dir.c_str()); | |
139 return false; | |
140 } | |
141 SkFILEWStream stream(filename.c_str()); | |
142 if (!stream.isValid()) { | |
143 SkDebugf("Can't write %s.\n", filename.c_str()); | |
144 return false; | |
145 } | |
146 if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 1 00)) { | |
147 SkDebugf("Can't encode a PNG.\n"); | |
148 return false; | |
149 } | |
150 return true; | |
151 } | |
152 | |
153 static int kFailedLoops = -2; | |
108 static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas, double* samples) { | 154 static int cpu_bench(const double overhead, Benchmark* bench, SkCanvas* canvas, double* samples) { |
109 // First figure out approximately how many loops of bench it takes to make o verhead negligible. | 155 // First figure out approximately how many loops of bench it takes to make o verhead negligible. |
110 double bench_plus_overhead = 0.0; | 156 double bench_plus_overhead = 0.0; |
111 int round = 0; | 157 int round = 0; |
112 while (bench_plus_overhead < overhead) { | 158 if (kAutoTuneLoops == FLAGS_loops) { |
113 if (round++ == FLAGS_maxCalibrationAttempts) { | 159 while (bench_plus_overhead < overhead) { |
114 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping .\n", | 160 if (round++ == FLAGS_maxCalibrationAttempts) { |
115 bench->getName(), HUMANIZE(bench_plus_overhead), HUMANIZE(o verhead)); | 161 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skip ping.\n", |
116 return 0; | 162 bench->getName(), HUMANIZE(bench_plus_overhead), HUMANI ZE(overhead)); |
163 return kFailedLoops; | |
164 } | |
165 bench_plus_overhead = time(1, bench, canvas, NULL); | |
117 } | 166 } |
118 bench_plus_overhead = time(1, bench, canvas, NULL); | |
119 } | 167 } |
120 | 168 |
121 // Later we'll just start and stop the timer once but loop N times. | 169 // Later we'll just start and stop the timer once but loop N times. |
122 // We'll pick N to make timer overhead negligible: | 170 // We'll pick N to make timer overhead negligible: |
123 // | 171 // |
124 // overhead | 172 // overhead |
125 // ------------------------- < FLAGS_overheadGoal | 173 // ------------------------- < FLAGS_overheadGoal |
126 // overhead + N * Bench Time | 174 // overhead + N * Bench Time |
127 // | 175 // |
128 // where bench_plus_overhead ≈ overhead + Bench Time. | 176 // where bench_plus_overhead ≈ overhead + Bench Time. |
129 // | 177 // |
130 // Doing some math, we get: | 178 // Doing some math, we get: |
131 // | 179 // |
132 // (overhead / FLAGS_overheadGoal) - overhead | 180 // (overhead / FLAGS_overheadGoal) - overhead |
133 // ------------------------------------------ < N | 181 // ------------------------------------------ < N |
134 // bench_plus_overhead - overhead) | 182 // bench_plus_overhead - overhead) |
135 // | 183 // |
136 // Luckily, this also works well in practice. :) | 184 // Luckily, this also works well in practice. :) |
137 const double numer = overhead / FLAGS_overheadGoal - overhead; | 185 int loops = FLAGS_loops; |
138 const double denom = bench_plus_overhead - overhead; | 186 if (kAutoTuneLoops == loops) { |
139 const int loops = clamp_loops(FLAGS_runOnce ? 1 : (int)ceil(numer / denom)); | 187 const double numer = overhead / FLAGS_overheadGoal - overhead; |
188 const double denom = bench_plus_overhead - overhead; | |
189 loops = (int)ceil(numer / denom); | |
190 } | |
191 loops = clamp_loops(loops); | |
140 | 192 |
141 for (int i = 0; i < FLAGS_samples; i++) { | 193 for (int i = 0; i < FLAGS_samples; i++) { |
142 samples[i] = time(loops, bench, canvas, NULL) / loops; | 194 samples[i] = time(loops, bench, canvas, NULL) / loops; |
143 } | 195 } |
144 return loops; | 196 return loops; |
145 } | 197 } |
146 | 198 |
147 #if SK_SUPPORT_GPU | 199 #if SK_SUPPORT_GPU |
148 static int gpu_bench(SkGLContextHelper* gl, | 200 static int gpu_bench(SkGLContextHelper* gl, |
149 Benchmark* bench, | 201 Benchmark* bench, |
150 SkCanvas* canvas, | 202 SkCanvas* canvas, |
151 double* samples) { | 203 double* samples) { |
152 gl->makeCurrent(); | 204 gl->makeCurrent(); |
153 // Make sure we're done with whatever came before. | 205 // Make sure we're done with whatever came before. |
154 SK_GL(*gl, Finish()); | 206 SK_GL(*gl, Finish()); |
155 | 207 |
156 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp uMs. | 208 // First, figure out how many loops it'll take to get a frame up to FLAGS_gp uMs. |
157 int loops = 1; | 209 int loops = FLAGS_loops; |
158 if (!FLAGS_runOnce) { | 210 if (kAutoTuneLoops == loops) { |
211 loops = 1; | |
159 double elapsed = 0; | 212 double elapsed = 0; |
160 do { | 213 do { |
161 loops *= 2; | 214 loops *= 2; |
162 // If the GPU lets frames lag at all, we need to make sure we're tim ing | 215 // If the GPU lets frames lag at all, we need to make sure we're tim ing |
163 // _this_ round, not still timing last round. We force this by loop ing | 216 // _this_ round, not still timing last round. We force this by loop ing |
164 // more times than any reasonable GPU will allow frames to lag. | 217 // more times than any reasonable GPU will allow frames to lag. |
165 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { | 218 for (int i = 0; i < FLAGS_gpuFrameLag; i++) { |
166 elapsed = time(loops, bench, canvas, gl); | 219 elapsed = time(loops, bench, canvas, gl); |
167 } | 220 } |
168 } while (elapsed < FLAGS_gpuMs); | 221 } while (elapsed < FLAGS_gpuMs); |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 const char* fSourceType; | 520 const char* fSourceType; |
468 int fCurrentScale; | 521 int fCurrentScale; |
469 int fCurrentSKP; | 522 int fCurrentSKP; |
470 }; | 523 }; |
471 | 524 |
472 int nanobench_main(); | 525 int nanobench_main(); |
473 int nanobench_main() { | 526 int nanobench_main() { |
474 SetupCrashHandler(); | 527 SetupCrashHandler(); |
475 SkAutoGraphics ag; | 528 SkAutoGraphics ag; |
476 | 529 |
477 if (FLAGS_runOnce) { | 530 if (kAutoTuneLoops != FLAGS_loops) { |
478 FLAGS_samples = 1; | 531 FLAGS_samples = 1; |
479 FLAGS_gpuFrameLag = 0; | 532 FLAGS_gpuFrameLag = 0; |
480 } | 533 } |
481 | 534 |
535 if (!FLAGS_writePath.isEmpty()) { | |
536 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]); | |
537 if (!sk_mkdir(FLAGS_writePath[0])) { | |
538 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_wri tePath[0]); | |
539 FLAGS_writePath.set(0, NULL); | |
540 } | |
541 } | |
542 | |
482 MultiResultsWriter log; | 543 MultiResultsWriter log; |
483 SkAutoTDelete<NanoJSONResultsWriter> json; | 544 SkAutoTDelete<NanoJSONResultsWriter> json; |
484 if (!FLAGS_outResultsFile.isEmpty()) { | 545 if (!FLAGS_outResultsFile.isEmpty()) { |
485 const char* gitHash = FLAGS_gitHash.isEmpty() ? "unknown-revision" : FLA GS_gitHash[0]; | 546 const char* gitHash = FLAGS_gitHash.isEmpty() ? "unknown-revision" : FLA GS_gitHash[0]; |
486 json.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0], gitHash) )); | 547 json.reset(SkNEW(NanoJSONResultsWriter(FLAGS_outResultsFile[0], gitHash) )); |
487 log.add(json.get()); | 548 log.add(json.get()); |
488 } | 549 } |
489 CallEnd<MultiResultsWriter> ender(log); | 550 CallEnd<MultiResultsWriter> ender(log); |
490 | 551 |
491 if (1 == FLAGS_key.count() % 2) { | 552 if (1 == FLAGS_key.count() % 2) { |
492 SkDebugf("ERROR: --key must be passed with an even number of arguments.\ n"); | 553 SkDebugf("ERROR: --key must be passed with an even number of arguments.\ n"); |
493 return 1; | 554 return 1; |
494 } | 555 } |
495 for (int i = 1; i < FLAGS_key.count(); i += 2) { | 556 for (int i = 1; i < FLAGS_key.count(); i += 2) { |
496 log.key(FLAGS_key[i-1], FLAGS_key[i]); | 557 log.key(FLAGS_key[i-1], FLAGS_key[i]); |
497 } | 558 } |
498 fill_static_options(&log); | 559 fill_static_options(&log); |
499 | 560 |
500 const double overhead = estimate_timer_overhead(); | 561 const double overhead = estimate_timer_overhead(); |
501 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead)); | 562 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead)); |
502 | 563 |
503 SkAutoTMalloc<double> samples(FLAGS_samples); | 564 SkAutoTMalloc<double> samples(FLAGS_samples); |
504 | 565 |
505 if (FLAGS_runOnce) { | 566 if (kAutoTuneLoops != FLAGS_loops) { |
506 SkDebugf("--runOnce is true; times would only be misleading so we won't print them.\n"); | 567 SkDebugf("Fixed number of loops; times would only be misleading so we wo n't print them.\n"); |
507 } else if (FLAGS_verbose) { | 568 } else if (FLAGS_verbose) { |
508 // No header. | 569 // No header. |
509 } else if (FLAGS_quiet) { | 570 } else if (FLAGS_quiet) { |
510 SkDebugf("median\tbench\tconfig\n"); | 571 SkDebugf("median\tbench\tconfig\n"); |
511 } else { | 572 } else { |
512 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\ n"); | 573 SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\ n"); |
513 } | 574 } |
514 | 575 |
515 SkTDArray<Config> configs; | 576 SkTDArray<Config> configs; |
516 create_configs(&configs); | 577 create_configs(&configs); |
(...skipping 16 matching lines...) Expand all Loading... | |
533 SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface-> getCanvas() : NULL; | 594 SkCanvas* canvas = targets[j]->surface.get() ? targets[j]->surface-> getCanvas() : NULL; |
534 const char* config = targets[j]->config.name; | 595 const char* config = targets[j]->config.name; |
535 | 596 |
536 #if SK_DEBUG | 597 #if SK_DEBUG |
537 // skia:2797 Some SKPs SkASSERT in debug mode. Skip them for now. | 598 // skia:2797 Some SKPs SkASSERT in debug mode. Skip them for now. |
538 if (0 == strcmp("565", config) && SkStrContains(bench->getName(), ". skp")) { | 599 if (0 == strcmp("565", config) && SkStrContains(bench->getName(), ". skp")) { |
539 SkDebugf("Skipping 565 %s. See skia:2797\n", bench->getName()); | 600 SkDebugf("Skipping 565 %s. See skia:2797\n", bench->getName()); |
540 continue; | 601 continue; |
541 } | 602 } |
542 #endif | 603 #endif |
604 if (canvas) { | |
605 canvas->clear(SK_ColorWHITE); | |
606 } | |
543 | 607 |
544 const int loops = | 608 const int loops = |
545 #if SK_SUPPORT_GPU | 609 #if SK_SUPPORT_GPU |
546 Benchmark::kGPU_Backend == targets[j]->config.backend | 610 Benchmark::kGPU_Backend == targets[j]->config.backend |
547 ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get()) | 611 ? gpu_bench(targets[j]->gl, bench.get(), canvas, samples.get()) |
548 : | 612 : |
549 #endif | 613 #endif |
550 cpu_bench( overhead, bench.get(), canvas, samples.get()); | 614 cpu_bench( overhead, bench.get(), canvas, samples.get()); |
551 | 615 |
552 if (loops == 0) { | 616 if (canvas && !FLAGS_writePath.isEmpty() && NULL != FLAGS_writePath[ 0]) { |
617 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config ); | |
618 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getName ()); | |
619 pngFilename.append(".png"); | |
620 write_canvas_png(canvas, pngFilename); | |
621 } | |
622 | |
623 if (kFailedLoops == loops) { | |
553 // Can't be timed. A warning note has already been printed. | 624 // Can't be timed. A warning note has already been printed. |
554 continue; | 625 continue; |
555 } | 626 } |
556 | 627 |
557 Stats stats(samples.get(), FLAGS_samples); | 628 Stats stats(samples.get(), FLAGS_samples); |
558 log.config(config); | 629 log.config(config); |
559 benchStream.fillCurrentOptions(&log); | 630 benchStream.fillCurrentOptions(&log); |
560 #if SK_SUPPORT_GPU | 631 #if SK_SUPPORT_GPU |
561 if (Benchmark::kGPU_Backend == targets[j]->config.backend) { | 632 if (Benchmark::kGPU_Backend == targets[j]->config.backend) { |
562 fill_gpu_options(&log, targets[j]->gl); | 633 fill_gpu_options(&log, targets[j]->gl); |
563 } | 634 } |
564 #endif | 635 #endif |
565 log.timer("min_ms", stats.min); | 636 log.timer("min_ms", stats.min); |
566 log.timer("median_ms", stats.median); | 637 log.timer("median_ms", stats.median); |
567 log.timer("mean_ms", stats.mean); | 638 log.timer("mean_ms", stats.mean); |
568 log.timer("max_ms", stats.max); | 639 log.timer("max_ms", stats.max); |
569 log.timer("stddev_ms", sqrt(stats.var)); | 640 log.timer("stddev_ms", sqrt(stats.var)); |
570 | 641 |
571 if (FLAGS_runOnce) { | 642 if (kAutoTuneLoops != FLAGS_loops) { |
572 if (targets.count() == 1) { | 643 if (targets.count() == 1) { |
573 config = ""; // Only print the config if we run the same ben ch on more than one. | 644 config = ""; // Only print the config if we run the same ben ch on more than one. |
574 } | 645 } |
575 SkDebugf("%s\t%s\n", bench->getName(), config); | 646 SkDebugf("%s\t%s\n", bench->getName(), config); |
576 } else if (FLAGS_verbose) { | 647 } else if (FLAGS_verbose) { |
577 for (int i = 0; i < FLAGS_samples; i++) { | 648 for (int i = 0; i < FLAGS_samples; i++) { |
578 SkDebugf("%s ", HUMANIZE(samples[i])); | 649 SkDebugf("%s ", HUMANIZE(samples[i])); |
579 } | 650 } |
580 SkDebugf("%s\n", bench->getName()); | 651 SkDebugf("%s\n", bench->getName()); |
581 } else if (FLAGS_quiet) { | 652 } else if (FLAGS_quiet) { |
(...skipping 30 matching lines...) Expand all Loading... | |
612 | 683 |
613 return 0; | 684 return 0; |
614 } | 685 } |
615 | 686 |
616 #if !defined SK_BUILD_FOR_IOS | 687 #if !defined SK_BUILD_FOR_IOS |
617 int main(int argc, char** argv) { | 688 int main(int argc, char** argv) { |
618 SkCommandLineFlags::Parse(argc, argv); | 689 SkCommandLineFlags::Parse(argc, argv); |
619 return nanobench_main(); | 690 return nanobench_main(); |
620 } | 691 } |
621 #endif | 692 #endif |
OLD | NEW |