diff options
Diffstat (limited to 'bench/benchmain.cpp')
-rw-r--r-- | bench/benchmain.cpp | 1000 |
1 files changed, 329 insertions, 671 deletions
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 472d4b95dc..289d5cb0a2 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -6,47 +6,37 @@ * found in the LICENSE file. */ - -#include "BenchTimer.h" - #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrContextFactory.h" -#include "gl/GrGLDefines.h" #include "GrRenderTarget.h" #include "SkGpuDevice.h" +#include "gl/GrGLDefines.h" #else class GrContext; #endif // SK_SUPPORT_GPU +#include "BenchTimer.h" #include "SkBenchLogger.h" #include "SkBenchmark.h" #include "SkBitmapDevice.h" #include "SkCanvas.h" #include "SkCommandLineFlags.h" #include "SkDeferredCanvas.h" -#include "SkColorPriv.h" #include "SkGraphics.h" #include "SkImageEncoder.h" -#include "SkNWayCanvas.h" +#include "SkOSFile.h" #include "SkPicture.h" #include "SkString.h" -#include "SkTArray.h" -#include "TimerData.h" - -enum benchModes { - kNormal_benchModes, - kDeferred_benchModes, - kDeferredSilent_benchModes, - kRecord_benchModes, - kPictureRecord_benchModes -}; -#ifdef SK_DEBUG -static const bool kDebugOnly = true; -#else -static const bool kDebugOnly = false; -#endif +enum BenchMode { + kNormal_BenchMode, + kDeferred_BenchMode, + kDeferredSilent_BenchMode, + kRecord_BenchMode, + kPictureRecord_BenchMode +}; +const char* BenchMode_Name[] = { "normal", "deferred", "deferredSilent", "record", "picturerecord" }; /////////////////////////////////////////////////////////////////////////////// @@ -58,43 +48,21 @@ static void erase(SkBitmap& bm) { } } -#if 0 -static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { - if (bm1.width() != bm2.width() || - bm1.height() != bm2.height() || - bm1.config() != bm2.config()) { - return false; - } - - size_t pixelBytes = bm1.width() * bm1.bytesPerPixel(); - for (int y = 0; y < bm1.height(); y++) { - if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) { - return false; - } - } - return true; -} -#endif - class Iter { public: - Iter(void* param) { - fBench = BenchRegistry::Head(); - fParam = param; - } + Iter() : fBench(BenchRegistry::Head()) {} SkBenchmark* next() { if (fBench) { BenchRegistry::Factory f = fBench->factory(); fBench = fBench->next(); - return f(fParam); + return f(NULL); } return NULL; } private: const BenchRegistry* fBench; - void* fParam; }; class AutoPrePostDraw { @@ -144,13 +112,12 @@ static void saveFile(const char name[], const char config[], const char dir[], } } - SkString str; - make_filename(name, &str); - str.appendf("_%s.png", config); - str.prepend(dir); - ::remove(str.c_str()); - SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, - 100); + SkString filename; + make_filename(name, &filename); + filename.appendf("_%s.png", config); + SkString path = SkOSPath::SkPathJoin(dir, filename.c_str()); + ::remove(path.c_str()); + SkImageEncoder::EncodeFile(path.c_str(), copy, SkImageEncoder::kPNG_Type, 100); } static void performClip(SkCanvas* canvas, int w, int h) { @@ -184,14 +151,6 @@ static void performScale(SkCanvas* canvas, int w, int h) { canvas->translate(-x, -y); } -static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { - if (argv < stop) { - *var = atoi(*argv) != 0; - return true; - } - return false; -} - enum Backend { kNonRendering_Backend, kRaster_Backend, @@ -237,111 +196,82 @@ static SkBaseDevice* make_device(SkBitmap::Config config, const SkIPoint& size, #if SK_SUPPORT_GPU GrContextFactory gContextFactory; typedef GrContextFactory::GLContextType GLContextType; -static const GLContextType kDontCareGLCtxType = GrContextFactory::kNative_GLContextType; +static const GLContextType kNative = GrContextFactory::kNative_GLContextType; +#if SK_ANGLE +static const GLContextType kANGLE = GrContextFactory::kANGLE_GLContextType; +#else +static const GLContextType kANGLE = kNative; +#endif +static const GLContextType kDebug = GrContextFactory::kDebug_GLContextType; +static const GLContextType kNull = GrContextFactory::kNull_GLContextType; #else typedef int GLContextType; -static const GLContextType kDontCareGLCtxType = 0; +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 { - SkBitmap::Config fConfig; - const char* fName; - int fSampleCnt; - Backend fBackend; - GLContextType fContextType; - bool fRunByDefault; +static const struct Config { + SkBitmap::Config config; + const char* name; + int sampleCount; + Backend backend; + GLContextType contextType; + bool runByDefault; } gConfigs[] = { - { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kDontCareGLCtxType, true }, - { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kDontCareGLCtxType, true }, - { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kDontCareGLCtxType, true }, + { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kNative, true}, + { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kNative, true}, + { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kNative, true}, #if SK_SUPPORT_GPU - { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, GrContextFactory::kNative_GLContextType, true }, - { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, GrContextFactory::kNative_GLContextType, false }, - { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, GrContextFactory::kNative_GLContextType, false }, + { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, kNative, true}, + { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, kNative, false}, + { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, kNative, false}, #if SK_ANGLE - { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, true }, + { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, kANGLE, true}, #endif // SK_ANGLE - { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, GrContextFactory::kDebug_GLContextType, kDebugOnly }, - { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, GrContextFactory::kNull_GLContextType, true }, + { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, kDebug, kIsDebug}, + { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, kNull, true}, #endif // SK_SUPPORT_GPU }; -static int findConfig(const char config[]) { - for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { - if (!strcmp(config, gConfigs[i].fName)) { - return i; - } - } - return -1; -} - -static void help() { - SkString configsStr; - static const size_t kConfigCount = SK_ARRAY_COUNT(gConfigs); - for (size_t i = 0; i < kConfigCount; ++i) { - configsStr.appendf("%s%s", gConfigs[i].fName, ((i == kConfigCount - 1) ? "" : "|")); - } - - SkDebugf("Usage: bench [-o outDir] [--repeat nr] [--logPerIter] " - "[--timers [wcgWC]*] [--rotate]\n" - " [--scale] [--clip] [--min] [--forceAA 1|0] [--forceFilter 1|0]\n" - " [--forceDither 1|0] [--forceBlend 1|0]" -#if SK_SUPPORT_GPU - " [--gpuCacheSize <bytes> <count>]" -#endif - "\n" - " [--strokeWidth width] [--match name]\n" - " [--mode normal|deferred|deferredSilent|record|picturerecord]\n" - " [--config "); - SkDebugf("%s]\n", configsStr.c_str()); - SkDebugf(" [-Dfoo bar] [--logFile filename] [-h|--help]"); - SkDebugf("\n\n"); - SkDebugf(" -o outDir : Image of each bench will be put in outDir.\n"); - SkDebugf(" --repeat nr : Each bench repeats for nr times.\n"); - SkDebugf(" --logPerIter : " - "Log each repeat timer instead of mean, default is disabled.\n"); - SkDebugf(" --timers [wcgWC]* : " - "Display wall, cpu, gpu, truncated wall or truncated cpu time for each bench.\n"); - SkDebugf(" --rotate : Rotate before each bench runs.\n"); - SkDebugf(" --scale : Scale before each bench runs.\n"); - SkDebugf(" --clip : Clip before each bench runs.\n"); - SkDebugf(" --min : Print the minimum times (instead of average).\n"); - SkDebugf(" --forceAA 1|0 : " - "Enable/disable anti-aliased, default is enabled.\n"); - SkDebugf(" --forceFilter 1|0 : " - "Enable/disable bitmap filtering, default is disabled.\n"); - SkDebugf(" --forceDither 1|0 : " - "Enable/disable dithering, default is disabled.\n"); - SkDebugf(" --forceBlend 1|0 : " - "Enable/disable dithering, default is disabled.\n"); -#if SK_SUPPORT_GPU - SkDebugf(" --gpuCacheSize <bytes> <count>: " - "limits gpu cache to bytes size or object count.\n"); - SkDebugf(" -1 for either value means use the default. 0 for either disables the cache.\n"); -#endif - SkDebugf(" --strokeWidth width : The width for path stroke.\n"); - SkDebugf(" --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"); - SkDebugf(" --mode normal|deferred|deferredSilent|record|picturerecord :\n" - " Run in the corresponding mode\n" - " normal, Use a normal canvas to draw to;\n" - " deferred, Use a deferrred canvas when drawing;\n" - " deferredSilent, deferred with silent playback;\n" - " record, Benchmark the time to record to an SkPicture;\n" - " picturerecord, Benchmark the time to do record from a \n" - " SkPicture to a SkPicture.\n"); - SkDebugf(" --logFile filename : destination for writing log output, in addition to stdout.\n"); - SkDebugf(" --config %s:\n", configsStr.c_str()); - SkDebugf(" Run bench in corresponding config mode.\n"); - SkDebugf(" -Dfoo bar : Add extra definition to bench.\n"); - SkDebugf(" -h|--help : Show this help message.\n"); -} +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_bool(forceAA, true, "Force anti-aliasing?"); +DEFINE_bool(forceFilter, false, "Force bitmap filtering?"); +DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?"); +DEFINE_bool(forceBlend, false, "Force alpha blending?"); + +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_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, "", "Run configs given. If empty, runs the defaults set in gConfigs."); +DEFINE_string(logFile, "", "Also write stdout here."); +DEFINE_int32(benchMs, 20, "Target time in ms to run each benchmark config."); +DEFINE_string(timeFormat, "%9.2f", "Format to print results, in milliseconds per 1000 loops."); int tool_main(int argc, char** argv); int tool_main(int argc, char** argv) { @@ -349,289 +279,79 @@ int tool_main(int argc, char** argv) { gPrintInstCount = true; #endif SkAutoGraphics ag; + SkCommandLineFlags::Parse(argc, argv); - SkTDict<const char*> defineDict(1024); - int repeatDraw = 1; - - int forceAlpha = 0xFF; - bool forceAA = true; - bool forceFilter = false; - SkTriState::State forceDither = SkTriState::kDefault; + // First, parse some flags. - static const uint32_t kDefaultTimerTypes = TimerData::kCpu_Flag | TimerData::kGpu_Flag; - static const TimerData::Result kDefaultTimerResult = TimerData::kAvg_Result; - uint32_t timerTypes = kDefaultTimerTypes; - TimerData::Result timerResult = kDefaultTimerResult; + SkBenchLogger logger; + if (FLAGS_logFile.count()) { + logger.SetLogFile(FLAGS_logFile[0]); + } - bool doScale = false; - bool doRotate = false; - bool doClip = false; - bool hasStrokeWidth = false; + 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); + } + } -#if SK_SUPPORT_GPU - struct { - int fBytes; - int fCount; - } gpuCacheSize = { -1, -1 }; // -1s mean use the default -#endif + 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); + } + } - float strokeWidth; - SkTDArray<const char*> fMatches; - benchModes benchMode = kNormal_benchModes; - SkString perIterTimeformat("%.2f"); - SkString normalTimeFormat("%6.2f"); - - SkString outDir; - SkBitmap::Config outConfig = SkBitmap::kNo_Config; - const char* configName = ""; - Backend backend = kRaster_Backend; // for warning - int sampleCount = 0; SkTDArray<int> configs; - bool userConfig = false; - - SkBenchLogger logger; - - char* const* stop = argv + argc; - for (++argv; argv < stop; ++argv) { - if (strcmp(*argv, "-o") == 0) { - argv++; - if (argv < stop && **argv) { - outDir.set(*argv); - if (outDir.c_str()[outDir.size() - 1] != '/') { - outDir.append("/"); - } - } - } else if (strcmp(*argv, "--repeat") == 0) { - argv++; - if (argv < stop) { - repeatDraw = atoi(*argv); - if (repeatDraw < 1) { - repeatDraw = 1; - } - } else { - logger.logError("missing arg for --repeat\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--logPerIter") == 0) { - timerResult = TimerData::kPerIter_Result; - } else if (strcmp(*argv, "--timers") == 0) { - argv++; - if (argv < stop) { - timerTypes = 0; - for (char* t = *argv; *t; ++t) { - switch (*t) { - case 'w': timerTypes |= TimerData::kWall_Flag; break; - case 'c': timerTypes |= TimerData::kCpu_Flag; break; - case 'W': timerTypes |= TimerData::kTruncatedWall_Flag; break; - case 'C': timerTypes |= TimerData::kTruncatedCpu_Flag; break; - case 'g': timerTypes |= TimerData::kGpu_Flag; break; - } - } - } else { - logger.logError("missing arg for --timers\n"); - help(); - return -1; - } - } else if (!strcmp(*argv, "--rotate")) { - doRotate = true; - } else if (!strcmp(*argv, "--scale")) { - doScale = true; - } else if (!strcmp(*argv, "--clip")) { - doClip = true; - } else if (!strcmp(*argv, "--min")) { - timerResult = TimerData::kMin_Result; - } else if (strcmp(*argv, "--forceAA") == 0) { - if (!parse_bool_arg(++argv, stop, &forceAA)) { - logger.logError("missing arg for --forceAA\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--forceFilter") == 0) { - if (!parse_bool_arg(++argv, stop, &forceFilter)) { - logger.logError("missing arg for --forceFilter\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--forceDither") == 0) { - bool tmp; - if (!parse_bool_arg(++argv, stop, &tmp)) { - logger.logError("missing arg for --forceDither\n"); - help(); - return -1; - } - forceDither = tmp ? SkTriState::kTrue : SkTriState::kFalse; - } else if (strcmp(*argv, "--forceBlend") == 0) { - bool wantAlpha = false; - if (!parse_bool_arg(++argv, stop, &wantAlpha)) { - logger.logError("missing arg for --forceBlend\n"); - help(); - return -1; - } - forceAlpha = wantAlpha ? 0x80 : 0xFF; -#if SK_SUPPORT_GPU - } else if (strcmp(*argv, "--gpuCacheSize") == 0) { - if (stop - argv > 2) { - gpuCacheSize.fBytes = atoi(*++argv); - gpuCacheSize.fCount = atoi(*++argv); - } else { - SkDebugf("missing arg for --gpuCacheSize\n"); - help(); - return -1; - } -#endif - } else if (strcmp(*argv, "--mode") == 0) { - argv++; - if (argv < stop) { - if (strcmp(*argv, "normal") == 0) { - benchMode = kNormal_benchModes; - } else if (strcmp(*argv, "deferred") == 0) { - benchMode = kDeferred_benchModes; - } else if (strcmp(*argv, "deferredSilent") == 0) { - benchMode = kDeferredSilent_benchModes; - } else if (strcmp(*argv, "record") == 0) { - benchMode = kRecord_benchModes; - } else if (strcmp(*argv, "picturerecord") == 0) { - benchMode = kPictureRecord_benchModes; - } else { - logger.logError("bad arg for --mode\n"); - help(); - return -1; - } - } else { - logger.logError("missing arg for --mode\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--strokeWidth") == 0) { - argv++; - if (argv < stop) { - const char *strokeWidthStr = *argv; - if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) { - logger.logError("bad arg for --strokeWidth\n"); - help(); - return -1; - } - hasStrokeWidth = true; - } else { - logger.logError("missing arg for --strokeWidth\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--match") == 0) { - argv++; - while (argv < stop && (*argv)[0] != '-') { - *fMatches.append() = *argv++; - } - argv--; - if (!fMatches.count()) { - logger.logError("missing arg for --match\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--config") == 0) { - argv++; - if (argv < stop) { - int index = findConfig(*argv); - if (index >= 0) { - *configs.append() = index; - userConfig = true; - } else { - SkString str; - str.printf("unrecognized config %s\n", *argv); - logger.logError(str); - help(); - return -1; - } - } else { - logger.logError("missing arg for --config\n"); - help(); - return -1; - } - } else if (strcmp(*argv, "--logFile") == 0) { - argv++; - if (argv < stop) { - if (!logger.SetLogFile(*argv)) { - SkString str; - str.printf("Could not open %s for writing.", *argv); - logger.logError(str); - return -1; - } - } else { - logger.logError("missing arg for --logFile\n"); - help(); - return -1; - } - } else if (strlen(*argv) > 2 && strncmp(*argv, "-D", 2) == 0) { - argv++; - if (argv < stop) { - defineDict.set(argv[-1] + 2, *argv); - } else { - logger.logError("incomplete '-Dfoo bar' definition\n"); - help(); - return -1; + // Try user-given configs first. + for (int i = 0; i < FLAGS_config.count(); i++) { + for (size_t j = 0; j < SK_ARRAY_COUNT(gConfigs); j++) { + if (0 == strcmp(FLAGS_config[i], gConfigs[j].name)) { + *configs.append() = j; } - } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { - help(); - return 0; - } else { - SkString str; - str.printf("unrecognized arg %s\n", *argv); - logger.logError(str); - help(); - return -1; } } - if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes) - && !outDir.isEmpty()) { - logger.logError("'--mode record' and '--mode picturerecord' are not" - " compatible with -o.\n"); - return -1; - } - if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes)) { - perIterTimeformat.set("%.4f"); - normalTimeFormat.set("%6.4f"); - } - if (!userConfig) { - // if no config is specified by user, add the default configs - for (unsigned int i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { - if (gConfigs[i].fRunByDefault) { + // If there weren't any, fill in with defaults. + if (configs.count() == 0) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { + if (gConfigs[i].runByDefault) { *configs.append() = i; } } } - if (kNormal_benchModes != benchMode) { + // 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) { - int configIdx = configs[i]; - if (kNonRendering_Backend == gConfigs[configIdx].fBackend) { + const Config& config = gConfigs[configs[i]]; + if (kNonRendering_Backend == config.backend) { configs.remove(i, 1); --i; } } } - #if SK_SUPPORT_GPU for (int i = 0; i < configs.count(); ++i) { - int configIdx = configs[i]; + const Config& config = gConfigs[configs[i]]; - if (kGPU_Backend == gConfigs[configIdx].fBackend && gConfigs[configIdx].fSampleCnt > 0) { - GrContext* context = gContextFactory.get(gConfigs[configIdx].fContextType); + if (kGPU_Backend == config.backend) { + GrContext* context = gContextFactory.get(config.contextType); if (NULL == context) { SkString error; error.printf("Error creating GrContext for config %s. Config will be skipped.\n", - gConfigs[configIdx].fName); - logger.logError(error.c_str()); + config.name); + logger.logError(error); configs.remove(i); --i; continue; } - if (gConfigs[configIdx].fSampleCnt > context->getMaxSampleCount()){ + if (config.sampleCount > context->getMaxSampleCount()){ SkString error; error.printf("Sample count (%d) for config %s is unsupported. " "Config will be skipped.\n", - gConfigs[configIdx].fSampleCnt, gConfigs[configIdx].fName); - logger.logError(error.c_str()); + config.sampleCount, config.name); + logger.logError(error); configs.remove(i); --i; continue; @@ -640,334 +360,272 @@ int tool_main(int argc, char** argv) { } #endif - // report our current settings - { - SkString str; - const char* deferredMode = benchMode == kDeferred_benchModes ? "yes" : - (benchMode == kDeferredSilent_benchModes ? "silent" : "no"); - str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d " - "deferred=%s logperiter=%d", - forceAlpha, forceAA, forceFilter, deferredMode, - TimerData::kPerIter_Result == timerResult); - str.appendf(" rotate=%d scale=%d clip=%d min=%d", - doRotate, doScale, doClip, TimerData::kMin_Result == timerResult); - str.appendf(" record=%d picturerecord=%d", - benchMode == kRecord_benchModes, - benchMode == kPictureRecord_benchModes); - const char * ditherName; - switch (forceDither) { - case SkTriState::kDefault: ditherName = "default"; break; - case SkTriState::kTrue: ditherName = "true"; break; - case SkTriState::kFalse: ditherName = "false"; break; - default: ditherName = "<invalid>"; break; - } - str.appendf(" dither=%s", ditherName); - - if (hasStrokeWidth) { - str.appendf(" strokeWidth=%f", strokeWidth); - } else { - str.append(" strokeWidth=none"); - } - -#if defined(SK_SCALAR_IS_FLOAT) - str.append(" scalar=float"); -#elif defined(SK_SCALAR_IS_FIXED) - str.append(" scalar=fixed"); + // All flags should be parsed now. Report our settings. + if (kIsDebug) { + logger.logError("bench was built in Debug mode, so we're going to hide the times." + " It's for your own good!\n"); + } + SkString str("skia bench:"); + str.appendf(" mode=%s", FLAGS_mode[0]); + str.appendf(" alpha=0x%02X antialias=%d filter=%d dither=%s", + alpha, FLAGS_forceAA, FLAGS_forceFilter, SkTriState::Name[dither]); + str.appendf(" rotate=%d scale=%d clip=%d", FLAGS_rotate, FLAGS_scale, FLAGS_clip); + +#if defined(SK_SCALAR_IS_FIXED) + str.append(" scalar=fixed"); +#else + str.append(" scalar=float"); #endif #if defined(SK_BUILD_FOR_WIN32) - str.append(" system=WIN32"); + str.append(" system=WIN32"); #elif defined(SK_BUILD_FOR_MAC) - str.append(" system=MAC"); + str.append(" system=MAC"); #elif defined(SK_BUILD_FOR_ANDROID) - str.append(" system=ANDROID"); + str.append(" system=ANDROID"); #elif defined(SK_BUILD_FOR_UNIX) - str.append(" system=UNIX"); + str.append(" system=UNIX"); #else - str.append(" system=other"); + str.append(" system=other"); #endif #if defined(SK_DEBUG) - str.append(" DEBUG"); + str.append(" DEBUG"); #endif - str.append("\n"); - logger.logProgress(str); - } + str.append("\n"); + logger.logProgress(str); + - SkTArray<BenchTimer*> timers(SK_ARRAY_COUNT(gConfigs)); + // Set texture cache limits if non-default. for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { #if SK_SUPPORT_GPU - SkGLContextHelper* glCtx = NULL; - if (kGPU_Backend == gConfigs[i].fBackend) { - GrContext* context = gContextFactory.get(gConfigs[i].fContextType); - if (NULL != context) { - // Set the user specified cache limits if non-default. - size_t bytes; - int count; - context->getTextureCacheLimits(&count, &bytes); - if (-1 != gpuCacheSize.fBytes) { - bytes = static_cast<size_t>(gpuCacheSize.fBytes); - } - if (-1 != gpuCacheSize.fCount) { - count = gpuCacheSize.fCount; - } - context->setTextureCacheLimits(count, bytes); - } - glCtx = gContextFactory.getGLContext(gConfigs[i].fContextType); + const Config& config = gConfigs[i]; + if (kGPU_Backend != config.backend) { + continue; } - timers.push_back(SkNEW_ARGS(BenchTimer, (glCtx))); -#else - timers.push_back(SkNEW(BenchTimer)); + GrContext* context = gContextFactory.get(config.contextType); + if (NULL == context) { + continue; + } + + size_t bytes; + int count; + context->getTextureCacheLimits(&count, &bytes); + if (-1 != FLAGS_gpuCacheBytes) { + bytes = static_cast<size_t>(FLAGS_gpuCacheBytes); + } + if (-1 != FLAGS_gpuCacheCount) { + count = FLAGS_gpuCacheCount; + } + context->setTextureCacheLimits(count, bytes); #endif } - Iter iter(&defineDict); + // Find the longest name of the benches we're going to run to make the output pretty. + Iter names; SkBenchmark* bench; - while ((bench = iter.next()) != NULL) { + int longestName = 0; + while ((bench = names.next()) != NULL) { SkAutoTUnref<SkBenchmark> benchUnref(bench); - - SkIPoint dim = bench->getSize(); - if (dim.fX <= 0 || dim.fY <= 0) { + if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { continue; } + const int length = strlen(bench->getName()); + longestName = length > longestName ? length : longestName; + } - bench->setForceAlpha(forceAlpha); - bench->setForceAA(forceAA); - bench->setForceFilter(forceFilter); - bench->setDither(forceDither); - if (hasStrokeWidth) { - bench->setStrokeWidth(strokeWidth); - } - - // only run benchmarks if their name contains matchStr - if (SkCommandLineFlags::ShouldSkip(fMatches, bench->getName())) { + // Run each bench in each configuration it supports and we asked for. + Iter iter; + while ((bench = iter.next()) != NULL) { + SkAutoTUnref<SkBenchmark> benchUnref(bench); + if (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getName())) { continue; } - bool loggedBenchStart = false; - + bench->setForceAlpha(alpha); + bench->setForceAA(FLAGS_forceAA); + bench->setForceFilter(FLAGS_forceFilter); + bench->setDither(dither); AutoPrePostDraw appd(bench); - for (int x = 0; x < configs.count(); ++x) { - int configIndex = configs[x]; - - bool setupFailed = false; + bool loggedBenchName = false; + for (int i = 0; i < configs.count(); ++i) { + const int configIndex = configs[i]; + const Config& config = gConfigs[configIndex]; - if (kNonRendering_Backend == gConfigs[configIndex].fBackend) { - if (bench->isRendering()) { - continue; - } - } else { - if (!bench->isRendering()) { - continue; - } + if ((kNonRendering_Backend == config.backend) == bench->isRendering()) { + continue; } - outConfig = gConfigs[configIndex].fConfig; - configName = gConfigs[configIndex].fName; - backend = gConfigs[configIndex].fBackend; - sampleCount = gConfigs[configIndex].fSampleCnt; GrContext* context = NULL; - BenchTimer* timer = timers[configIndex]; - #if SK_SUPPORT_GPU SkGLContextHelper* glContext = NULL; - if (kGPU_Backend == backend) { - context = gContextFactory.get(gConfigs[configIndex].fContextType); + if (kGPU_Backend == config.backend) { + context = gContextFactory.get(config.contextType); if (NULL == context) { continue; } - glContext = gContextFactory.getGLContext(gConfigs[configIndex].fContextType); + glContext = gContextFactory.getGLContext(config.contextType); } #endif - SkBaseDevice* device = NULL; - SkCanvas* canvas = NULL; - SkPicture pictureRecordFrom; - SkPicture pictureRecordTo; - - if (kNonRendering_Backend != backend) { - device = make_device(outConfig, dim, backend, sampleCount, context); - if (NULL == device) { + SkAutoTUnref<SkBaseDevice> device; + SkAutoTUnref<SkCanvas> canvas; + SkPicture recordFrom, recordTo; + const SkIPoint dim = bench->getSize(); + + const SkPicture::RecordingFlags kRecordFlags = + SkPicture::kUsePathBoundsForClip_RecordingFlag; + + if (kNonRendering_Backend != config.backend) { + device.reset(make_device(config.config, + dim, + config.backend, + config.sampleCount, + context)); + if (!device.get()) { SkString error; - error.printf("Device creation failure for config %s. Will skip.\n", configName); - logger.logError(error.c_str()); - setupFailed = true; - } else { - switch(benchMode) { - case kDeferredSilent_benchModes: - case kDeferred_benchModes: - canvas = SkDeferredCanvas::Create(device); - break; - case kRecord_benchModes: - canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, - SkPicture::kUsePathBoundsForClip_RecordingFlag); - canvas->ref(); - break; - case kPictureRecord_benchModes: { - // This sets up picture-to-picture recording. - // The C++ drawing calls for the benchmark are recorded into - // pictureRecordFrom. As the benchmark, we will time how - // long it takes to playback pictureRecordFrom into - // pictureRecordTo. - SkCanvas* tempCanvas = pictureRecordFrom.beginRecording(dim.fX, dim.fY, - SkPicture::kUsePathBoundsForClip_RecordingFlag); - bench->draw(tempCanvas); - pictureRecordFrom.endRecording(); - canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, - SkPicture::kUsePathBoundsForClip_RecordingFlag); - canvas->ref(); - break; - } - case kNormal_benchModes: - canvas = new SkCanvas(device); - break; - default: - SkASSERT(0); - } - device->unref(); - canvas->clear(SK_ColorWHITE); - } - } - SkAutoUnref canvasUnref(canvas); - if (!setupFailed) { - if (NULL != canvas) { - if (doClip) { - performClip(canvas, dim.fX, dim.fY); - } - if (doScale) { - performScale(canvas, dim.fX, dim.fY); - } - if (doRotate) { - performRotate(canvas, dim.fX, dim.fY); - } + error.printf("Device creation failure for config %s. Will skip.\n", config.name); + logger.logError(error); + continue; } - if (!loggedBenchStart) { - loggedBenchStart = true; - SkString str; - str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, bench->getName()); - logger.logProgress(str); + switch(benchMode) { + case kDeferredSilent_BenchMode: + case kDeferred_BenchMode: + canvas.reset(SkDeferredCanvas::Create(device.get())); + break; + case kRecord_BenchMode: + canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags))); + break; + case kPictureRecord_BenchMode: + bench->draw(recordFrom.beginRecording(dim.fX, dim.fY, kRecordFlags)); + recordFrom.endRecording(); + canvas.reset(SkRef(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags))); + break; + case kNormal_BenchMode: + canvas.reset(new SkCanvas(device.get())); + break; + default: + SkASSERT(false); } + } - // warm up caches if needed - if (repeatDraw > 1 && NULL != canvas) { -#if SK_SUPPORT_GPU - // purge the GPU resources to reduce variance - if (NULL != context) { - context->freeGpuResources(); - } -#endif - SkAutoCanvasRestore acr(canvas, true); - if (benchMode == kPictureRecord_benchModes) { - pictureRecordFrom.draw(canvas); - } else { - bench->draw(canvas); - } - - if (kDeferredSilent_benchModes == benchMode) { - static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); - } else { - canvas->flush(); - } -#if SK_SUPPORT_GPU - if (NULL != context) { - context->flush(); - SK_GL(*glContext, Finish()); - } -#endif - } + if (NULL != canvas) { + canvas->clear(SK_ColorWHITE); + if (FLAGS_clip) { performClip(canvas, dim.fX, dim.fY); } + if (FLAGS_scale) { performScale(canvas, dim.fX, dim.fY); } + if (FLAGS_rotate) { performRotate(canvas, dim.fX, dim.fY); } + } + + if (!loggedBenchName) { + loggedBenchName = true; + SkString str; + str.printf("running bench [%3d %3d] %*s ", + dim.fX, dim.fY, longestName, bench->getName()); + logger.logProgress(str); + } - // record timer values for each repeat, and their sum - TimerData timerData(repeatDraw); - for (int i = 0; i < repeatDraw; i++) { - if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes)) { - // This will clear the recorded commands so that they do not - // accumulate. - canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, - SkPicture::kUsePathBoundsForClip_RecordingFlag); - } - - timer->start(bench->getDurationScale()); - if (NULL != canvas) { - canvas->save(); - } - if (benchMode == kPictureRecord_benchModes) { - pictureRecordFrom.draw(canvas); - } else { - bench->draw(canvas); - } - - if (kDeferredSilent_benchModes == benchMode) { - static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); - } else if (NULL != canvas) { - canvas->flush(); - } - - if (NULL != canvas) { - canvas->restore(); - } - - // stop the truncated timer after the last canvas call but - // don't wait for all the GL calls to complete - timer->truncatedEnd(); #if SK_SUPPORT_GPU - if (NULL != glContext) { - context->flush(); - SK_GL(*glContext, Finish()); - } + SkGLContextHelper* contextHelper = NULL; + if (kGPU_Backend == config.backend) { + contextHelper = gContextFactory.getGLContext(config.contextType); + } + BenchTimer timer(contextHelper); +#else + BenchTimer timer; #endif - // stop the inclusive and gpu timers once all the GL calls - // have completed - timer->end(); - SkAssertResult(timerData.appendTimes(timer)); + bench->setLoops(0); + do { + // Ramp up 1 -> 4 -> 16 -> ... -> ~1 billion. + const int loops = bench->getLoops(); + if (loops >= (1<<30)) { + // 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." + SkString str; + str.printf("Can't ramp %s to %dms.\n", bench->getName(), FLAGS_benchMs); + logger.logError(str); + break; + } + bench->setLoops(loops == 0 ? 1 : loops * 4); + + if ((benchMode == kRecord_BenchMode || benchMode == kPictureRecord_BenchMode)) { + // Clear the recorded commands so that they do not accumulate. + canvas.reset(recordTo.beginRecording(dim.fX, dim.fY, kRecordFlags)); + } + timer.start(); + if (NULL != canvas) { + canvas->save(); } - const char* timeFormat; - if (repeatDraw > 1 && TimerData::kPerIter_Result == timerResult) { - timeFormat = perIterTimeformat.c_str(); + if (benchMode == kPictureRecord_BenchMode) { + recordFrom.draw(canvas); } else { - timeFormat = normalTimeFormat.c_str(); + bench->draw(canvas); } - uint32_t filteredTimerTypes = timerTypes; - if (NULL == context) { - filteredTimerTypes &= ~TimerData::kGpu_Flag; + + if (kDeferredSilent_BenchMode == benchMode) { + static_cast<SkDeferredCanvas*>(canvas.get())->silentFlush(); + } else if (NULL != canvas) { + canvas->flush(); + } + + if (NULL != canvas) { + canvas->restore(); + } + + + // 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()); } - SkString result = timerData.getResult(timeFormat, - timerResult, - configName, - filteredTimerTypes); - logger.logProgress(result); - - if (outDir.size() > 0 && kNonRendering_Backend != backend) { - saveFile(bench->getName(), configName, outDir.c_str(), - device->accessBitmap(false)); +#endif + timer.end(); + } while (!kIsDebug && timer.fWall < FLAGS_benchMs); // One loop only in debug mode. + + if (FLAGS_outDir.count() && kNonRendering_Backend != config.backend) { + saveFile(bench->getName(), + config.name, + FLAGS_outDir[0], + device->accessBitmap(false)); + } + + if (kIsDebug) { + // Let's not mislead ourselves by looking at Debug build bench times! + continue; + } + + // Normalize to ms per 1000 iterations. + const double normalize = 1000.0 / bench->getLoops(); + 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}, + }; + + SkString result; + result.appendf(" %s:", 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) { + result.appendf(" %s = ", times[i].longName); + result.appendf(FLAGS_timeFormat[0], times[i].ms); } } + logger.logProgress(result); } - if (loggedBenchStart) { - logger.logProgress(SkString("\n")); + if (loggedBenchName) { + logger.logProgress("\n"); } } #if SK_SUPPORT_GPU -#if GR_CACHE_STATS - for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) { - GrContextFactory::GLContextType ctxType = (GrContextFactory::GLContextType)i; - GrContext* context = gContextFactory.get(ctxType); - if (NULL != context) { - SkDebugf("Cache Stats for %s context:\n", GrContextFactory::GLContextTypeName(ctxType)); - context->printCacheStats(); - SkDebugf("\n"); - } - } -#endif - // Destroy the GrContext before the inst tracking printing at main() exit occurs. gContextFactory.destroyContexts(); #endif - for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { - SkDELETE(timers[i]); - } - return 0; } |