Index: bench/benchmain.cpp |
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp |
deleted file mode 100644 |
index 9c5f0e9bd7af59868d3892e4910a7b32ced35f4f..0000000000000000000000000000000000000000 |
--- a/bench/benchmain.cpp |
+++ /dev/null |
@@ -1,716 +0,0 @@ |
-/* |
- * Copyright 2011 Google Inc. |
- * |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-#include "BenchLogger.h" |
-#include "Benchmark.h" |
-#include "CrashHandler.h" |
-#include "GMBench.h" |
-#include "ResultsWriter.h" |
-#include "SkCanvas.h" |
-#include "SkColorPriv.h" |
-#include "SkCommandLineFlags.h" |
-#include "SkData.h" |
-#include "SkDeferredCanvas.h" |
-#include "SkGraphics.h" |
-#include "SkImageEncoder.h" |
-#include "SkOSFile.h" |
-#include "SkPicture.h" |
-#include "SkPictureRecorder.h" |
-#include "SkString.h" |
-#include "SkSurface.h" |
-#include "Timer.h" |
- |
-#if SK_SUPPORT_GPU |
-#include "GrContext.h" |
-#include "GrContextFactory.h" |
-#include "GrRenderTarget.h" |
-#include "gl/GrGLDefines.h" |
-#else |
-class GrContext; |
-#endif // SK_SUPPORT_GPU |
- |
-#include <limits> |
- |
-enum BenchMode { |
- kNormal_BenchMode, |
- kDeferred_BenchMode, |
- kDeferredSilent_BenchMode, |
- kRecord_BenchMode, |
- kPictureRecord_BenchMode |
-}; |
-const char* BenchMode_Name[] = { |
- "normal", "deferred", "deferredSilent", "record", "picturerecord" |
-}; |
- |
-static const char kDefaultsConfigStr[] = "defaults"; |
- |
-#if SK_SUPPORT_GPU |
-static const char kGpuAPINameGL[] = "gl"; |
-static const char kGpuAPINameGLES[] = "gles"; |
-#endif |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-class Iter { |
-public: |
- Iter() : fBenches(BenchRegistry::Head()), fGMs(skiagm::GMRegistry::Head()) {} |
- |
- Benchmark* next() { |
- if (fBenches) { |
- BenchRegistry::Factory f = fBenches->factory(); |
- fBenches = fBenches->next(); |
- return (*f)(NULL); |
- } |
- |
- while (fGMs) { |
- SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(NULL)); |
- fGMs = fGMs->next(); |
- if (gm->getFlags() & skiagm::GM::kAsBench_Flag) { |
- return SkNEW_ARGS(GMBench, (gm.detach())); |
- } |
- } |
- |
- return NULL; |
- } |
- |
-private: |
- const BenchRegistry* fBenches; |
- const skiagm::GMRegistry* fGMs; |
-}; |
- |
-static void make_filename(const char name[], SkString* path) { |
- path->set(name); |
- for (int i = 0; name[i]; i++) { |
- switch (name[i]) { |
- case '/': |
- case '\\': |
- case ' ': |
- case ':': |
- path->writable_str()[i] = '-'; |
- break; |
- default: |
- break; |
- } |
- } |
-} |
- |
-static void saveFile(const char name[], const char config[], const char dir[], |
- const SkImage* image) { |
- SkAutoTUnref<SkData> data(image->encode(SkImageEncoder::kPNG_Type, 100)); |
- if (NULL == data.get()) { |
- return; |
- } |
- |
- SkString filename; |
- make_filename(name, &filename); |
- filename.appendf("_%s.png", config); |
- SkString path = SkOSPath::Join(dir, filename.c_str()); |
- ::remove(path.c_str()); |
- |
- SkFILEWStream stream(path.c_str()); |
- stream.write(data->data(), data->size()); |
-} |
- |
-static void perform_clip(SkCanvas* canvas, int w, int h) { |
- SkRect r; |
- |
- r.set(SkIntToScalar(10), SkIntToScalar(10), |
- SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); |
- canvas->clipRect(r, SkRegion::kIntersect_Op); |
- |
- r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), |
- SkIntToScalar(w-10), SkIntToScalar(h-10)); |
- canvas->clipRect(r, SkRegion::kXOR_Op); |
-} |
- |
-static void perform_rotate(SkCanvas* canvas, int w, int h) { |
- const SkScalar x = SkIntToScalar(w) / 2; |
- const SkScalar y = SkIntToScalar(h) / 2; |
- |
- canvas->translate(x, y); |
- canvas->rotate(SkIntToScalar(35)); |
- canvas->translate(-x, -y); |
-} |
- |
-static void perform_scale(SkCanvas* canvas, int w, int h) { |
- const SkScalar x = SkIntToScalar(w) / 2; |
- const SkScalar y = SkIntToScalar(h) / 2; |
- |
- canvas->translate(x, y); |
- // just enough so we can't take the sprite case |
- canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); |
- canvas->translate(-x, -y); |
-} |
- |
-static SkSurface* make_surface(SkColorType colorType, const SkIPoint& size, |
- Benchmark::Backend backend, int sampleCount, |
- GrContext* context) { |
- SkSurface* surface = NULL; |
- SkImageInfo info = SkImageInfo::Make(size.fX, size.fY, colorType, |
- kPremul_SkAlphaType); |
- |
- switch (backend) { |
- case Benchmark::kRaster_Backend: |
- surface = SkSurface::NewRaster(info); |
- surface->getCanvas()->clear(SK_ColorWHITE); |
- break; |
-#if SK_SUPPORT_GPU |
- case Benchmark::kGPU_Backend: { |
- surface = SkSurface::NewRenderTarget(context, info, sampleCount); |
- break; |
- } |
-#endif |
- case Benchmark::kPDF_Backend: |
- default: |
- SkDEBUGFAIL("unsupported"); |
- } |
- return surface; |
-} |
- |
-#if SK_SUPPORT_GPU |
-GrContextFactory gContextFactory; |
-typedef GrContextFactory::GLContextType GLContextType; |
-static const GLContextType kNative = GrContextFactory::kNative_GLContextType; |
-static const GLContextType kNVPR = GrContextFactory::kNVPR_GLContextType; |
-#if SK_ANGLE |
-static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType; |
-#endif |
-static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType; |
-static const GLContextType kNull = GrContextFactory::kNull_GLContextType; |
-#else |
-typedef int GLContextType; |
-static const GLContextType kNative = 0, kANGLE = 0, kDebug = 0, kNull = 0; |
-#endif |
- |
-#ifdef SK_DEBUG |
-static const bool kIsDebug = true; |
-#else |
-static const bool kIsDebug = false; |
-#endif |
- |
-static const struct Config { |
- SkColorType fColorType; |
- const char* name; |
- int sampleCount; |
- Benchmark::Backend backend; |
- GLContextType contextType; |
- bool runByDefault; |
-} gConfigs[] = { |
- { kN32_SkColorType, "NONRENDERING", 0, Benchmark::kNonRendering_Backend, kNative, true}, |
- { kN32_SkColorType, "8888", 0, Benchmark::kRaster_Backend, kNative, true}, |
- { kRGB_565_SkColorType, "565", 0, Benchmark::kRaster_Backend, kNative, true}, |
-#if SK_SUPPORT_GPU |
- { kN32_SkColorType, "GPU", 0, Benchmark::kGPU_Backend, kNative, true}, |
- { kN32_SkColorType, "MSAA4", 4, Benchmark::kGPU_Backend, kNative, false}, |
- { kN32_SkColorType, "MSAA16", 16, Benchmark::kGPU_Backend, kNative, false}, |
- { kN32_SkColorType, "NVPRMSAA4", 4, Benchmark::kGPU_Backend, kNVPR, true}, |
- { kN32_SkColorType, "NVPRMSAA16", 16, Benchmark::kGPU_Backend, kNVPR, false}, |
-#if SK_ANGLE |
- { kN32_SkColorType, "ANGLE", 0, Benchmark::kGPU_Backend, kANGLE, true}, |
-#endif // SK_ANGLE |
- { kN32_SkColorType, "Debug", 0, Benchmark::kGPU_Backend, kDebug, kIsDebug}, |
- { kN32_SkColorType, "NULLGPU", 0, Benchmark::kGPU_Backend, kNull, true}, |
-#endif // SK_SUPPORT_GPU |
-}; |
- |
-DEFINE_string(outDir, "", "If given, image of each bench will be put in outDir."); |
-DEFINE_string(timers, "cg", "Timers to display. " |
- "Options: w(all) W(all, truncated) c(pu) C(pu, truncated) g(pu)"); |
- |
-DEFINE_bool(rotate, false, "Rotate canvas before bench run?"); |
-DEFINE_bool(scale, false, "Scale canvas before bench run?"); |
-DEFINE_bool(clip, false, "Clip canvas before bench run?"); |
- |
-DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?"); |
-DEFINE_bool(forceBlend, false, "Force alpha blending?"); |
- |
-DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" " |
- "forces OpenGL API. Using \"gles\" forces OpenGL ES API. " |
- "Defaults to empty string, which selects the API native to the " |
- "system."); |
-DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes. 0 to disable cache."); |
-DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count. 0 to disable cache."); |
- |
-DEFINE_bool(gpu, true, "Allows GPU configs to be run. Applied after --configs."); |
-DEFINE_bool(cpu, true, "Allows non-GPU configs to be run. Applied after --config."); |
- |
-DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects."); |
-DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n" |
- "Multiple matches may be separated by spaces.\n" |
- "~ causes a matching test to always be skipped\n" |
- "^ requires the start of the test to match\n" |
- "$ requires the end of the test to match\n" |
- "^ and $ requires an exact match\n" |
- "If a test does not match any list entry,\n" |
- "it is skipped unless some list entry starts with ~\n"); |
-DEFINE_string(mode, "normal", |
- "normal: draw to a normal canvas;\n" |
- "deferred: draw to a deferred canvas;\n" |
- "deferredSilent: deferred with silent playback;\n" |
- "record: draw to an SkPicture;\n" |
- "picturerecord: draw from an SkPicture to an SkPicture.\n"); |
-DEFINE_string(config, kDefaultsConfigStr, |
- "Run configs given. By default, runs the configs marked \"runByDefault\" in gConfigs."); |
-DEFINE_string(logFile, "", "Also write stdout here."); |
-DEFINE_int32(minMs, 20, "Shortest time we'll allow a benchmark to run."); |
-DEFINE_int32(maxMs, 1000, "Longest time we'll allow a benchmark to run."); |
-DEFINE_bool(runOnce, kIsDebug, "Run each bench exactly once and don't report timings."); |
-DEFINE_double(error, 0.01, |
- "Ratio of subsequent bench measurements must drop within 1±error to converge."); |
-DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); |
-DEFINE_bool2(verbose, v, false, "Print more."); |
-DEFINE_string(outResultsFile, "", "If given, the results will be written to the file in JSON format."); |
-DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would have been done."); |
- |
-// Has this bench converged? First arguments are milliseconds / loop iteration, |
-// last is overall runtime in milliseconds. |
-static bool HasConverged(double prevPerLoop, double currPerLoop, double currRaw) { |
- if (currRaw < FLAGS_minMs) { |
- return false; |
- } |
- const double low = 1 - FLAGS_error, high = 1 + FLAGS_error; |
- const double ratio = currPerLoop / prevPerLoop; |
- return low < ratio && ratio < high; |
-} |
- |
-int tool_main(int argc, char** argv); |
-int tool_main(int argc, char** argv) { |
- SetupCrashHandler(); |
- SkCommandLineFlags::Parse(argc, argv); |
-#if SK_ENABLE_INST_COUNT |
- if (FLAGS_leaks) { |
- gPrintInstCount = true; |
- } |
-#endif |
- SkAutoGraphics ag; |
- |
- // First, parse some flags. |
- BenchLogger logger; |
- if (FLAGS_logFile.count()) { |
- logger.SetLogFile(FLAGS_logFile[0]); |
- } |
- |
- LoggerResultsWriter logWriter(logger, FLAGS_timeFormat[0]); |
- MultiResultsWriter writer; |
- writer.add(&logWriter); |
- |
- SkAutoTDelete<JSONResultsWriter> jsonWriter; |
- if (FLAGS_outResultsFile.count()) { |
- jsonWriter.reset(SkNEW(JSONResultsWriter(FLAGS_outResultsFile[0]))); |
- writer.add(jsonWriter.get()); |
- } |
- |
- // Instantiate after all the writers have been added to writer so that we |
- // call close() before their destructors are called on the way out. |
- CallEnd<MultiResultsWriter> ender(writer); |
- |
- const uint8_t alpha = FLAGS_forceBlend ? 0x80 : 0xFF; |
- SkTriState::State dither = SkTriState::kDefault; |
- for (size_t i = 0; i < 3; i++) { |
- if (strcmp(SkTriState::Name[i], FLAGS_forceDither[0]) == 0) { |
- dither = static_cast<SkTriState::State>(i); |
- } |
- } |
- |
- BenchMode benchMode = kNormal_BenchMode; |
- for (size_t i = 0; i < SK_ARRAY_COUNT(BenchMode_Name); i++) { |
- if (strcmp(FLAGS_mode[0], BenchMode_Name[i]) == 0) { |
- benchMode = static_cast<BenchMode>(i); |
- } |
- } |
- |
- SkTDArray<int> configs; |
- bool runDefaultConfigs = false; |
- // Try user-given configs first. |
- for (int i = 0; i < FLAGS_config.count(); i++) { |
- for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++j) { |
- if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) { |
- *configs.append() = j; |
- } else if (0 == strcmp(FLAGS_config[i], kDefaultsConfigStr)) { |
- runDefaultConfigs = true; |
- } |
- } |
- } |
- // If there weren't any, fill in with defaults. |
- if (runDefaultConfigs) { |
- for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(gConfigs)); ++i) { |
- if (gConfigs[i].runByDefault) { |
- *configs.append() = i; |
- } |
- } |
- } |
- // Filter out things we can't run. |
- if (kNormal_BenchMode != benchMode) { |
- // Non-rendering configs only run in normal mode |
- for (int i = 0; i < configs.count(); ++i) { |
- const Config& config = gConfigs[configs[i]]; |
- if (Benchmark::kNonRendering_Backend == config.backend) { |
- configs.remove(i, 1); |
- --i; |
- } |
- } |
- } |
- // Apply the gpu/cpu only flags |
- for (int i = 0; i < configs.count(); ++i) { |
- const Config& config = gConfigs[configs[i]]; |
- if (config.backend == Benchmark::kGPU_Backend) { |
- if (!FLAGS_gpu) { |
- configs.remove(i, 1); |
- --i; |
- } |
- } else if (!FLAGS_cpu) { |
- configs.remove(i, 1); |
- --i; |
- } |
- } |
- |
-#if SK_SUPPORT_GPU |
- GrGLStandard gpuAPI = kNone_GrGLStandard; |
- if (1 == FLAGS_gpuAPI.count()) { |
- if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) { |
- gpuAPI = kGL_GrGLStandard; |
- } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) { |
- gpuAPI = kGLES_GrGLStandard; |
- } else { |
- SkDebugf("Selected gpu API could not be used. Using the default.\n"); |
- } |
- } else if (FLAGS_gpuAPI.count() > 1) { |
- SkDebugf("Selected gpu API could not be used. Using the default.\n"); |
- } |
- |
- for (int i = 0; i < configs.count(); ++i) { |
- const Config& config = gConfigs[configs[i]]; |
- |
- if (Benchmark::kGPU_Backend == config.backend) { |
- GrContext* context = gContextFactory.get(config.contextType, gpuAPI); |
- if (NULL == context) { |
- SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n", |
- config.name); |
- configs.remove(i); |
- --i; |
- continue; |
- } |
- if (config.sampleCount > context->getMaxSampleCount()){ |
- SkDebugf( |
- "Sample count (%d) for config %s is not supported. Config will be skipped.\n", |
- config.sampleCount, config.name); |
- configs.remove(i); |
- --i; |
- continue; |
- } |
- } |
- } |
-#endif |
- |
- // All flags should be parsed now. Report our settings. |
- if (FLAGS_runOnce) { |
- logger.logError("bench was run with --runOnce, so we're going to hide the times." |
- " It's for your own good!\n"); |
- } |
- writer.option("mode", FLAGS_mode[0]); |
- writer.option("alpha", SkStringPrintf("0x%02X", alpha).c_str()); |
- writer.option("dither", SkTriState::Name[dither]); |
- |
- writer.option("rotate", SkStringPrintf("%d", FLAGS_rotate).c_str()); |
- writer.option("scale", SkStringPrintf("%d", FLAGS_scale).c_str()); |
- writer.option("clip", SkStringPrintf("%d", FLAGS_clip).c_str()); |
- |
-#if defined(SK_BUILD_FOR_WIN32) |
- writer.option("system", "WIN32"); |
-#elif defined(SK_BUILD_FOR_MAC) |
- writer.option("system", "MAC"); |
-#elif defined(SK_BUILD_FOR_ANDROID) |
- writer.option("system", "ANDROID"); |
-#elif defined(SK_BUILD_FOR_UNIX) |
- writer.option("system", "UNIX"); |
-#else |
- writer.option("system", "other"); |
-#endif |
- |
-#if defined(SK_DEBUG) |
- writer.option("build", "DEBUG"); |
-#else |
- writer.option("build", "RELEASE"); |
-#endif |
- |
- // Set texture cache limits if non-default. |
- for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { |
-#if SK_SUPPORT_GPU |
- const Config& config = gConfigs[i]; |
- if (Benchmark::kGPU_Backend != config.backend) { |
- continue; |
- } |
- GrContext* context = gContextFactory.get(config.contextType, gpuAPI); |
- if (NULL == context) { |
- continue; |
- } |
- |
- size_t bytes; |
- int count; |
- context->getResourceCacheLimits(&count, &bytes); |
- if (-1 != FLAGS_gpuCacheBytes) { |
- bytes = static_cast<size_t>(FLAGS_gpuCacheBytes); |
- } |
- if (-1 != FLAGS_gpuCacheCount) { |
- count = FLAGS_gpuCacheCount; |
- } |
- context->setResourceCacheLimits(count, bytes); |
-#endif |
- } |
- |
- // Run each bench in each configuration it supports and we asked for. |
- Iter iter; |
- Benchmark* bench; |
- while ((bench = iter.next()) != NULL) { |
- SkAutoTUnref<Benchmark> benchUnref(bench); |
- if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { |
- continue; |
- } |
- |
- bench->setForceAlpha(alpha); |
- bench->setDither(dither); |
- bench->preDraw(); |
- |
- bool loggedBenchName = false; |
- for (int i = 0; i < configs.count(); ++i) { |
- const int configIndex = configs[i]; |
- const Config& config = gConfigs[configIndex]; |
- |
- if (!bench->isSuitableFor(config.backend)) { |
- continue; |
- } |
- |
- GrContext* context = NULL; |
-#if SK_SUPPORT_GPU |
- SkGLContextHelper* glContext = NULL; |
- if (Benchmark::kGPU_Backend == config.backend) { |
- context = gContextFactory.get(config.contextType, gpuAPI); |
- if (NULL == context) { |
- continue; |
- } |
- glContext = gContextFactory.getGLContext(config.contextType); |
- } |
-#endif |
- |
- SkAutoTUnref<SkCanvas> canvas; |
- SkAutoTUnref<SkPicture> recordFrom; |
- SkPictureRecorder recorderTo; |
- const SkIPoint dim = bench->getSize(); |
- |
- SkAutoTUnref<SkSurface> surface; |
- if (Benchmark::kNonRendering_Backend != config.backend) { |
- surface.reset(make_surface(config.fColorType, |
- dim, |
- config.backend, |
- config.sampleCount, |
- context)); |
- if (!surface.get()) { |
- logger.logError(SkStringPrintf( |
- "Device creation failure for config %s. Will skip.\n", config.name)); |
- continue; |
- } |
- |
- switch(benchMode) { |
- case kDeferredSilent_BenchMode: |
- case kDeferred_BenchMode: |
- canvas.reset(SkDeferredCanvas::Create(surface.get())); |
- break; |
- case kRecord_BenchMode: |
- canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY))); |
- break; |
- case kPictureRecord_BenchMode: { |
- SkPictureRecorder recorderFrom; |
- bench->draw(1, recorderFrom.beginRecording(dim.fX, dim.fY)); |
- recordFrom.reset(recorderFrom.endRecording()); |
- canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY))); |
- break; |
- } |
- case kNormal_BenchMode: |
- canvas.reset(SkRef(surface->getCanvas())); |
- break; |
- default: |
- SkASSERT(false); |
- } |
- } |
- |
- if (NULL != canvas) { |
- canvas->clear(SK_ColorWHITE); |
- if (FLAGS_clip) { |
- perform_clip(canvas, dim.fX, dim.fY); |
- } |
- if (FLAGS_scale) { |
- perform_scale(canvas, dim.fX, dim.fY); |
- } |
- if (FLAGS_rotate) { |
- perform_rotate(canvas, dim.fX, dim.fY); |
- } |
- } |
- |
- if (!loggedBenchName) { |
- loggedBenchName = true; |
- writer.bench(bench->getName(), dim.fX, dim.fY); |
- } |
- |
-#if SK_SUPPORT_GPU |
- SkGLContextHelper* contextHelper = NULL; |
- if (Benchmark::kGPU_Backend == config.backend) { |
- contextHelper = gContextFactory.getGLContext(config.contextType); |
- } |
- Timer timer(contextHelper); |
-#else |
- Timer timer; |
-#endif |
- |
- double previous = std::numeric_limits<double>::infinity(); |
- bool converged = false; |
- |
- // variables used to compute loopsPerFrame |
- double frameIntervalTime = 0.0f; |
- int frameIntervalTotalLoops = 0; |
- |
- bool frameIntervalComputed = false; |
- int loopsPerFrame = 0; |
- int loopsPerIter = 0; |
- if (FLAGS_verbose) { SkDebugf("%s %s: ", bench->getName(), config.name); } |
- if (!FLAGS_dryRun) { |
- do { |
- // Ramp up 1 -> 2 -> 4 -> 8 -> 16 -> ... -> ~1 billion. |
- loopsPerIter = (loopsPerIter == 0) ? 1 : loopsPerIter * 2; |
- if (loopsPerIter >= (1<<30) || timer.fWall > FLAGS_maxMs) { |
- // If you find it takes more than a billion loops to get up to 20ms of runtime, |
- // you've got a computer clocked at several THz or have a broken benchmark. ;) |
- // "1B ought to be enough for anybody." |
- logger.logError(SkStringPrintf( |
- "\nCan't get %s %s to converge in %dms (%d loops)", |
- bench->getName(), config.name, FLAGS_maxMs, loopsPerIter)); |
- break; |
- } |
- |
- if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) { |
- // Clear the recorded commands so that they do not accumulate. |
- canvas.reset(SkRef(recorderTo.beginRecording(dim.fX, dim.fY))); |
- } |
- |
- timer.start(); |
- // Inner loop that allows us to break the run into smaller |
- // chunks (e.g. frames). This is especially useful for the GPU |
- // as we can flush and/or swap buffers to keep the GPU from |
- // queuing up too much work. |
- for (int loopCount = loopsPerIter; loopCount > 0; ) { |
- // Save and restore around each call to draw() to guarantee a pristine canvas. |
- SkAutoCanvasRestore saveRestore(canvas, true/*also save*/); |
- |
- int loops; |
- if (frameIntervalComputed && loopCount > loopsPerFrame) { |
- loops = loopsPerFrame; |
- loopCount -= loopsPerFrame; |
- } else { |
- loops = loopCount; |
- loopCount = 0; |
- } |
- |
- if (benchMode == kPictureRecord_BenchMode) { |
- recordFrom->draw(canvas); |
- } else { |
- bench->draw(loops, canvas); |
- } |
- |
- if (kDeferredSilent_BenchMode == benchMode) { |
- static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); |
- } else if (NULL != canvas) { |
- canvas->flush(); |
- } |
- |
- #if SK_SUPPORT_GPU |
- // swap drawing buffers on each frame to prevent the GPU |
- // from queuing up too much work |
- if (NULL != glContext) { |
- glContext->swapBuffers(); |
- } |
- #endif |
- } |
- |
- |
- |
- // Stop truncated timers before GL calls complete, and stop the full timers after. |
- timer.truncatedEnd(); |
- #if SK_SUPPORT_GPU |
- if (NULL != glContext) { |
- context->flush(); |
- SK_GL(*glContext, Finish()); |
- } |
- #endif |
- timer.end(); |
- |
- // setup the frame interval for subsequent iterations |
- if (!frameIntervalComputed) { |
- frameIntervalTime += timer.fWall; |
- frameIntervalTotalLoops += loopsPerIter; |
- if (frameIntervalTime >= FLAGS_minMs) { |
- frameIntervalComputed = true; |
- loopsPerFrame = |
- (int)(((double)frameIntervalTotalLoops / frameIntervalTime) * FLAGS_minMs); |
- if (loopsPerFrame < 1) { |
- loopsPerFrame = 1; |
- } |
- // SkDebugf(" %s has %d loops in %f ms (normalized to %d)\n", |
- // bench->getName(), frameIntervalTotalLoops, |
- // timer.fWall, loopsPerFrame); |
- } |
- } |
- |
- const double current = timer.fWall / loopsPerIter; |
- if (FLAGS_verbose && current > previous) { SkDebugf("↑"); } |
- if (FLAGS_verbose) { SkDebugf("%.3g ", current); } |
- converged = HasConverged(previous, current, timer.fWall); |
- previous = current; |
- } while (!FLAGS_runOnce && !converged); |
- } |
- if (FLAGS_verbose) { SkDebugf("\n"); } |
- |
- if (!FLAGS_dryRun && FLAGS_outDir.count() && Benchmark::kNonRendering_Backend != config.backend) { |
- SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); |
- if (image.get()) { |
- saveFile(bench->getName(), config.name, FLAGS_outDir[0], |
- image); |
- } |
- } |
- |
- if (FLAGS_runOnce) { |
- // Let's not mislead ourselves by looking at Debug build or single iteration bench times! |
- continue; |
- } |
- |
- // Normalize to ms per 1000 iterations. |
- const double normalize = 1000.0 / loopsPerIter; |
- const struct { char shortName; const char* longName; double ms; } times[] = { |
- {'w', "msecs", normalize * timer.fWall}, |
- {'W', "Wmsecs", normalize * timer.fTruncatedWall}, |
- {'c', "cmsecs", normalize * timer.fCpu}, |
- {'C', "Cmsecs", normalize * timer.fTruncatedCpu}, |
- {'g', "gmsecs", normalize * timer.fGpu}, |
- }; |
- |
- writer.config(config.name); |
- for (size_t i = 0; i < SK_ARRAY_COUNT(times); i++) { |
- if (strchr(FLAGS_timers[0], times[i].shortName) && times[i].ms > 0) { |
- writer.timer(times[i].longName, times[i].ms); |
- } |
- } |
- } |
- } |
-#if SK_SUPPORT_GPU |
- gContextFactory.destroyContexts(); |
-#endif |
- return 0; |
-} |
- |
-#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
-int main(int argc, char * const argv[]) { |
- return tool_main(argc, (char**) argv); |
-} |
-#endif |