| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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" | 8 #include "BenchTimer.h" |
| 9 #include "ResultsWriter.h" | 9 #include "ResultsWriter.h" |
| 10 #include "SkBenchLogger.h" | 10 #include "SkBenchLogger.h" |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 DEFINE_string(logFile, "", "Also write stdout here."); | 260 DEFINE_string(logFile, "", "Also write stdout here."); |
| 261 DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run."); | 261 DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run."); |
| 262 DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run."); | 262 DEFINE_int32(maxMs, 4000, "Longest time we'll allow a benchmark to run."); |
| 263 DEFINE_double(error, 0.01, | 263 DEFINE_double(error, 0.01, |
| 264 "Ratio of subsequent bench measurements must drop within 1±error t
o converge."); | 264 "Ratio of subsequent bench measurements must drop within 1±error t
o converge."); |
| 265 DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per
1000 loops."); | 265 DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per
1000 loops."); |
| 266 DEFINE_bool2(verbose, v, false, "Print more."); | 266 DEFINE_bool2(verbose, v, false, "Print more."); |
| 267 DEFINE_string2(resourcePath, i, "resources", "directory for test resources."); | 267 DEFINE_string2(resourcePath, i, "resources", "directory for test resources."); |
| 268 DEFINE_string(outResultsFile, "", "If given, the results will be written to the
file in JSON format."); | 268 DEFINE_string(outResultsFile, "", "If given, the results will be written to the
file in JSON format."); |
| 269 | 269 |
| 270 DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would
have been done."); |
| 271 |
| 270 // Has this bench converged? First arguments are milliseconds / loop iteration, | 272 // Has this bench converged? First arguments are milliseconds / loop iteration, |
| 271 // last is overall runtime in milliseconds. | 273 // last is overall runtime in milliseconds. |
| 272 static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw)
{ | 274 static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw)
{ |
| 273 if (currRaw < FLAGS_minMs) { | 275 if (currRaw < FLAGS_minMs) { |
| 274 return false; | 276 return false; |
| 275 } | 277 } |
| 276 const double low = 1 - FLAGS_error, high = 1 + FLAGS_error; | 278 const double low = 1 - FLAGS_error, high = 1 + FLAGS_error; |
| 277 const double ratio = currPerLoop / prevPerLoop; | 279 const double ratio = currPerLoop / prevPerLoop; |
| 278 return low < ratio && ratio < high; | 280 return low < ratio && ratio < high; |
| 279 } | 281 } |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 bool converged = false; | 546 bool converged = false; |
| 545 | 547 |
| 546 // variables used to compute loopsPerFrame | 548 // variables used to compute loopsPerFrame |
| 547 double frameIntervalTime = 0.0f; | 549 double frameIntervalTime = 0.0f; |
| 548 int frameIntervalTotalLoops = 0; | 550 int frameIntervalTotalLoops = 0; |
| 549 | 551 |
| 550 bool frameIntervalComputed = false; | 552 bool frameIntervalComputed = false; |
| 551 int loopsPerFrame = 0; | 553 int loopsPerFrame = 0; |
| 552 int loopsPerIter = 0; | 554 int loopsPerIter = 0; |
| 553 if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.na
me); } | 555 if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.na
me); } |
| 554 do { | 556 if (!FLAGS_dryRun) { |
| 555 // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion. | 557 do { |
| 556 loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2; | 558 // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion. |
| 557 if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) { | 559 loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2; |
| 558 // If you find it takes more than a billion loops to get up
to 20ms of runtime, | 560 if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) { |
| 559 // you've got a computer clocked at several THz or have a br
oken benchmark. ;) | 561 // If you find it takes more than a billion loops to get
up to 20ms of runtime, |
| 560 // "1B ought to be enough for anybody." | 562 // you've got a computer clocked at several THz or have
a broken benchmark. ;) |
| 561 logger.logError(SkStringPrintf( | 563 // "1B ought to be enough for anybody." |
| 562 "\nCan't get %s %s to converge in %dms (%d loops)", | 564 logger.logError(SkStringPrintf( |
| 563 bench->getName(), config.name, FLAGS_maxMs, loopsPerIte
r)); | 565 "\nCan't get %s %s to converge in %dms (%d loops)", |
| 564 break; | 566 bench->getName(), config.name, FLAGS_maxMs, loopsPe
rIter)); |
| 565 } | 567 break; |
| 566 | |
| 567 if ((benchMode == kRecord_BenchMode || benchMode == kPictureReco
rd_BenchMode)) { | |
| 568 // Clear the recorded commands so that they do not accumulat
e. | |
| 569 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, k
RecordFlags))); | |
| 570 } | |
| 571 | |
| 572 timer.start(); | |
| 573 // Inner loop that allows us to break the run into smaller | |
| 574 // chunks (e.g. frames). This is especially useful for the GPU | |
| 575 // as we can flush and/or swap buffers to keep the GPU from | |
| 576 // queuing up too much work. | |
| 577 for (int loopCount = loopsPerIter; loopCount > 0; ) { | |
| 578 // Save and restore around each call to draw() to guarantee
a pristine canvas. | |
| 579 SkAutoCanvasRestore saveRestore(canvas, true/*also save*/); | |
| 580 | |
| 581 int loops; | |
| 582 if (frameIntervalComputed && loopCount > loopsPerFrame) { | |
| 583 loops = loopsPerFrame; | |
| 584 loopCount -= loopsPerFrame; | |
| 585 } else { | |
| 586 loops = loopCount; | |
| 587 loopCount = 0; | |
| 588 } | 568 } |
| 589 | 569 |
| 590 if (benchMode == kPictureRecord_BenchMode) { | 570 if ((benchMode == kRecord_BenchMode || benchMode == kPicture
Record_BenchMode)) { |
| 591 recordFrom.draw(canvas); | 571 // Clear the recorded commands so that they do not accum
ulate. |
| 592 } else { | 572 canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.f
Y, kRecordFlags))); |
| 593 bench->draw(loops, canvas); | |
| 594 } | 573 } |
| 595 | 574 |
| 596 if (kDeferredSilent_BenchMode == benchMode) { | 575 timer.start(); |
| 597 static_cast<SkDeferredCanvas*>(canvas.get())->silentFlus
h(); | 576 // Inner loop that allows us to break the run into smaller |
| 598 } else if (NULL != canvas) { | 577 // chunks (e.g. frames). This is especially useful for the G
PU |
| 599 canvas->flush(); | 578 // as we can flush and/or swap buffers to keep the GPU from |
| 579 // queuing up too much work. |
| 580 for (int loopCount = loopsPerIter; loopCount > 0; ) { |
| 581 // Save and restore around each call to draw() to guaran
tee a pristine canvas. |
| 582 SkAutoCanvasRestore saveRestore(canvas, true/*also save*
/); |
| 583 |
| 584 int loops; |
| 585 if (frameIntervalComputed && loopCount > loopsPerFrame)
{ |
| 586 loops = loopsPerFrame; |
| 587 loopCount -= loopsPerFrame; |
| 588 } else { |
| 589 loops = loopCount; |
| 590 loopCount = 0; |
| 591 } |
| 592 |
| 593 if (benchMode == kPictureRecord_BenchMode) { |
| 594 recordFrom.draw(canvas); |
| 595 } else { |
| 596 bench->draw(loops, canvas); |
| 597 } |
| 598 |
| 599 if (kDeferredSilent_BenchMode == benchMode) { |
| 600 static_cast<SkDeferredCanvas*>(canvas.get())->silent
Flush(); |
| 601 } else if (NULL != canvas) { |
| 602 canvas->flush(); |
| 603 } |
| 604 |
| 605 #if SK_SUPPORT_GPU |
| 606 // swap drawing buffers on each frame to prevent the GPU |
| 607 // from queuing up too much work |
| 608 if (NULL != glContext) { |
| 609 glContext->swapBuffers(); |
| 610 } |
| 611 #endif |
| 600 } | 612 } |
| 601 | 613 |
| 602 #if SK_SUPPORT_GPU | |
| 603 // swap drawing buffers on each frame to prevent the GPU | |
| 604 // from queuing up too much work | |
| 605 if (NULL != glContext) { | |
| 606 glContext->swapBuffers(); | |
| 607 } | |
| 608 #endif | |
| 609 } | |
| 610 | |
| 611 | 614 |
| 612 | 615 |
| 613 // Stop truncated timers before GL calls complete, and stop the
full timers after. | 616 // Stop truncated timers before GL calls complete, and stop
the full timers after. |
| 614 timer.truncatedEnd(); | 617 timer.truncatedEnd(); |
| 615 #if SK_SUPPORT_GPU | 618 #if SK_SUPPORT_GPU |
| 616 if (NULL != glContext) { | 619 if (NULL != glContext) { |
| 617 context->flush(); | 620 context->flush(); |
| 618 SK_GL(*glContext, Finish()); | 621 SK_GL(*glContext, Finish()); |
| 619 } | 622 } |
| 620 #endif | 623 #endif |
| 621 timer.end(); | 624 timer.end(); |
| 622 | 625 |
| 623 // setup the frame interval for subsequent iterations | 626 // setup the frame interval for subsequent iterations |
| 624 if (!frameIntervalComputed) { | 627 if (!frameIntervalComputed) { |
| 625 frameIntervalTime += timer.fWall; | 628 frameIntervalTime += timer.fWall; |
| 626 frameIntervalTotalLoops += loopsPerIter; | 629 frameIntervalTotalLoops += loopsPerIter; |
| 627 if (frameIntervalTime >= FLAGS_minMs) { | 630 if (frameIntervalTime >= FLAGS_minMs) { |
| 628 frameIntervalComputed = true; | 631 frameIntervalComputed = true; |
| 629 loopsPerFrame = | 632 loopsPerFrame = |
| 630 (int)(((double)frameIntervalTotalLoops / frameInterval
Time) * FLAGS_minMs); | 633 (int)(((double)frameIntervalTotalLoops / frameInte
rvalTime) * FLAGS_minMs); |
| 631 if (loopsPerFrame < 1) { | 634 if (loopsPerFrame < 1) { |
| 632 loopsPerFrame = 1; | 635 loopsPerFrame = 1; |
| 636 } |
| 637 // SkDebugf(" %s has %d loops in %f ms (normalized t
o %d)\n", |
| 638 // bench->getName(), frameIntervalTotalLoops
, |
| 639 // timer.fWall, loopsPerFrame); |
| 633 } | 640 } |
| 634 // SkDebugf(" %s has %d loops in %f ms (normalized to %d
)\n", | |
| 635 // bench->getName(), frameIntervalTotalLoops, | |
| 636 // timer.fWall, loopsPerFrame); | |
| 637 } | 641 } |
| 638 } | |
| 639 | 642 |
| 640 const double current = timer.fWall / loopsPerIter; | 643 const double current = timer.fWall / loopsPerIter; |
| 641 if (FLAGS_verbose && current > previous) { SkDebugf("↑"); } | 644 if (FLAGS_verbose && current > previous) { SkDebugf("↑"); } |
| 642 if (FLAGS_verbose) { SkDebugf("%.3g ", current); } | 645 if (FLAGS_verbose) { SkDebugf("%.3g ", current); } |
| 643 converged = HasConverged(previous, current, timer.fWall); | 646 converged = HasConverged(previous, current, timer.fWall); |
| 644 previous = current; | 647 previous = current; |
| 645 } while (!kIsDebug && !converged); | 648 } while (!kIsDebug && !converged); |
| 649 } |
| 646 if (FLAGS_verbose) { SkDebugf("\n"); } | 650 if (FLAGS_verbose) { SkDebugf("\n"); } |
| 647 | 651 |
| 648 if (FLAGS_outDir.count() && SkBenchmark::kNonRendering_Backend != co
nfig.backend) { | 652 if (!FLAGS_dryRun && FLAGS_outDir.count() && SkBenchmark::kNonRender
ing_Backend != config.backend) { |
| 649 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); | 653 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); |
| 650 if (image.get()) { | 654 if (image.get()) { |
| 651 saveFile(bench->getName(), config.name, FLAGS_outDir[0], | 655 saveFile(bench->getName(), config.name, FLAGS_outDir[0], |
| 652 image); | 656 image); |
| 653 } | 657 } |
| 654 } | 658 } |
| 655 | 659 |
| 656 if (kIsDebug) { | 660 if (kIsDebug) { |
| 657 // Let's not mislead ourselves by looking at Debug build bench t
imes! | 661 // Let's not mislead ourselves by looking at Debug build bench t
imes! |
| 658 continue; | 662 continue; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 680 gContextFactory.destroyContexts(); | 684 gContextFactory.destroyContexts(); |
| 681 #endif | 685 #endif |
| 682 return 0; | 686 return 0; |
| 683 } | 687 } |
| 684 | 688 |
| 685 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 689 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
| 686 int main(int argc, char * const argv[]) { | 690 int main(int argc, char * const argv[]) { |
| 687 return tool_main(argc, (char**) argv); | 691 return tool_main(argc, (char**) argv); |
| 688 } | 692 } |
| 689 #endif | 693 #endif |
| OLD | NEW |