1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include <ctype.h> 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "bench/nanobench.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#include "bench/AndroidCodecBench.h" 13cb93a386Sopenharmony_ci#include "bench/Benchmark.h" 14cb93a386Sopenharmony_ci#include "bench/CodecBench.h" 15cb93a386Sopenharmony_ci#include "bench/CodecBenchPriv.h" 16cb93a386Sopenharmony_ci#include "bench/GMBench.h" 17cb93a386Sopenharmony_ci#include "bench/MSKPBench.h" 18cb93a386Sopenharmony_ci#include "bench/RecordingBench.h" 19cb93a386Sopenharmony_ci#include "bench/ResultsWriter.h" 20cb93a386Sopenharmony_ci#include "bench/SKPAnimationBench.h" 21cb93a386Sopenharmony_ci#include "bench/SKPBench.h" 22cb93a386Sopenharmony_ci#include "bench/SkGlyphCacheBench.h" 23cb93a386Sopenharmony_ci#include "bench/SkSLBench.h" 24cb93a386Sopenharmony_ci#include "include/codec/SkAndroidCodec.h" 25cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h" 26cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 27cb93a386Sopenharmony_ci#include "include/core/SkData.h" 28cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h" 29cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 30cb93a386Sopenharmony_ci#include "include/core/SkString.h" 31cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 32cb93a386Sopenharmony_ci#include "include/core/SkTime.h" 33cb93a386Sopenharmony_ci#include "include/private/SkTOptional.h" 34cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 35cb93a386Sopenharmony_ci#include "src/core/SkColorSpacePriv.h" 36cb93a386Sopenharmony_ci#include "src/core/SkLeanWindows.h" 37cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h" 38cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h" 39cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 40cb93a386Sopenharmony_ci#include "src/gpu/GrShaderUtils.h" 41cb93a386Sopenharmony_ci#include "src/utils/SkJSONWriter.h" 42cb93a386Sopenharmony_ci#include "src/utils/SkOSPath.h" 43cb93a386Sopenharmony_ci#include "tools/AutoreleasePool.h" 44cb93a386Sopenharmony_ci#include "tools/CrashHandler.h" 45cb93a386Sopenharmony_ci#include "tools/MSKPPlayer.h" 46cb93a386Sopenharmony_ci#include "tools/ProcStats.h" 47cb93a386Sopenharmony_ci#include "tools/Stats.h" 48cb93a386Sopenharmony_ci#include "tools/flags/CommonFlags.h" 49cb93a386Sopenharmony_ci#include "tools/flags/CommonFlagsConfig.h" 50cb93a386Sopenharmony_ci#include "tools/ios_utils.h" 51cb93a386Sopenharmony_ci#include "tools/trace/EventTracingPriv.h" 52cb93a386Sopenharmony_ci#include "tools/trace/SkDebugfTracer.h" 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci#if defined(SK_ENABLE_SVG) 55cb93a386Sopenharmony_ci#include "modules/svg/include/SkSVGDOM.h" 56cb93a386Sopenharmony_ci#include "modules/svg/include/SkSVGNode.h" 57cb93a386Sopenharmony_ci#endif 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci#ifdef SK_ENABLE_ANDROID_UTILS 60cb93a386Sopenharmony_ci#include "bench/BitmapRegionDecoderBench.h" 61cb93a386Sopenharmony_ci#include "client_utils/android/BitmapRegionDecoder.h" 62cb93a386Sopenharmony_ci#endif 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci#include <cinttypes> 65cb93a386Sopenharmony_ci#include <stdlib.h> 66cb93a386Sopenharmony_ci#include <memory> 67cb93a386Sopenharmony_ci#include <thread> 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ciextern bool gSkForceRasterPipelineBlitter; 70cb93a386Sopenharmony_ciextern bool gForceHighPrecisionRasterPipeline; 71cb93a386Sopenharmony_ciextern bool gUseSkVMBlitter; 72cb93a386Sopenharmony_ciextern bool gSkVMAllowJIT; 73cb93a386Sopenharmony_ciextern bool gSkVMJITViaDylib; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci#ifndef SK_BUILD_FOR_WIN 76cb93a386Sopenharmony_ci #include <unistd.h> 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci#endif 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 81cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 82cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 83cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 84cb93a386Sopenharmony_ci#include "tools/gpu/GrContextFactory.h" 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ciusing sk_gpu_test::ContextInfo; 87cb93a386Sopenharmony_ciusing sk_gpu_test::GrContextFactory; 88cb93a386Sopenharmony_ciusing sk_gpu_test::TestContext; 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ciGrContextOptions grContextOpts; 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_cistatic const int kAutoTuneLoops = 0; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_cistatic SkString loops_help_txt() { 95cb93a386Sopenharmony_ci SkString help; 96cb93a386Sopenharmony_ci help.printf("Number of times to run each bench. Set this to %d to auto-" 97cb93a386Sopenharmony_ci "tune for each bench. Timings are only reported when auto-tuning.", 98cb93a386Sopenharmony_ci kAutoTuneLoops); 99cb93a386Sopenharmony_ci return help; 100cb93a386Sopenharmony_ci} 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_cistatic SkString to_string(int n) { 103cb93a386Sopenharmony_ci SkString str; 104cb93a386Sopenharmony_ci str.appendS32(n); 105cb93a386Sopenharmony_ci return str; 106cb93a386Sopenharmony_ci} 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_cistatic DEFINE_int(loops, kAutoTuneLoops, loops_help_txt().c_str()); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_cistatic DEFINE_int(samples, 10, "Number of samples to measure for each bench."); 111cb93a386Sopenharmony_cistatic DEFINE_int(ms, 0, "If >0, run each bench for this many ms instead of obeying --samples."); 112cb93a386Sopenharmony_cistatic DEFINE_int(overheadLoops, 100000, "Loops to estimate timer overhead."); 113cb93a386Sopenharmony_cistatic DEFINE_double(overheadGoal, 0.0001, 114cb93a386Sopenharmony_ci "Loop until timer overhead is at most this fraction of our measurments."); 115cb93a386Sopenharmony_cistatic DEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); 116cb93a386Sopenharmony_cistatic DEFINE_int(gpuFrameLag, 5, 117cb93a386Sopenharmony_ci "If unknown, estimated maximum number of frames GPU allows to lag."); 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_cistatic DEFINE_string(outResultsFile, "", "If given, write results here as JSON."); 120cb93a386Sopenharmony_cistatic DEFINE_int(maxCalibrationAttempts, 3, 121cb93a386Sopenharmony_ci "Try up to this many times to guess loops for a bench, or skip the bench."); 122cb93a386Sopenharmony_cistatic DEFINE_int(maxLoops, 1000000, "Never run a bench more times than this."); 123cb93a386Sopenharmony_cistatic DEFINE_string(clip, "0,0,1000,1000", "Clip for SKPs."); 124cb93a386Sopenharmony_cistatic DEFINE_string(scales, "1.0", "Space-separated scales for SKPs."); 125cb93a386Sopenharmony_cistatic DEFINE_string(zoom, "1.0,0", 126cb93a386Sopenharmony_ci "Comma-separated zoomMax,zoomPeriodMs factors for a periodic SKP zoom " 127cb93a386Sopenharmony_ci "function that ping-pongs between 1.0 and zoomMax."); 128cb93a386Sopenharmony_cistatic DEFINE_bool(bbh, true, "Build a BBH for SKPs?"); 129cb93a386Sopenharmony_cistatic DEFINE_bool(loopSKP, true, "Loop SKPs like we do for micro benches?"); 130cb93a386Sopenharmony_cistatic DEFINE_int(flushEvery, 10, "Flush --outResultsFile every Nth run."); 131cb93a386Sopenharmony_cistatic DEFINE_bool(gpuStats, false, "Print GPU stats after each gpu benchmark?"); 132cb93a386Sopenharmony_cistatic DEFINE_bool(gpuStatsDump, false, "Dump GPU stats after each benchmark to json"); 133cb93a386Sopenharmony_cistatic DEFINE_bool(dmsaaStatsDump, false, "Dump DMSAA stats after each benchmark to json"); 134cb93a386Sopenharmony_cistatic DEFINE_bool(keepAlive, false, "Print a message every so often so that we don't time out"); 135cb93a386Sopenharmony_cistatic DEFINE_bool(csv, false, "Print status in CSV format"); 136cb93a386Sopenharmony_cistatic DEFINE_string(sourceType, "", 137cb93a386Sopenharmony_ci "Apply usual --match rules to source type: bench, gm, skp, image, etc."); 138cb93a386Sopenharmony_cistatic DEFINE_string(benchType, "", 139cb93a386Sopenharmony_ci "Apply usual --match rules to bench type: micro, recording, " 140cb93a386Sopenharmony_ci "piping, playback, skcodec, etc."); 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_cistatic DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter"); 143cb93a386Sopenharmony_cistatic DEFINE_bool(forceRasterPipelineHP, false, "sets gSkForceRasterPipelineBlitter and gForceHighPrecisionRasterPipeline"); 144cb93a386Sopenharmony_cistatic DEFINE_bool(skvm, false, "sets gUseSkVMBlitter"); 145cb93a386Sopenharmony_cistatic DEFINE_bool(jit, true, "JIT SkVM?"); 146cb93a386Sopenharmony_cistatic DEFINE_bool(dylib, false, "JIT via dylib (much slower compile but easier to debug/profile)"); 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_cistatic DEFINE_bool2(pre_log, p, false, 149cb93a386Sopenharmony_ci "Log before running each test. May be incomprehensible when threading"); 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_cistatic DEFINE_bool(cpu, true, "Run CPU-bound work?"); 152cb93a386Sopenharmony_cistatic DEFINE_bool(gpu, true, "Run GPU-bound work?"); 153cb93a386Sopenharmony_cistatic DEFINE_bool(dryRun, false, 154cb93a386Sopenharmony_ci "just print the tests that would be run, without actually running them."); 155cb93a386Sopenharmony_cistatic DEFINE_string(images, "", 156cb93a386Sopenharmony_ci "List of images and/or directories to decode. A directory with no images" 157cb93a386Sopenharmony_ci " is treated as a fatal error."); 158cb93a386Sopenharmony_cistatic DEFINE_bool(simpleCodec, false, 159cb93a386Sopenharmony_ci "Runs of a subset of the codec tests, always N32, Premul or Opaque"); 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_cistatic DEFINE_string2(match, m, nullptr, 162cb93a386Sopenharmony_ci "[~][^]substring[$] [...] of name to run.\n" 163cb93a386Sopenharmony_ci "Multiple matches may be separated by spaces.\n" 164cb93a386Sopenharmony_ci "~ causes a matching name to always be skipped\n" 165cb93a386Sopenharmony_ci "^ requires the start of the name to match\n" 166cb93a386Sopenharmony_ci "$ requires the end of the name to match\n" 167cb93a386Sopenharmony_ci "^ and $ requires an exact match\n" 168cb93a386Sopenharmony_ci "If a name does not match any list entry,\n" 169cb93a386Sopenharmony_ci "it is skipped unless some list entry starts with ~"); 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_cistatic DEFINE_bool2(quiet, q, false, "if true, don't print status updates."); 172cb93a386Sopenharmony_cistatic DEFINE_bool2(verbose, v, false, "enable verbose output from the test driver."); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_cistatic DEFINE_string(skps, "skps", "Directory to read skps from."); 176cb93a386Sopenharmony_cistatic DEFINE_string(mskps, "mskps", "Directory to read mskps from."); 177cb93a386Sopenharmony_cistatic DEFINE_string(svgs, "", "Directory to read SVGs from, or a single SVG file."); 178cb93a386Sopenharmony_cistatic DEFINE_string(texttraces, "", "Directory to read TextBlobTrace files from."); 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_cistatic DEFINE_int_2(threads, j, -1, 181cb93a386Sopenharmony_ci "Run threadsafe tests on a threadpool with this many extra threads, " 182cb93a386Sopenharmony_ci "defaulting to one extra thread per core."); 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_cistatic DEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs."); 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_cistatic DEFINE_string(key, "", 187cb93a386Sopenharmony_ci "Space-separated key/value pairs to add to JSON identifying this builder."); 188cb93a386Sopenharmony_cistatic DEFINE_string(properties, "", 189cb93a386Sopenharmony_ci "Space-separated key/value pairs to add to JSON identifying this run."); 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_cistatic DEFINE_bool(purgeBetweenBenches, false, 192cb93a386Sopenharmony_ci "Call SkGraphics::PurgeAllCaches() between each benchmark?"); 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_cistatic double now_ms() { return SkTime::GetNSecs() * 1e-6; } 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_cistatic SkString humanize(double ms) { 197cb93a386Sopenharmony_ci if (FLAGS_verbose) return SkStringPrintf("%" PRIu64, (uint64_t)(ms*1e6)); 198cb93a386Sopenharmony_ci return HumanizeMs(ms); 199cb93a386Sopenharmony_ci} 200cb93a386Sopenharmony_ci#define HUMANIZE(ms) humanize(ms).c_str() 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_cibool Target::init(SkImageInfo info, Benchmark* bench) { 203cb93a386Sopenharmony_ci if (Benchmark::kRaster_Backend == config.backend) { 204cb93a386Sopenharmony_ci this->surface = SkSurface::MakeRaster(info); 205cb93a386Sopenharmony_ci if (!this->surface) { 206cb93a386Sopenharmony_ci return false; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci return true; 210cb93a386Sopenharmony_ci} 211cb93a386Sopenharmony_cibool Target::capturePixels(SkBitmap* bmp) { 212cb93a386Sopenharmony_ci SkCanvas* canvas = this->getCanvas(); 213cb93a386Sopenharmony_ci if (!canvas) { 214cb93a386Sopenharmony_ci return false; 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci bmp->allocPixels(canvas->imageInfo()); 217cb93a386Sopenharmony_ci if (!canvas->readPixels(*bmp, 0, 0)) { 218cb93a386Sopenharmony_ci SkDebugf("Can't read canvas pixels.\n"); 219cb93a386Sopenharmony_ci return false; 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci return true; 222cb93a386Sopenharmony_ci} 223cb93a386Sopenharmony_ci 224cb93a386Sopenharmony_cistruct GPUTarget : public Target { 225cb93a386Sopenharmony_ci explicit GPUTarget(const Config& c) : Target(c) {} 226cb93a386Sopenharmony_ci ContextInfo contextInfo; 227cb93a386Sopenharmony_ci std::unique_ptr<GrContextFactory> factory; 228cb93a386Sopenharmony_ci 229cb93a386Sopenharmony_ci ~GPUTarget() override { 230cb93a386Sopenharmony_ci // For Vulkan we need to release all our refs to the GrContext before destroy the vulkan 231cb93a386Sopenharmony_ci // context which happens at the end of this destructor. Thus we need to release the surface 232cb93a386Sopenharmony_ci // here which holds a ref to the GrContext. 233cb93a386Sopenharmony_ci surface.reset(); 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci void setup() override { 237cb93a386Sopenharmony_ci this->contextInfo.testContext()->makeCurrent(); 238cb93a386Sopenharmony_ci // Make sure we're done with whatever came before. 239cb93a386Sopenharmony_ci this->contextInfo.testContext()->finish(); 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci void endTiming() override { 242cb93a386Sopenharmony_ci if (this->contextInfo.testContext()) { 243cb93a386Sopenharmony_ci this->contextInfo.testContext()->flushAndWaitOnSync(contextInfo.directContext()); 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci void fence() override { this->contextInfo.testContext()->finish(); } 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci bool needsFrameTiming(int* maxFrameLag) const override { 249cb93a386Sopenharmony_ci if (!this->contextInfo.testContext()->getMaxGpuFrameLag(maxFrameLag)) { 250cb93a386Sopenharmony_ci // Frame lag is unknown. 251cb93a386Sopenharmony_ci *maxFrameLag = FLAGS_gpuFrameLag; 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci return true; 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci bool init(SkImageInfo info, Benchmark* bench) override { 256cb93a386Sopenharmony_ci GrContextOptions options = grContextOpts; 257cb93a386Sopenharmony_ci bench->modifyGrContextOptions(&options); 258cb93a386Sopenharmony_ci this->factory = std::make_unique<GrContextFactory>(options); 259cb93a386Sopenharmony_ci SkSurfaceProps props(this->config.surfaceFlags, kRGB_H_SkPixelGeometry); 260cb93a386Sopenharmony_ci this->surface = SkSurface::MakeRenderTarget( 261cb93a386Sopenharmony_ci this->factory->get(this->config.ctxType, this->config.ctxOverrides), 262cb93a386Sopenharmony_ci SkBudgeted::kNo, info, this->config.samples, &props); 263cb93a386Sopenharmony_ci this->contextInfo = 264cb93a386Sopenharmony_ci this->factory->getContextInfo(this->config.ctxType, this->config.ctxOverrides); 265cb93a386Sopenharmony_ci if (!this->surface) { 266cb93a386Sopenharmony_ci return false; 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci if (!this->contextInfo.testContext()->fenceSyncSupport()) { 269cb93a386Sopenharmony_ci SkDebugf("WARNING: GL context for config \"%s\" does not support fence sync. " 270cb93a386Sopenharmony_ci "Timings might not be accurate.\n", this->config.name.c_str()); 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci return true; 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci void dumpStats() override { 276cb93a386Sopenharmony_ci auto context = this->contextInfo.directContext(); 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci context->priv().printCacheStats(); 279cb93a386Sopenharmony_ci context->priv().printGpuStats(); 280cb93a386Sopenharmony_ci context->priv().printContextStats(); 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci}; 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_cistatic double time(int loops, Benchmark* bench, Target* target) { 285cb93a386Sopenharmony_ci SkCanvas* canvas = target->getCanvas(); 286cb93a386Sopenharmony_ci if (canvas) { 287cb93a386Sopenharmony_ci canvas->clear(SK_ColorWHITE); 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci bench->preDraw(canvas); 290cb93a386Sopenharmony_ci double start = now_ms(); 291cb93a386Sopenharmony_ci canvas = target->beginTiming(canvas); 292cb93a386Sopenharmony_ci bench->draw(loops, canvas); 293cb93a386Sopenharmony_ci target->endTiming(); 294cb93a386Sopenharmony_ci double elapsed = now_ms() - start; 295cb93a386Sopenharmony_ci bench->postDraw(canvas); 296cb93a386Sopenharmony_ci return elapsed; 297cb93a386Sopenharmony_ci} 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_cistatic double estimate_timer_overhead() { 300cb93a386Sopenharmony_ci double overhead = 0; 301cb93a386Sopenharmony_ci for (int i = 0; i < FLAGS_overheadLoops; i++) { 302cb93a386Sopenharmony_ci double start = now_ms(); 303cb93a386Sopenharmony_ci overhead += now_ms() - start; 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci return overhead / FLAGS_overheadLoops; 306cb93a386Sopenharmony_ci} 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_cistatic int detect_forever_loops(int loops) { 309cb93a386Sopenharmony_ci // look for a magic run-forever value 310cb93a386Sopenharmony_ci if (loops < 0) { 311cb93a386Sopenharmony_ci loops = SK_MaxS32; 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci return loops; 314cb93a386Sopenharmony_ci} 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_cistatic int clamp_loops(int loops) { 317cb93a386Sopenharmony_ci if (loops < 1) { 318cb93a386Sopenharmony_ci SkDebugf("ERROR: clamping loops from %d to 1. " 319cb93a386Sopenharmony_ci "There's probably something wrong with the bench.\n", loops); 320cb93a386Sopenharmony_ci return 1; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci if (loops > FLAGS_maxLoops) { 323cb93a386Sopenharmony_ci SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops); 324cb93a386Sopenharmony_ci return FLAGS_maxLoops; 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci return loops; 327cb93a386Sopenharmony_ci} 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_cistatic bool write_canvas_png(Target* target, const SkString& filename) { 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci if (filename.isEmpty()) { 332cb93a386Sopenharmony_ci return false; 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci if (target->getCanvas() && 335cb93a386Sopenharmony_ci kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) { 336cb93a386Sopenharmony_ci return false; 337cb93a386Sopenharmony_ci } 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_ci SkBitmap bmp; 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci if (!target->capturePixels(&bmp)) { 342cb93a386Sopenharmony_ci return false; 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci SkString dir = SkOSPath::Dirname(filename.c_str()); 346cb93a386Sopenharmony_ci if (!sk_mkdir(dir.c_str())) { 347cb93a386Sopenharmony_ci SkDebugf("Can't make dir %s.\n", dir.c_str()); 348cb93a386Sopenharmony_ci return false; 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci SkFILEWStream stream(filename.c_str()); 351cb93a386Sopenharmony_ci if (!stream.isValid()) { 352cb93a386Sopenharmony_ci SkDebugf("Can't write %s.\n", filename.c_str()); 353cb93a386Sopenharmony_ci return false; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci if (!SkEncodeImage(&stream, bmp, SkEncodedImageFormat::kPNG, 100)) { 356cb93a386Sopenharmony_ci SkDebugf("Can't encode a PNG.\n"); 357cb93a386Sopenharmony_ci return false; 358cb93a386Sopenharmony_ci } 359cb93a386Sopenharmony_ci return true; 360cb93a386Sopenharmony_ci} 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_cistatic int kFailedLoops = -2; 363cb93a386Sopenharmony_cistatic int setup_cpu_bench(const double overhead, Target* target, Benchmark* bench) { 364cb93a386Sopenharmony_ci // First figure out approximately how many loops of bench it takes to make overhead negligible. 365cb93a386Sopenharmony_ci double bench_plus_overhead = 0.0; 366cb93a386Sopenharmony_ci int round = 0; 367cb93a386Sopenharmony_ci int loops = bench->calculateLoops(FLAGS_loops); 368cb93a386Sopenharmony_ci if (kAutoTuneLoops == loops) { 369cb93a386Sopenharmony_ci while (bench_plus_overhead < overhead) { 370cb93a386Sopenharmony_ci if (round++ == FLAGS_maxCalibrationAttempts) { 371cb93a386Sopenharmony_ci SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n", 372cb93a386Sopenharmony_ci bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead)); 373cb93a386Sopenharmony_ci return kFailedLoops; 374cb93a386Sopenharmony_ci } 375cb93a386Sopenharmony_ci bench_plus_overhead = time(1, bench, target); 376cb93a386Sopenharmony_ci } 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci // Later we'll just start and stop the timer once but loop N times. 380cb93a386Sopenharmony_ci // We'll pick N to make timer overhead negligible: 381cb93a386Sopenharmony_ci // 382cb93a386Sopenharmony_ci // overhead 383cb93a386Sopenharmony_ci // ------------------------- < FLAGS_overheadGoal 384cb93a386Sopenharmony_ci // overhead + N * Bench Time 385cb93a386Sopenharmony_ci // 386cb93a386Sopenharmony_ci // where bench_plus_overhead ~=~ overhead + Bench Time. 387cb93a386Sopenharmony_ci // 388cb93a386Sopenharmony_ci // Doing some math, we get: 389cb93a386Sopenharmony_ci // 390cb93a386Sopenharmony_ci // (overhead / FLAGS_overheadGoal) - overhead 391cb93a386Sopenharmony_ci // ------------------------------------------ < N 392cb93a386Sopenharmony_ci // bench_plus_overhead - overhead) 393cb93a386Sopenharmony_ci // 394cb93a386Sopenharmony_ci // Luckily, this also works well in practice. :) 395cb93a386Sopenharmony_ci if (kAutoTuneLoops == loops) { 396cb93a386Sopenharmony_ci const double numer = overhead / FLAGS_overheadGoal - overhead; 397cb93a386Sopenharmony_ci const double denom = bench_plus_overhead - overhead; 398cb93a386Sopenharmony_ci loops = (int)ceil(numer / denom); 399cb93a386Sopenharmony_ci loops = clamp_loops(loops); 400cb93a386Sopenharmony_ci } else { 401cb93a386Sopenharmony_ci loops = detect_forever_loops(loops); 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci return loops; 405cb93a386Sopenharmony_ci} 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_cistatic int setup_gpu_bench(Target* target, Benchmark* bench, int maxGpuFrameLag) { 408cb93a386Sopenharmony_ci // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs. 409cb93a386Sopenharmony_ci int loops = bench->calculateLoops(FLAGS_loops); 410cb93a386Sopenharmony_ci if (kAutoTuneLoops == loops) { 411cb93a386Sopenharmony_ci loops = 1; 412cb93a386Sopenharmony_ci double elapsed = 0; 413cb93a386Sopenharmony_ci do { 414cb93a386Sopenharmony_ci if (1<<30 == loops) { 415cb93a386Sopenharmony_ci // We're about to wrap. Something's wrong with the bench. 416cb93a386Sopenharmony_ci loops = 0; 417cb93a386Sopenharmony_ci break; 418cb93a386Sopenharmony_ci } 419cb93a386Sopenharmony_ci loops *= 2; 420cb93a386Sopenharmony_ci // If the GPU lets frames lag at all, we need to make sure we're timing 421cb93a386Sopenharmony_ci // _this_ round, not still timing last round. 422cb93a386Sopenharmony_ci for (int i = 0; i < maxGpuFrameLag; i++) { 423cb93a386Sopenharmony_ci elapsed = time(loops, bench, target); 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci } while (elapsed < FLAGS_gpuMs); 426cb93a386Sopenharmony_ci 427cb93a386Sopenharmony_ci // We've overshot at least a little. Scale back linearly. 428cb93a386Sopenharmony_ci loops = (int)ceil(loops * FLAGS_gpuMs / elapsed); 429cb93a386Sopenharmony_ci loops = clamp_loops(loops); 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci // Make sure we're not still timing our calibration. 432cb93a386Sopenharmony_ci target->fence(); 433cb93a386Sopenharmony_ci } else { 434cb93a386Sopenharmony_ci loops = detect_forever_loops(loops); 435cb93a386Sopenharmony_ci } 436cb93a386Sopenharmony_ci // Pretty much the same deal as the calibration: do some warmup to make 437cb93a386Sopenharmony_ci // sure we're timing steady-state pipelined frames. 438cb93a386Sopenharmony_ci for (int i = 0; i < maxGpuFrameLag; i++) { 439cb93a386Sopenharmony_ci time(loops, bench, target); 440cb93a386Sopenharmony_ci } 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci return loops; 443cb93a386Sopenharmony_ci} 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_ci#define kBogusContextType GrContextFactory::kGL_ContextType 446cb93a386Sopenharmony_ci#define kBogusContextOverrides GrContextFactory::ContextOverrides::kNone 447cb93a386Sopenharmony_ci 448cb93a386Sopenharmony_cistatic skstd::optional<Config> create_config(const SkCommandLineConfig* config) { 449cb93a386Sopenharmony_ci if (const auto* gpuConfig = config->asConfigGpu()) { 450cb93a386Sopenharmony_ci if (!FLAGS_gpu) { 451cb93a386Sopenharmony_ci SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str()); 452cb93a386Sopenharmony_ci return skstd::nullopt; 453cb93a386Sopenharmony_ci } 454cb93a386Sopenharmony_ci 455cb93a386Sopenharmony_ci const auto ctxType = gpuConfig->getContextType(); 456cb93a386Sopenharmony_ci const auto ctxOverrides = gpuConfig->getContextOverrides(); 457cb93a386Sopenharmony_ci const auto sampleCount = gpuConfig->getSamples(); 458cb93a386Sopenharmony_ci const auto colorType = gpuConfig->getColorType(); 459cb93a386Sopenharmony_ci if (gpuConfig->getSurfType() != SkCommandLineConfigGpu::SurfType::kDefault) { 460cb93a386Sopenharmony_ci SkDebugf("This tool only supports the default surface type."); 461cb93a386Sopenharmony_ci return skstd::nullopt; 462cb93a386Sopenharmony_ci } 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ci GrContextFactory factory(grContextOpts); 465cb93a386Sopenharmony_ci if (const auto ctx = factory.get(ctxType, ctxOverrides)) { 466cb93a386Sopenharmony_ci GrBackendFormat format = ctx->defaultBackendFormat(colorType, GrRenderable::kYes); 467cb93a386Sopenharmony_ci int supportedSampleCount = 468cb93a386Sopenharmony_ci ctx->priv().caps()->getRenderTargetSampleCount(sampleCount, format); 469cb93a386Sopenharmony_ci if (sampleCount != supportedSampleCount) { 470cb93a386Sopenharmony_ci SkDebugf("Configuration '%s' sample count %d is not a supported sample count.\n", 471cb93a386Sopenharmony_ci config->getTag().c_str(), 472cb93a386Sopenharmony_ci sampleCount); 473cb93a386Sopenharmony_ci return skstd::nullopt; 474cb93a386Sopenharmony_ci } 475cb93a386Sopenharmony_ci } else { 476cb93a386Sopenharmony_ci SkDebugf("No context was available matching config '%s'.\n", config->getTag().c_str()); 477cb93a386Sopenharmony_ci return skstd::nullopt; 478cb93a386Sopenharmony_ci } 479cb93a386Sopenharmony_ci 480cb93a386Sopenharmony_ci return Config{gpuConfig->getTag(), 481cb93a386Sopenharmony_ci Benchmark::kGPU_Backend, 482cb93a386Sopenharmony_ci colorType, 483cb93a386Sopenharmony_ci kPremul_SkAlphaType, 484cb93a386Sopenharmony_ci config->refColorSpace(), 485cb93a386Sopenharmony_ci sampleCount, 486cb93a386Sopenharmony_ci ctxType, 487cb93a386Sopenharmony_ci ctxOverrides, 488cb93a386Sopenharmony_ci gpuConfig->getSurfaceFlags()}; 489cb93a386Sopenharmony_ci } 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_ci#define CPU_CONFIG(name, backend, color, alpha) \ 492cb93a386Sopenharmony_ci if (config->getBackend().equals(name)) { \ 493cb93a386Sopenharmony_ci if (!FLAGS_cpu) { \ 494cb93a386Sopenharmony_ci SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str()); \ 495cb93a386Sopenharmony_ci return skstd::nullopt; \ 496cb93a386Sopenharmony_ci } \ 497cb93a386Sopenharmony_ci return Config{SkString(name), \ 498cb93a386Sopenharmony_ci Benchmark::backend, \ 499cb93a386Sopenharmony_ci color, \ 500cb93a386Sopenharmony_ci alpha, \ 501cb93a386Sopenharmony_ci config->refColorSpace(), \ 502cb93a386Sopenharmony_ci 0, \ 503cb93a386Sopenharmony_ci kBogusContextType, \ 504cb93a386Sopenharmony_ci kBogusContextOverrides, \ 505cb93a386Sopenharmony_ci 0}; \ 506cb93a386Sopenharmony_ci } 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci CPU_CONFIG("nonrendering", kNonRendering_Backend, kUnknown_SkColorType, kUnpremul_SkAlphaType) 509cb93a386Sopenharmony_ci 510cb93a386Sopenharmony_ci CPU_CONFIG("a8", kRaster_Backend, kAlpha_8_SkColorType, kPremul_SkAlphaType) 511cb93a386Sopenharmony_ci CPU_CONFIG("565", kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType) 512cb93a386Sopenharmony_ci CPU_CONFIG("8888", kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType) 513cb93a386Sopenharmony_ci CPU_CONFIG("rgba", kRaster_Backend, kRGBA_8888_SkColorType, kPremul_SkAlphaType) 514cb93a386Sopenharmony_ci CPU_CONFIG("bgra", kRaster_Backend, kBGRA_8888_SkColorType, kPremul_SkAlphaType) 515cb93a386Sopenharmony_ci CPU_CONFIG("f16", kRaster_Backend, kRGBA_F16_SkColorType, kPremul_SkAlphaType) 516cb93a386Sopenharmony_ci CPU_CONFIG("srgba", kRaster_Backend, kSRGBA_8888_SkColorType, kPremul_SkAlphaType) 517cb93a386Sopenharmony_ci 518cb93a386Sopenharmony_ci#undef CPU_CONFIG 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci SkDebugf("Unknown config '%s'.\n", config->getTag().c_str()); 521cb93a386Sopenharmony_ci return skstd::nullopt; 522cb93a386Sopenharmony_ci} 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ci// Append all configs that are enabled and supported. 525cb93a386Sopenharmony_civoid create_configs(SkTArray<Config>* configs) { 526cb93a386Sopenharmony_ci SkCommandLineConfigArray array; 527cb93a386Sopenharmony_ci ParseConfigs(FLAGS_config, &array); 528cb93a386Sopenharmony_ci for (int i = 0; i < array.count(); ++i) { 529cb93a386Sopenharmony_ci if (skstd::optional<Config> config = create_config(array[i].get())) { 530cb93a386Sopenharmony_ci configs->push_back(*config); 531cb93a386Sopenharmony_ci } 532cb93a386Sopenharmony_ci } 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci // If no just default configs were requested, then we're okay. 535cb93a386Sopenharmony_ci if (array.count() == 0 || FLAGS_config.count() == 0 || 536cb93a386Sopenharmony_ci // Otherwise, make sure that all specified configs have been created. 537cb93a386Sopenharmony_ci array.count() == configs->count()) { 538cb93a386Sopenharmony_ci return; 539cb93a386Sopenharmony_ci } 540cb93a386Sopenharmony_ci exit(1); 541cb93a386Sopenharmony_ci} 542cb93a386Sopenharmony_ci 543cb93a386Sopenharmony_ci// disable warning : switch statement contains default but no 'case' labels 544cb93a386Sopenharmony_ci#if defined _WIN32 545cb93a386Sopenharmony_ci#pragma warning ( push ) 546cb93a386Sopenharmony_ci#pragma warning ( disable : 4065 ) 547cb93a386Sopenharmony_ci#endif 548cb93a386Sopenharmony_ci 549cb93a386Sopenharmony_ci// If bench is enabled for config, returns a Target* for it, otherwise nullptr. 550cb93a386Sopenharmony_cistatic Target* is_enabled(Benchmark* bench, const Config& config) { 551cb93a386Sopenharmony_ci if (!bench->isSuitableFor(config.backend)) { 552cb93a386Sopenharmony_ci return nullptr; 553cb93a386Sopenharmony_ci } 554cb93a386Sopenharmony_ci 555cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::Make(bench->getSize().fX, bench->getSize().fY, 556cb93a386Sopenharmony_ci config.color, config.alpha, config.colorSpace); 557cb93a386Sopenharmony_ci 558cb93a386Sopenharmony_ci Target* target = nullptr; 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci switch (config.backend) { 561cb93a386Sopenharmony_ci case Benchmark::kGPU_Backend: 562cb93a386Sopenharmony_ci target = new GPUTarget(config); 563cb93a386Sopenharmony_ci break; 564cb93a386Sopenharmony_ci default: 565cb93a386Sopenharmony_ci target = new Target(config); 566cb93a386Sopenharmony_ci break; 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci if (!target->init(info, bench)) { 570cb93a386Sopenharmony_ci delete target; 571cb93a386Sopenharmony_ci return nullptr; 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci return target; 574cb93a386Sopenharmony_ci} 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ci#if defined _WIN32 577cb93a386Sopenharmony_ci#pragma warning ( pop ) 578cb93a386Sopenharmony_ci#endif 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci#ifdef SK_ENABLE_ANDROID_UTILS 581cb93a386Sopenharmony_cistatic bool valid_brd_bench(sk_sp<SkData> encoded, SkColorType colorType, uint32_t sampleSize, 582cb93a386Sopenharmony_ci uint32_t minOutputSize, int* width, int* height) { 583cb93a386Sopenharmony_ci auto brd = android::skia::BitmapRegionDecoder::Make(encoded); 584cb93a386Sopenharmony_ci if (nullptr == brd) { 585cb93a386Sopenharmony_ci // This is indicates that subset decoding is not supported for a particular image format. 586cb93a386Sopenharmony_ci return false; 587cb93a386Sopenharmony_ci } 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ci if (sampleSize * minOutputSize > (uint32_t) brd->width() || sampleSize * minOutputSize > 590cb93a386Sopenharmony_ci (uint32_t) brd->height()) { 591cb93a386Sopenharmony_ci // This indicates that the image is not large enough to decode a 592cb93a386Sopenharmony_ci // minOutputSize x minOutputSize subset at the given sampleSize. 593cb93a386Sopenharmony_ci return false; 594cb93a386Sopenharmony_ci } 595cb93a386Sopenharmony_ci 596cb93a386Sopenharmony_ci // Set the image width and height. The calling code will use this to choose subsets to decode. 597cb93a386Sopenharmony_ci *width = brd->width(); 598cb93a386Sopenharmony_ci *height = brd->height(); 599cb93a386Sopenharmony_ci return true; 600cb93a386Sopenharmony_ci} 601cb93a386Sopenharmony_ci#endif 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_cistatic void cleanup_run(Target* target) { 604cb93a386Sopenharmony_ci delete target; 605cb93a386Sopenharmony_ci} 606cb93a386Sopenharmony_ci 607cb93a386Sopenharmony_cistatic void collect_files(const CommandLineFlags::StringArray& paths, 608cb93a386Sopenharmony_ci const char* ext, 609cb93a386Sopenharmony_ci SkTArray<SkString>* list) { 610cb93a386Sopenharmony_ci for (int i = 0; i < paths.count(); ++i) { 611cb93a386Sopenharmony_ci if (SkStrEndsWith(paths[i], ext)) { 612cb93a386Sopenharmony_ci list->push_back(SkString(paths[i])); 613cb93a386Sopenharmony_ci } else { 614cb93a386Sopenharmony_ci SkOSFile::Iter it(paths[i], ext); 615cb93a386Sopenharmony_ci SkString path; 616cb93a386Sopenharmony_ci while (it.next(&path)) { 617cb93a386Sopenharmony_ci list->push_back(SkOSPath::Join(paths[i], path.c_str())); 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci } 620cb93a386Sopenharmony_ci } 621cb93a386Sopenharmony_ci} 622cb93a386Sopenharmony_ci 623cb93a386Sopenharmony_ciclass BenchmarkStream { 624cb93a386Sopenharmony_cipublic: 625cb93a386Sopenharmony_ci BenchmarkStream() : fBenches(BenchRegistry::Head()) 626cb93a386Sopenharmony_ci , fGMs(skiagm::GMRegistry::Head()) { 627cb93a386Sopenharmony_ci collect_files(FLAGS_skps, ".skp", &fSKPs); 628cb93a386Sopenharmony_ci collect_files(FLAGS_mskps, ".mskp", &fMSKPs); 629cb93a386Sopenharmony_ci collect_files(FLAGS_svgs, ".svg", &fSVGs); 630cb93a386Sopenharmony_ci collect_files(FLAGS_texttraces, ".trace", &fTextBlobTraces); 631cb93a386Sopenharmony_ci 632cb93a386Sopenharmony_ci if (4 != sscanf(FLAGS_clip[0], "%d,%d,%d,%d", 633cb93a386Sopenharmony_ci &fClip.fLeft, &fClip.fTop, &fClip.fRight, &fClip.fBottom)) { 634cb93a386Sopenharmony_ci SkDebugf("Can't parse %s from --clip as an SkIRect.\n", FLAGS_clip[0]); 635cb93a386Sopenharmony_ci exit(1); 636cb93a386Sopenharmony_ci } 637cb93a386Sopenharmony_ci 638cb93a386Sopenharmony_ci for (int i = 0; i < FLAGS_scales.count(); i++) { 639cb93a386Sopenharmony_ci if (1 != sscanf(FLAGS_scales[i], "%f", &fScales.push_back())) { 640cb93a386Sopenharmony_ci SkDebugf("Can't parse %s from --scales as an SkScalar.\n", FLAGS_scales[i]); 641cb93a386Sopenharmony_ci exit(1); 642cb93a386Sopenharmony_ci } 643cb93a386Sopenharmony_ci } 644cb93a386Sopenharmony_ci 645cb93a386Sopenharmony_ci if (2 != sscanf(FLAGS_zoom[0], "%f,%lf", &fZoomMax, &fZoomPeriodMs)) { 646cb93a386Sopenharmony_ci SkDebugf("Can't parse %s from --zoom as a zoomMax,zoomPeriodMs.\n", FLAGS_zoom[0]); 647cb93a386Sopenharmony_ci exit(1); 648cb93a386Sopenharmony_ci } 649cb93a386Sopenharmony_ci 650cb93a386Sopenharmony_ci // Prepare the images for decoding 651cb93a386Sopenharmony_ci if (!CommonFlags::CollectImages(FLAGS_images, &fImages)) { 652cb93a386Sopenharmony_ci exit(1); 653cb93a386Sopenharmony_ci } 654cb93a386Sopenharmony_ci 655cb93a386Sopenharmony_ci // Choose the candidate color types for image decoding 656cb93a386Sopenharmony_ci fColorTypes.push_back(kN32_SkColorType); 657cb93a386Sopenharmony_ci if (!FLAGS_simpleCodec) { 658cb93a386Sopenharmony_ci fColorTypes.push_back(kRGB_565_SkColorType); 659cb93a386Sopenharmony_ci fColorTypes.push_back(kAlpha_8_SkColorType); 660cb93a386Sopenharmony_ci fColorTypes.push_back(kGray_8_SkColorType); 661cb93a386Sopenharmony_ci } 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci static sk_sp<SkPicture> ReadPicture(const char* path) { 665cb93a386Sopenharmony_ci // Not strictly necessary, as it will be checked again later, 666cb93a386Sopenharmony_ci // but helps to avoid a lot of pointless work if we're going to skip it. 667cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, SkOSPath::Basename(path).c_str())) { 668cb93a386Sopenharmony_ci return nullptr; 669cb93a386Sopenharmony_ci } 670cb93a386Sopenharmony_ci 671cb93a386Sopenharmony_ci std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); 672cb93a386Sopenharmony_ci if (!stream) { 673cb93a386Sopenharmony_ci SkDebugf("Could not read %s.\n", path); 674cb93a386Sopenharmony_ci return nullptr; 675cb93a386Sopenharmony_ci } 676cb93a386Sopenharmony_ci 677cb93a386Sopenharmony_ci return SkPicture::MakeFromStream(stream.get()); 678cb93a386Sopenharmony_ci } 679cb93a386Sopenharmony_ci 680cb93a386Sopenharmony_ci static std::unique_ptr<MSKPPlayer> ReadMSKP(const char* path) { 681cb93a386Sopenharmony_ci // Not strictly necessary, as it will be checked again later, 682cb93a386Sopenharmony_ci // but helps to avoid a lot of pointless work if we're going to skip it. 683cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, SkOSPath::Basename(path).c_str())) { 684cb93a386Sopenharmony_ci return nullptr; 685cb93a386Sopenharmony_ci } 686cb93a386Sopenharmony_ci 687cb93a386Sopenharmony_ci std::unique_ptr<SkStreamSeekable> stream = SkStream::MakeFromFile(path); 688cb93a386Sopenharmony_ci if (!stream) { 689cb93a386Sopenharmony_ci SkDebugf("Could not read %s.\n", path); 690cb93a386Sopenharmony_ci return nullptr; 691cb93a386Sopenharmony_ci } 692cb93a386Sopenharmony_ci 693cb93a386Sopenharmony_ci return MSKPPlayer::Make(stream.get()); 694cb93a386Sopenharmony_ci } 695cb93a386Sopenharmony_ci 696cb93a386Sopenharmony_ci static sk_sp<SkPicture> ReadSVGPicture(const char* path) { 697cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, SkOSPath::Basename(path).c_str())) { 698cb93a386Sopenharmony_ci return nullptr; 699cb93a386Sopenharmony_ci } 700cb93a386Sopenharmony_ci sk_sp<SkData> data(SkData::MakeFromFileName(path)); 701cb93a386Sopenharmony_ci if (!data) { 702cb93a386Sopenharmony_ci SkDebugf("Could not read %s.\n", path); 703cb93a386Sopenharmony_ci return nullptr; 704cb93a386Sopenharmony_ci } 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci#if defined(SK_ENABLE_SVG) 707cb93a386Sopenharmony_ci SkMemoryStream stream(std::move(data)); 708cb93a386Sopenharmony_ci sk_sp<SkSVGDOM> svgDom = SkSVGDOM::MakeFromStream(stream); 709cb93a386Sopenharmony_ci if (!svgDom) { 710cb93a386Sopenharmony_ci SkDebugf("Could not parse %s.\n", path); 711cb93a386Sopenharmony_ci return nullptr; 712cb93a386Sopenharmony_ci } 713cb93a386Sopenharmony_ci 714cb93a386Sopenharmony_ci // Use the intrinsic SVG size if available, otherwise fall back to a default value. 715cb93a386Sopenharmony_ci static const SkSize kDefaultContainerSize = SkSize::Make(128, 128); 716cb93a386Sopenharmony_ci if (svgDom->containerSize().isEmpty()) { 717cb93a386Sopenharmony_ci svgDom->setContainerSize(kDefaultContainerSize); 718cb93a386Sopenharmony_ci } 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci SkPictureRecorder recorder; 721cb93a386Sopenharmony_ci svgDom->render(recorder.beginRecording(svgDom->containerSize().width(), 722cb93a386Sopenharmony_ci svgDom->containerSize().height())); 723cb93a386Sopenharmony_ci return recorder.finishRecordingAsPicture(); 724cb93a386Sopenharmony_ci#else 725cb93a386Sopenharmony_ci return nullptr; 726cb93a386Sopenharmony_ci#endif // defined(SK_ENABLE_SVG) 727cb93a386Sopenharmony_ci } 728cb93a386Sopenharmony_ci 729cb93a386Sopenharmony_ci Benchmark* next() { 730cb93a386Sopenharmony_ci std::unique_ptr<Benchmark> bench; 731cb93a386Sopenharmony_ci do { 732cb93a386Sopenharmony_ci bench.reset(this->rawNext()); 733cb93a386Sopenharmony_ci if (!bench) { 734cb93a386Sopenharmony_ci return nullptr; 735cb93a386Sopenharmony_ci } 736cb93a386Sopenharmony_ci } while (CommandLineFlags::ShouldSkip(FLAGS_sourceType, fSourceType) || 737cb93a386Sopenharmony_ci CommandLineFlags::ShouldSkip(FLAGS_benchType, fBenchType)); 738cb93a386Sopenharmony_ci return bench.release(); 739cb93a386Sopenharmony_ci } 740cb93a386Sopenharmony_ci 741cb93a386Sopenharmony_ci Benchmark* rawNext() { 742cb93a386Sopenharmony_ci if (fBenches) { 743cb93a386Sopenharmony_ci Benchmark* bench = fBenches->get()(nullptr); 744cb93a386Sopenharmony_ci fBenches = fBenches->next(); 745cb93a386Sopenharmony_ci fSourceType = "bench"; 746cb93a386Sopenharmony_ci fBenchType = "micro"; 747cb93a386Sopenharmony_ci return bench; 748cb93a386Sopenharmony_ci } 749cb93a386Sopenharmony_ci 750cb93a386Sopenharmony_ci while (fGMs) { 751cb93a386Sopenharmony_ci std::unique_ptr<skiagm::GM> gm = fGMs->get()(); 752cb93a386Sopenharmony_ci fGMs = fGMs->next(); 753cb93a386Sopenharmony_ci if (gm->runAsBench()) { 754cb93a386Sopenharmony_ci fSourceType = "gm"; 755cb93a386Sopenharmony_ci fBenchType = "micro"; 756cb93a386Sopenharmony_ci return new GMBench(std::move(gm)); 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci } 759cb93a386Sopenharmony_ci 760cb93a386Sopenharmony_ci while (fCurrentTextBlobTrace < fTextBlobTraces.count()) { 761cb93a386Sopenharmony_ci SkString path = fTextBlobTraces[fCurrentTextBlobTrace++]; 762cb93a386Sopenharmony_ci SkString basename = SkOSPath::Basename(path.c_str()); 763cb93a386Sopenharmony_ci static constexpr char kEnding[] = ".trace"; 764cb93a386Sopenharmony_ci if (basename.endsWith(kEnding)) { 765cb93a386Sopenharmony_ci basename.remove(basename.size() - strlen(kEnding), strlen(kEnding)); 766cb93a386Sopenharmony_ci } 767cb93a386Sopenharmony_ci fSourceType = "texttrace"; 768cb93a386Sopenharmony_ci fBenchType = "micro"; 769cb93a386Sopenharmony_ci return CreateDiffCanvasBench( 770cb93a386Sopenharmony_ci SkStringPrintf("SkDiffBench-%s", basename.c_str()), 771cb93a386Sopenharmony_ci [path](){ return SkStream::MakeFromFile(path.c_str()); }); 772cb93a386Sopenharmony_ci } 773cb93a386Sopenharmony_ci 774cb93a386Sopenharmony_ci // First add all .skps as RecordingBenches. 775cb93a386Sopenharmony_ci while (fCurrentRecording < fSKPs.count()) { 776cb93a386Sopenharmony_ci const SkString& path = fSKPs[fCurrentRecording++]; 777cb93a386Sopenharmony_ci sk_sp<SkPicture> pic = ReadPicture(path.c_str()); 778cb93a386Sopenharmony_ci if (!pic) { 779cb93a386Sopenharmony_ci continue; 780cb93a386Sopenharmony_ci } 781cb93a386Sopenharmony_ci SkString name = SkOSPath::Basename(path.c_str()); 782cb93a386Sopenharmony_ci fSourceType = "skp"; 783cb93a386Sopenharmony_ci fBenchType = "recording"; 784cb93a386Sopenharmony_ci fSKPBytes = static_cast<double>(pic->approximateBytesUsed()); 785cb93a386Sopenharmony_ci fSKPOps = pic->approximateOpCount(); 786cb93a386Sopenharmony_ci return new RecordingBench(name.c_str(), pic.get(), FLAGS_bbh); 787cb93a386Sopenharmony_ci } 788cb93a386Sopenharmony_ci 789cb93a386Sopenharmony_ci // Add all .skps as DeserializePictureBenchs. 790cb93a386Sopenharmony_ci while (fCurrentDeserialPicture < fSKPs.count()) { 791cb93a386Sopenharmony_ci const SkString& path = fSKPs[fCurrentDeserialPicture++]; 792cb93a386Sopenharmony_ci sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str()); 793cb93a386Sopenharmony_ci if (!data) { 794cb93a386Sopenharmony_ci continue; 795cb93a386Sopenharmony_ci } 796cb93a386Sopenharmony_ci SkString name = SkOSPath::Basename(path.c_str()); 797cb93a386Sopenharmony_ci fSourceType = "skp"; 798cb93a386Sopenharmony_ci fBenchType = "deserial"; 799cb93a386Sopenharmony_ci fSKPBytes = static_cast<double>(data->size()); 800cb93a386Sopenharmony_ci fSKPOps = 0; 801cb93a386Sopenharmony_ci return new DeserializePictureBench(name.c_str(), std::move(data)); 802cb93a386Sopenharmony_ci } 803cb93a386Sopenharmony_ci 804cb93a386Sopenharmony_ci // Then once each for each scale as SKPBenches (playback). 805cb93a386Sopenharmony_ci while (fCurrentScale < fScales.count()) { 806cb93a386Sopenharmony_ci while (fCurrentSKP < fSKPs.count()) { 807cb93a386Sopenharmony_ci const SkString& path = fSKPs[fCurrentSKP++]; 808cb93a386Sopenharmony_ci sk_sp<SkPicture> pic = ReadPicture(path.c_str()); 809cb93a386Sopenharmony_ci if (!pic) { 810cb93a386Sopenharmony_ci continue; 811cb93a386Sopenharmony_ci } 812cb93a386Sopenharmony_ci 813cb93a386Sopenharmony_ci if (FLAGS_bbh) { 814cb93a386Sopenharmony_ci // The SKP we read off disk doesn't have a BBH. Re-record so it grows one. 815cb93a386Sopenharmony_ci SkRTreeFactory factory; 816cb93a386Sopenharmony_ci SkPictureRecorder recorder; 817cb93a386Sopenharmony_ci pic->playback(recorder.beginRecording(pic->cullRect().width(), 818cb93a386Sopenharmony_ci pic->cullRect().height(), 819cb93a386Sopenharmony_ci &factory)); 820cb93a386Sopenharmony_ci pic = recorder.finishRecordingAsPicture(); 821cb93a386Sopenharmony_ci } 822cb93a386Sopenharmony_ci SkString name = SkOSPath::Basename(path.c_str()); 823cb93a386Sopenharmony_ci fSourceType = "skp"; 824cb93a386Sopenharmony_ci fBenchType = "playback"; 825cb93a386Sopenharmony_ci return new SKPBench(name.c_str(), pic.get(), fClip, fScales[fCurrentScale], 826cb93a386Sopenharmony_ci FLAGS_loopSKP); 827cb93a386Sopenharmony_ci } 828cb93a386Sopenharmony_ci 829cb93a386Sopenharmony_ci while (fCurrentSVG < fSVGs.count()) { 830cb93a386Sopenharmony_ci const char* path = fSVGs[fCurrentSVG++].c_str(); 831cb93a386Sopenharmony_ci if (sk_sp<SkPicture> pic = ReadSVGPicture(path)) { 832cb93a386Sopenharmony_ci fSourceType = "svg"; 833cb93a386Sopenharmony_ci fBenchType = "playback"; 834cb93a386Sopenharmony_ci return new SKPBench(SkOSPath::Basename(path).c_str(), pic.get(), fClip, 835cb93a386Sopenharmony_ci fScales[fCurrentScale], FLAGS_loopSKP); 836cb93a386Sopenharmony_ci } 837cb93a386Sopenharmony_ci } 838cb93a386Sopenharmony_ci 839cb93a386Sopenharmony_ci fCurrentSKP = 0; 840cb93a386Sopenharmony_ci fCurrentSVG = 0; 841cb93a386Sopenharmony_ci fCurrentScale++; 842cb93a386Sopenharmony_ci } 843cb93a386Sopenharmony_ci 844cb93a386Sopenharmony_ci // Now loop over each skp again if we have an animation 845cb93a386Sopenharmony_ci if (fZoomMax != 1.0f && fZoomPeriodMs > 0) { 846cb93a386Sopenharmony_ci while (fCurrentAnimSKP < fSKPs.count()) { 847cb93a386Sopenharmony_ci const SkString& path = fSKPs[fCurrentAnimSKP]; 848cb93a386Sopenharmony_ci sk_sp<SkPicture> pic = ReadPicture(path.c_str()); 849cb93a386Sopenharmony_ci if (!pic) { 850cb93a386Sopenharmony_ci fCurrentAnimSKP++; 851cb93a386Sopenharmony_ci continue; 852cb93a386Sopenharmony_ci } 853cb93a386Sopenharmony_ci 854cb93a386Sopenharmony_ci fCurrentAnimSKP++; 855cb93a386Sopenharmony_ci SkString name = SkOSPath::Basename(path.c_str()); 856cb93a386Sopenharmony_ci sk_sp<SKPAnimationBench::Animation> animation = 857cb93a386Sopenharmony_ci SKPAnimationBench::MakeZoomAnimation(fZoomMax, fZoomPeriodMs); 858cb93a386Sopenharmony_ci return new SKPAnimationBench(name.c_str(), pic.get(), fClip, std::move(animation), 859cb93a386Sopenharmony_ci FLAGS_loopSKP); 860cb93a386Sopenharmony_ci } 861cb93a386Sopenharmony_ci } 862cb93a386Sopenharmony_ci 863cb93a386Sopenharmony_ci // Read all MSKPs as benches 864cb93a386Sopenharmony_ci while (fCurrentMSKP < fMSKPs.count()) { 865cb93a386Sopenharmony_ci const SkString& path = fMSKPs[fCurrentMSKP++]; 866cb93a386Sopenharmony_ci std::unique_ptr<MSKPPlayer> player = ReadMSKP(path.c_str()); 867cb93a386Sopenharmony_ci if (!player) { 868cb93a386Sopenharmony_ci continue; 869cb93a386Sopenharmony_ci } 870cb93a386Sopenharmony_ci SkString name = SkOSPath::Basename(path.c_str()); 871cb93a386Sopenharmony_ci fSourceType = "mskp"; 872cb93a386Sopenharmony_ci fBenchType = "mskp"; 873cb93a386Sopenharmony_ci return new MSKPBench(std::move(name), std::move(player)); 874cb93a386Sopenharmony_ci } 875cb93a386Sopenharmony_ci 876cb93a386Sopenharmony_ci for (; fCurrentCodec < fImages.count(); fCurrentCodec++) { 877cb93a386Sopenharmony_ci fSourceType = "image"; 878cb93a386Sopenharmony_ci fBenchType = "skcodec"; 879cb93a386Sopenharmony_ci const SkString& path = fImages[fCurrentCodec]; 880cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) { 881cb93a386Sopenharmony_ci continue; 882cb93a386Sopenharmony_ci } 883cb93a386Sopenharmony_ci sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); 884cb93a386Sopenharmony_ci std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); 885cb93a386Sopenharmony_ci if (!codec) { 886cb93a386Sopenharmony_ci // Nothing to time. 887cb93a386Sopenharmony_ci SkDebugf("Cannot find codec for %s\n", path.c_str()); 888cb93a386Sopenharmony_ci continue; 889cb93a386Sopenharmony_ci } 890cb93a386Sopenharmony_ci 891cb93a386Sopenharmony_ci while (fCurrentColorType < fColorTypes.count()) { 892cb93a386Sopenharmony_ci const SkColorType colorType = fColorTypes[fCurrentColorType]; 893cb93a386Sopenharmony_ci 894cb93a386Sopenharmony_ci SkAlphaType alphaType = codec->getInfo().alphaType(); 895cb93a386Sopenharmony_ci if (FLAGS_simpleCodec) { 896cb93a386Sopenharmony_ci if (kUnpremul_SkAlphaType == alphaType) { 897cb93a386Sopenharmony_ci alphaType = kPremul_SkAlphaType; 898cb93a386Sopenharmony_ci } 899cb93a386Sopenharmony_ci 900cb93a386Sopenharmony_ci fCurrentColorType++; 901cb93a386Sopenharmony_ci } else { 902cb93a386Sopenharmony_ci switch (alphaType) { 903cb93a386Sopenharmony_ci case kOpaque_SkAlphaType: 904cb93a386Sopenharmony_ci // We only need to test one alpha type (opaque). 905cb93a386Sopenharmony_ci fCurrentColorType++; 906cb93a386Sopenharmony_ci break; 907cb93a386Sopenharmony_ci case kUnpremul_SkAlphaType: 908cb93a386Sopenharmony_ci case kPremul_SkAlphaType: 909cb93a386Sopenharmony_ci if (0 == fCurrentAlphaType) { 910cb93a386Sopenharmony_ci // Test unpremul first. 911cb93a386Sopenharmony_ci alphaType = kUnpremul_SkAlphaType; 912cb93a386Sopenharmony_ci fCurrentAlphaType++; 913cb93a386Sopenharmony_ci } else { 914cb93a386Sopenharmony_ci // Test premul. 915cb93a386Sopenharmony_ci alphaType = kPremul_SkAlphaType; 916cb93a386Sopenharmony_ci fCurrentAlphaType = 0; 917cb93a386Sopenharmony_ci fCurrentColorType++; 918cb93a386Sopenharmony_ci } 919cb93a386Sopenharmony_ci break; 920cb93a386Sopenharmony_ci default: 921cb93a386Sopenharmony_ci SkASSERT(false); 922cb93a386Sopenharmony_ci fCurrentColorType++; 923cb93a386Sopenharmony_ci break; 924cb93a386Sopenharmony_ci } 925cb93a386Sopenharmony_ci } 926cb93a386Sopenharmony_ci 927cb93a386Sopenharmony_ci // Make sure we can decode to this color type and alpha type. 928cb93a386Sopenharmony_ci SkImageInfo info = 929cb93a386Sopenharmony_ci codec->getInfo().makeColorType(colorType).makeAlphaType(alphaType); 930cb93a386Sopenharmony_ci const size_t rowBytes = info.minRowBytes(); 931cb93a386Sopenharmony_ci SkAutoMalloc storage(info.computeByteSize(rowBytes)); 932cb93a386Sopenharmony_ci 933cb93a386Sopenharmony_ci const SkCodec::Result result = codec->getPixels( 934cb93a386Sopenharmony_ci info, storage.get(), rowBytes); 935cb93a386Sopenharmony_ci switch (result) { 936cb93a386Sopenharmony_ci case SkCodec::kSuccess: 937cb93a386Sopenharmony_ci case SkCodec::kIncompleteInput: 938cb93a386Sopenharmony_ci return new CodecBench(SkOSPath::Basename(path.c_str()), 939cb93a386Sopenharmony_ci encoded.get(), colorType, alphaType); 940cb93a386Sopenharmony_ci case SkCodec::kInvalidConversion: 941cb93a386Sopenharmony_ci // This is okay. Not all conversions are valid. 942cb93a386Sopenharmony_ci break; 943cb93a386Sopenharmony_ci default: 944cb93a386Sopenharmony_ci // This represents some sort of failure. 945cb93a386Sopenharmony_ci SkASSERT(false); 946cb93a386Sopenharmony_ci break; 947cb93a386Sopenharmony_ci } 948cb93a386Sopenharmony_ci } 949cb93a386Sopenharmony_ci fCurrentColorType = 0; 950cb93a386Sopenharmony_ci } 951cb93a386Sopenharmony_ci 952cb93a386Sopenharmony_ci // Run AndroidCodecBenches 953cb93a386Sopenharmony_ci const int sampleSizes[] = { 2, 4, 8 }; 954cb93a386Sopenharmony_ci for (; fCurrentAndroidCodec < fImages.count(); fCurrentAndroidCodec++) { 955cb93a386Sopenharmony_ci fSourceType = "image"; 956cb93a386Sopenharmony_ci fBenchType = "skandroidcodec"; 957cb93a386Sopenharmony_ci 958cb93a386Sopenharmony_ci const SkString& path = fImages[fCurrentAndroidCodec]; 959cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) { 960cb93a386Sopenharmony_ci continue; 961cb93a386Sopenharmony_ci } 962cb93a386Sopenharmony_ci sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); 963cb93a386Sopenharmony_ci std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded)); 964cb93a386Sopenharmony_ci if (!codec) { 965cb93a386Sopenharmony_ci // Nothing to time. 966cb93a386Sopenharmony_ci SkDebugf("Cannot find codec for %s\n", path.c_str()); 967cb93a386Sopenharmony_ci continue; 968cb93a386Sopenharmony_ci } 969cb93a386Sopenharmony_ci 970cb93a386Sopenharmony_ci while (fCurrentSampleSize < (int) SK_ARRAY_COUNT(sampleSizes)) { 971cb93a386Sopenharmony_ci int sampleSize = sampleSizes[fCurrentSampleSize]; 972cb93a386Sopenharmony_ci fCurrentSampleSize++; 973cb93a386Sopenharmony_ci if (10 * sampleSize > std::min(codec->getInfo().width(), codec->getInfo().height())) { 974cb93a386Sopenharmony_ci // Avoid benchmarking scaled decodes of already small images. 975cb93a386Sopenharmony_ci break; 976cb93a386Sopenharmony_ci } 977cb93a386Sopenharmony_ci 978cb93a386Sopenharmony_ci return new AndroidCodecBench(SkOSPath::Basename(path.c_str()), 979cb93a386Sopenharmony_ci encoded.get(), sampleSize); 980cb93a386Sopenharmony_ci } 981cb93a386Sopenharmony_ci fCurrentSampleSize = 0; 982cb93a386Sopenharmony_ci } 983cb93a386Sopenharmony_ci 984cb93a386Sopenharmony_ci#ifdef SK_ENABLE_ANDROID_UTILS 985cb93a386Sopenharmony_ci // Run the BRDBenches 986cb93a386Sopenharmony_ci // We intend to create benchmarks that model the use cases in 987cb93a386Sopenharmony_ci // android/libraries/social/tiledimage. In this library, an image is decoded in 512x512 988cb93a386Sopenharmony_ci // tiles. The image can be translated freely, so the location of a tile may be anywhere in 989cb93a386Sopenharmony_ci // the image. For that reason, we will benchmark decodes in five representative locations 990cb93a386Sopenharmony_ci // in the image. Additionally, this use case utilizes power of two scaling, so we will 991cb93a386Sopenharmony_ci // test on power of two sample sizes. The output tile is always 512x512, so, when a 992cb93a386Sopenharmony_ci // sampleSize is used, the size of the subset that is decoded is always 993cb93a386Sopenharmony_ci // (sampleSize*512)x(sampleSize*512). 994cb93a386Sopenharmony_ci // There are a few good reasons to only test on power of two sample sizes at this time: 995cb93a386Sopenharmony_ci // All use cases we are aware of only scale by powers of two. 996cb93a386Sopenharmony_ci // PNG decodes use the indicated sampling strategy regardless of the sample size, so 997cb93a386Sopenharmony_ci // these tests are sufficient to provide good coverage of our scaling options. 998cb93a386Sopenharmony_ci const uint32_t brdSampleSizes[] = { 1, 2, 4, 8, 16 }; 999cb93a386Sopenharmony_ci const uint32_t minOutputSize = 512; 1000cb93a386Sopenharmony_ci for (; fCurrentBRDImage < fImages.count(); fCurrentBRDImage++) { 1001cb93a386Sopenharmony_ci fSourceType = "image"; 1002cb93a386Sopenharmony_ci fBenchType = "BRD"; 1003cb93a386Sopenharmony_ci 1004cb93a386Sopenharmony_ci const SkString& path = fImages[fCurrentBRDImage]; 1005cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, path.c_str())) { 1006cb93a386Sopenharmony_ci continue; 1007cb93a386Sopenharmony_ci } 1008cb93a386Sopenharmony_ci 1009cb93a386Sopenharmony_ci while (fCurrentColorType < fColorTypes.count()) { 1010cb93a386Sopenharmony_ci while (fCurrentSampleSize < (int) SK_ARRAY_COUNT(brdSampleSizes)) { 1011cb93a386Sopenharmony_ci while (fCurrentSubsetType <= kLastSingle_SubsetType) { 1012cb93a386Sopenharmony_ci 1013cb93a386Sopenharmony_ci sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); 1014cb93a386Sopenharmony_ci const SkColorType colorType = fColorTypes[fCurrentColorType]; 1015cb93a386Sopenharmony_ci uint32_t sampleSize = brdSampleSizes[fCurrentSampleSize]; 1016cb93a386Sopenharmony_ci int currentSubsetType = fCurrentSubsetType++; 1017cb93a386Sopenharmony_ci 1018cb93a386Sopenharmony_ci int width = 0; 1019cb93a386Sopenharmony_ci int height = 0; 1020cb93a386Sopenharmony_ci if (!valid_brd_bench(encoded, colorType, sampleSize, minOutputSize, 1021cb93a386Sopenharmony_ci &width, &height)) { 1022cb93a386Sopenharmony_ci break; 1023cb93a386Sopenharmony_ci } 1024cb93a386Sopenharmony_ci 1025cb93a386Sopenharmony_ci SkString basename = SkOSPath::Basename(path.c_str()); 1026cb93a386Sopenharmony_ci SkIRect subset; 1027cb93a386Sopenharmony_ci const uint32_t subsetSize = sampleSize * minOutputSize; 1028cb93a386Sopenharmony_ci switch (currentSubsetType) { 1029cb93a386Sopenharmony_ci case kTopLeft_SubsetType: 1030cb93a386Sopenharmony_ci basename.append("_TopLeft"); 1031cb93a386Sopenharmony_ci subset = SkIRect::MakeXYWH(0, 0, subsetSize, subsetSize); 1032cb93a386Sopenharmony_ci break; 1033cb93a386Sopenharmony_ci case kTopRight_SubsetType: 1034cb93a386Sopenharmony_ci basename.append("_TopRight"); 1035cb93a386Sopenharmony_ci subset = SkIRect::MakeXYWH(width - subsetSize, 0, subsetSize, 1036cb93a386Sopenharmony_ci subsetSize); 1037cb93a386Sopenharmony_ci break; 1038cb93a386Sopenharmony_ci case kMiddle_SubsetType: 1039cb93a386Sopenharmony_ci basename.append("_Middle"); 1040cb93a386Sopenharmony_ci subset = SkIRect::MakeXYWH((width - subsetSize) / 2, 1041cb93a386Sopenharmony_ci (height - subsetSize) / 2, subsetSize, subsetSize); 1042cb93a386Sopenharmony_ci break; 1043cb93a386Sopenharmony_ci case kBottomLeft_SubsetType: 1044cb93a386Sopenharmony_ci basename.append("_BottomLeft"); 1045cb93a386Sopenharmony_ci subset = SkIRect::MakeXYWH(0, height - subsetSize, subsetSize, 1046cb93a386Sopenharmony_ci subsetSize); 1047cb93a386Sopenharmony_ci break; 1048cb93a386Sopenharmony_ci case kBottomRight_SubsetType: 1049cb93a386Sopenharmony_ci basename.append("_BottomRight"); 1050cb93a386Sopenharmony_ci subset = SkIRect::MakeXYWH(width - subsetSize, 1051cb93a386Sopenharmony_ci height - subsetSize, subsetSize, subsetSize); 1052cb93a386Sopenharmony_ci break; 1053cb93a386Sopenharmony_ci default: 1054cb93a386Sopenharmony_ci SkASSERT(false); 1055cb93a386Sopenharmony_ci } 1056cb93a386Sopenharmony_ci 1057cb93a386Sopenharmony_ci return new BitmapRegionDecoderBench(basename.c_str(), encoded.get(), 1058cb93a386Sopenharmony_ci colorType, sampleSize, subset); 1059cb93a386Sopenharmony_ci } 1060cb93a386Sopenharmony_ci fCurrentSubsetType = 0; 1061cb93a386Sopenharmony_ci fCurrentSampleSize++; 1062cb93a386Sopenharmony_ci } 1063cb93a386Sopenharmony_ci fCurrentSampleSize = 0; 1064cb93a386Sopenharmony_ci fCurrentColorType++; 1065cb93a386Sopenharmony_ci } 1066cb93a386Sopenharmony_ci fCurrentColorType = 0; 1067cb93a386Sopenharmony_ci } 1068cb93a386Sopenharmony_ci#endif // SK_ENABLE_ANDROID_UTILS 1069cb93a386Sopenharmony_ci 1070cb93a386Sopenharmony_ci return nullptr; 1071cb93a386Sopenharmony_ci } 1072cb93a386Sopenharmony_ci 1073cb93a386Sopenharmony_ci void fillCurrentOptions(NanoJSONResultsWriter& log) const { 1074cb93a386Sopenharmony_ci log.appendString("source_type", fSourceType); 1075cb93a386Sopenharmony_ci log.appendString("bench_type", fBenchType); 1076cb93a386Sopenharmony_ci if (0 == strcmp(fSourceType, "skp")) { 1077cb93a386Sopenharmony_ci log.appendString("clip", 1078cb93a386Sopenharmony_ci SkStringPrintf("%d %d %d %d", fClip.fLeft, fClip.fTop, 1079cb93a386Sopenharmony_ci fClip.fRight, fClip.fBottom).c_str()); 1080cb93a386Sopenharmony_ci SkASSERT_RELEASE(fCurrentScale < fScales.count()); // debugging paranoia 1081cb93a386Sopenharmony_ci log.appendString("scale", SkStringPrintf("%.2g", fScales[fCurrentScale]).c_str()); 1082cb93a386Sopenharmony_ci } 1083cb93a386Sopenharmony_ci } 1084cb93a386Sopenharmony_ci 1085cb93a386Sopenharmony_ci void fillCurrentMetrics(NanoJSONResultsWriter& log) const { 1086cb93a386Sopenharmony_ci if (0 == strcmp(fBenchType, "recording")) { 1087cb93a386Sopenharmony_ci log.appendMetric("bytes", fSKPBytes); 1088cb93a386Sopenharmony_ci log.appendMetric("ops", fSKPOps); 1089cb93a386Sopenharmony_ci } 1090cb93a386Sopenharmony_ci } 1091cb93a386Sopenharmony_ci 1092cb93a386Sopenharmony_ciprivate: 1093cb93a386Sopenharmony_ci#ifdef SK_ENABLE_ANDROID_UTILS 1094cb93a386Sopenharmony_ci enum SubsetType { 1095cb93a386Sopenharmony_ci kTopLeft_SubsetType = 0, 1096cb93a386Sopenharmony_ci kTopRight_SubsetType = 1, 1097cb93a386Sopenharmony_ci kMiddle_SubsetType = 2, 1098cb93a386Sopenharmony_ci kBottomLeft_SubsetType = 3, 1099cb93a386Sopenharmony_ci kBottomRight_SubsetType = 4, 1100cb93a386Sopenharmony_ci kTranslate_SubsetType = 5, 1101cb93a386Sopenharmony_ci kZoom_SubsetType = 6, 1102cb93a386Sopenharmony_ci kLast_SubsetType = kZoom_SubsetType, 1103cb93a386Sopenharmony_ci kLastSingle_SubsetType = kBottomRight_SubsetType, 1104cb93a386Sopenharmony_ci }; 1105cb93a386Sopenharmony_ci#endif 1106cb93a386Sopenharmony_ci 1107cb93a386Sopenharmony_ci const BenchRegistry* fBenches; 1108cb93a386Sopenharmony_ci const skiagm::GMRegistry* fGMs; 1109cb93a386Sopenharmony_ci SkIRect fClip; 1110cb93a386Sopenharmony_ci SkTArray<SkScalar> fScales; 1111cb93a386Sopenharmony_ci SkTArray<SkString> fSKPs; 1112cb93a386Sopenharmony_ci SkTArray<SkString> fMSKPs; 1113cb93a386Sopenharmony_ci SkTArray<SkString> fSVGs; 1114cb93a386Sopenharmony_ci SkTArray<SkString> fTextBlobTraces; 1115cb93a386Sopenharmony_ci SkTArray<SkString> fImages; 1116cb93a386Sopenharmony_ci SkTArray<SkColorType, true> fColorTypes; 1117cb93a386Sopenharmony_ci SkScalar fZoomMax; 1118cb93a386Sopenharmony_ci double fZoomPeriodMs; 1119cb93a386Sopenharmony_ci 1120cb93a386Sopenharmony_ci double fSKPBytes, fSKPOps; 1121cb93a386Sopenharmony_ci 1122cb93a386Sopenharmony_ci const char* fSourceType; // What we're benching: bench, GM, SKP, ... 1123cb93a386Sopenharmony_ci const char* fBenchType; // How we bench it: micro, recording, playback, ... 1124cb93a386Sopenharmony_ci int fCurrentRecording = 0; 1125cb93a386Sopenharmony_ci int fCurrentDeserialPicture = 0; 1126cb93a386Sopenharmony_ci int fCurrentMSKP = 0; 1127cb93a386Sopenharmony_ci int fCurrentScale = 0; 1128cb93a386Sopenharmony_ci int fCurrentSKP = 0; 1129cb93a386Sopenharmony_ci int fCurrentSVG = 0; 1130cb93a386Sopenharmony_ci int fCurrentTextBlobTrace = 0; 1131cb93a386Sopenharmony_ci int fCurrentCodec = 0; 1132cb93a386Sopenharmony_ci int fCurrentAndroidCodec = 0; 1133cb93a386Sopenharmony_ci#ifdef SK_ENABLE_ANDROID_UTILS 1134cb93a386Sopenharmony_ci int fCurrentBRDImage = 0; 1135cb93a386Sopenharmony_ci int fCurrentSubsetType = 0; 1136cb93a386Sopenharmony_ci#endif 1137cb93a386Sopenharmony_ci int fCurrentColorType = 0; 1138cb93a386Sopenharmony_ci int fCurrentAlphaType = 0; 1139cb93a386Sopenharmony_ci int fCurrentSampleSize = 0; 1140cb93a386Sopenharmony_ci int fCurrentAnimSKP = 0; 1141cb93a386Sopenharmony_ci}; 1142cb93a386Sopenharmony_ci 1143cb93a386Sopenharmony_ci// Some runs (mostly, Valgrind) are so slow that the bot framework thinks we've hung. 1144cb93a386Sopenharmony_ci// This prints something every once in a while so that it knows we're still working. 1145cb93a386Sopenharmony_cistatic void start_keepalive() { 1146cb93a386Sopenharmony_ci static std::thread* intentionallyLeaked = new std::thread([]{ 1147cb93a386Sopenharmony_ci for (;;) { 1148cb93a386Sopenharmony_ci static const int kSec = 1200; 1149cb93a386Sopenharmony_ci #if defined(SK_BUILD_FOR_WIN) 1150cb93a386Sopenharmony_ci Sleep(kSec * 1000); 1151cb93a386Sopenharmony_ci #else 1152cb93a386Sopenharmony_ci sleep(kSec); 1153cb93a386Sopenharmony_ci #endif 1154cb93a386Sopenharmony_ci SkDebugf("\nBenchmarks still running...\n"); 1155cb93a386Sopenharmony_ci } 1156cb93a386Sopenharmony_ci }); 1157cb93a386Sopenharmony_ci (void)intentionallyLeaked; 1158cb93a386Sopenharmony_ci} 1159cb93a386Sopenharmony_ci 1160cb93a386Sopenharmony_ciclass NanobenchShaderErrorHandler : public GrContextOptions::ShaderErrorHandler { 1161cb93a386Sopenharmony_ci void compileError(const char* shader, const char* errors) override { 1162cb93a386Sopenharmony_ci // Nanobench should abort if any shader can't compile. Failure is much better than 1163cb93a386Sopenharmony_ci // reporting meaningless performance metrics. 1164cb93a386Sopenharmony_ci SkSL::String message = GrShaderUtils::BuildShaderErrorMessage(shader, errors); 1165cb93a386Sopenharmony_ci SK_ABORT("\n%s", message.c_str()); 1166cb93a386Sopenharmony_ci } 1167cb93a386Sopenharmony_ci}; 1168cb93a386Sopenharmony_ci 1169cb93a386Sopenharmony_ciint main(int argc, char** argv) { 1170cb93a386Sopenharmony_ci CommandLineFlags::Parse(argc, argv); 1171cb93a386Sopenharmony_ci 1172cb93a386Sopenharmony_ci initializeEventTracingForTools(); 1173cb93a386Sopenharmony_ci 1174cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_IOS) 1175cb93a386Sopenharmony_ci cd_Documents(); 1176cb93a386Sopenharmony_ci#endif 1177cb93a386Sopenharmony_ci SetupCrashHandler(); 1178cb93a386Sopenharmony_ci SkAutoGraphics ag; 1179cb93a386Sopenharmony_ci SkTaskGroup::Enabler enabled(FLAGS_threads); 1180cb93a386Sopenharmony_ci 1181cb93a386Sopenharmony_ci CommonFlags::SetCtxOptions(&grContextOpts); 1182cb93a386Sopenharmony_ci 1183cb93a386Sopenharmony_ci NanobenchShaderErrorHandler errorHandler; 1184cb93a386Sopenharmony_ci grContextOpts.fShaderErrorHandler = &errorHandler; 1185cb93a386Sopenharmony_ci 1186cb93a386Sopenharmony_ci if (kAutoTuneLoops != FLAGS_loops) { 1187cb93a386Sopenharmony_ci FLAGS_samples = 1; 1188cb93a386Sopenharmony_ci FLAGS_gpuFrameLag = 0; 1189cb93a386Sopenharmony_ci } 1190cb93a386Sopenharmony_ci 1191cb93a386Sopenharmony_ci if (!FLAGS_writePath.isEmpty()) { 1192cb93a386Sopenharmony_ci SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]); 1193cb93a386Sopenharmony_ci if (!sk_mkdir(FLAGS_writePath[0])) { 1194cb93a386Sopenharmony_ci SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_writePath[0]); 1195cb93a386Sopenharmony_ci FLAGS_writePath.set(0, nullptr); 1196cb93a386Sopenharmony_ci } 1197cb93a386Sopenharmony_ci } 1198cb93a386Sopenharmony_ci 1199cb93a386Sopenharmony_ci std::unique_ptr<SkWStream> logStream(new SkNullWStream); 1200cb93a386Sopenharmony_ci if (!FLAGS_outResultsFile.isEmpty()) { 1201cb93a386Sopenharmony_ci#if defined(SK_RELEASE) 1202cb93a386Sopenharmony_ci logStream.reset(new SkFILEWStream(FLAGS_outResultsFile[0])); 1203cb93a386Sopenharmony_ci#else 1204cb93a386Sopenharmony_ci SkDebugf("I'm ignoring --outResultsFile because this is a Debug build."); 1205cb93a386Sopenharmony_ci return 1; 1206cb93a386Sopenharmony_ci#endif 1207cb93a386Sopenharmony_ci } 1208cb93a386Sopenharmony_ci NanoJSONResultsWriter log(logStream.get(), SkJSONWriter::Mode::kPretty); 1209cb93a386Sopenharmony_ci log.beginObject(); // root 1210cb93a386Sopenharmony_ci 1211cb93a386Sopenharmony_ci if (1 == FLAGS_properties.count() % 2) { 1212cb93a386Sopenharmony_ci SkDebugf("ERROR: --properties must be passed with an even number of arguments.\n"); 1213cb93a386Sopenharmony_ci return 1; 1214cb93a386Sopenharmony_ci } 1215cb93a386Sopenharmony_ci for (int i = 1; i < FLAGS_properties.count(); i += 2) { 1216cb93a386Sopenharmony_ci log.appendString(FLAGS_properties[i-1], FLAGS_properties[i]); 1217cb93a386Sopenharmony_ci } 1218cb93a386Sopenharmony_ci 1219cb93a386Sopenharmony_ci if (1 == FLAGS_key.count() % 2) { 1220cb93a386Sopenharmony_ci SkDebugf("ERROR: --key must be passed with an even number of arguments.\n"); 1221cb93a386Sopenharmony_ci return 1; 1222cb93a386Sopenharmony_ci } 1223cb93a386Sopenharmony_ci if (FLAGS_key.count()) { 1224cb93a386Sopenharmony_ci log.beginObject("key"); 1225cb93a386Sopenharmony_ci for (int i = 1; i < FLAGS_key.count(); i += 2) { 1226cb93a386Sopenharmony_ci log.appendString(FLAGS_key[i - 1], FLAGS_key[i]); 1227cb93a386Sopenharmony_ci } 1228cb93a386Sopenharmony_ci log.endObject(); // key 1229cb93a386Sopenharmony_ci } 1230cb93a386Sopenharmony_ci 1231cb93a386Sopenharmony_ci const double overhead = estimate_timer_overhead(); 1232cb93a386Sopenharmony_ci SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead)); 1233cb93a386Sopenharmony_ci 1234cb93a386Sopenharmony_ci SkTArray<double> samples; 1235cb93a386Sopenharmony_ci 1236cb93a386Sopenharmony_ci if (kAutoTuneLoops != FLAGS_loops) { 1237cb93a386Sopenharmony_ci SkDebugf("Fixed number of loops; times would only be misleading so we won't print them.\n"); 1238cb93a386Sopenharmony_ci } else if (FLAGS_quiet) { 1239cb93a386Sopenharmony_ci SkDebugf("! -> high variance, ? -> moderate variance\n"); 1240cb93a386Sopenharmony_ci SkDebugf(" micros \tbench\n"); 1241cb93a386Sopenharmony_ci } else if (FLAGS_ms) { 1242cb93a386Sopenharmony_ci SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\n"); 1243cb93a386Sopenharmony_ci } else { 1244cb93a386Sopenharmony_ci SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n", 1245cb93a386Sopenharmony_ci FLAGS_samples, "samples"); 1246cb93a386Sopenharmony_ci } 1247cb93a386Sopenharmony_ci 1248cb93a386Sopenharmony_ci GrRecordingContextPriv::DMSAAStats combinedDMSAAStats; 1249cb93a386Sopenharmony_ci 1250cb93a386Sopenharmony_ci SkTArray<Config> configs; 1251cb93a386Sopenharmony_ci create_configs(&configs); 1252cb93a386Sopenharmony_ci 1253cb93a386Sopenharmony_ci if (FLAGS_keepAlive) { 1254cb93a386Sopenharmony_ci start_keepalive(); 1255cb93a386Sopenharmony_ci } 1256cb93a386Sopenharmony_ci 1257cb93a386Sopenharmony_ci CommonFlags::SetAnalyticAA(); 1258cb93a386Sopenharmony_ci 1259cb93a386Sopenharmony_ci gSkForceRasterPipelineBlitter = FLAGS_forceRasterPipelineHP || FLAGS_forceRasterPipeline; 1260cb93a386Sopenharmony_ci gForceHighPrecisionRasterPipeline = FLAGS_forceRasterPipelineHP; 1261cb93a386Sopenharmony_ci gUseSkVMBlitter = FLAGS_skvm; 1262cb93a386Sopenharmony_ci gSkVMAllowJIT = FLAGS_jit; 1263cb93a386Sopenharmony_ci gSkVMJITViaDylib = FLAGS_dylib; 1264cb93a386Sopenharmony_ci 1265cb93a386Sopenharmony_ci int runs = 0; 1266cb93a386Sopenharmony_ci BenchmarkStream benchStream; 1267cb93a386Sopenharmony_ci log.beginObject("results"); 1268cb93a386Sopenharmony_ci AutoreleasePool pool; 1269cb93a386Sopenharmony_ci while (Benchmark* b = benchStream.next()) { 1270cb93a386Sopenharmony_ci std::unique_ptr<Benchmark> bench(b); 1271cb93a386Sopenharmony_ci if (CommandLineFlags::ShouldSkip(FLAGS_match, bench->getUniqueName())) { 1272cb93a386Sopenharmony_ci continue; 1273cb93a386Sopenharmony_ci } 1274cb93a386Sopenharmony_ci 1275cb93a386Sopenharmony_ci if (!configs.empty()) { 1276cb93a386Sopenharmony_ci log.beginBench(bench->getUniqueName(), bench->getSize().fX, bench->getSize().fY); 1277cb93a386Sopenharmony_ci bench->delayedSetup(); 1278cb93a386Sopenharmony_ci } 1279cb93a386Sopenharmony_ci for (int i = 0; i < configs.count(); ++i) { 1280cb93a386Sopenharmony_ci Target* target = is_enabled(b, configs[i]); 1281cb93a386Sopenharmony_ci if (!target) { 1282cb93a386Sopenharmony_ci continue; 1283cb93a386Sopenharmony_ci } 1284cb93a386Sopenharmony_ci 1285cb93a386Sopenharmony_ci // During HWUI output this canvas may be nullptr. 1286cb93a386Sopenharmony_ci SkCanvas* canvas = target->getCanvas(); 1287cb93a386Sopenharmony_ci const char* config = target->config.name.c_str(); 1288cb93a386Sopenharmony_ci 1289cb93a386Sopenharmony_ci if (FLAGS_pre_log || FLAGS_dryRun) { 1290cb93a386Sopenharmony_ci SkDebugf("Running %s\t%s\n" 1291cb93a386Sopenharmony_ci , bench->getUniqueName() 1292cb93a386Sopenharmony_ci , config); 1293cb93a386Sopenharmony_ci if (FLAGS_dryRun) { 1294cb93a386Sopenharmony_ci continue; 1295cb93a386Sopenharmony_ci } 1296cb93a386Sopenharmony_ci } 1297cb93a386Sopenharmony_ci 1298cb93a386Sopenharmony_ci if (FLAGS_purgeBetweenBenches) { 1299cb93a386Sopenharmony_ci SkGraphics::PurgeAllCaches(); 1300cb93a386Sopenharmony_ci } 1301cb93a386Sopenharmony_ci 1302cb93a386Sopenharmony_ci TRACE_EVENT2("skia", "Benchmark", "name", TRACE_STR_COPY(bench->getUniqueName()), 1303cb93a386Sopenharmony_ci "config", TRACE_STR_COPY(config)); 1304cb93a386Sopenharmony_ci 1305cb93a386Sopenharmony_ci target->setup(); 1306cb93a386Sopenharmony_ci bench->perCanvasPreDraw(canvas); 1307cb93a386Sopenharmony_ci 1308cb93a386Sopenharmony_ci int maxFrameLag; 1309cb93a386Sopenharmony_ci int loops = target->needsFrameTiming(&maxFrameLag) 1310cb93a386Sopenharmony_ci ? setup_gpu_bench(target, bench.get(), maxFrameLag) 1311cb93a386Sopenharmony_ci : setup_cpu_bench(overhead, target, bench.get()); 1312cb93a386Sopenharmony_ci 1313cb93a386Sopenharmony_ci if (kFailedLoops == loops) { 1314cb93a386Sopenharmony_ci // Can't be timed. A warning note has already been printed. 1315cb93a386Sopenharmony_ci cleanup_run(target); 1316cb93a386Sopenharmony_ci continue; 1317cb93a386Sopenharmony_ci } 1318cb93a386Sopenharmony_ci 1319cb93a386Sopenharmony_ci if (runs == 0 && FLAGS_ms < 1000) { 1320cb93a386Sopenharmony_ci // Run the first bench for 1000ms to warm up the nanobench if FLAGS_ms < 1000. 1321cb93a386Sopenharmony_ci // Otherwise, the first few benches' measurements will be inaccurate. 1322cb93a386Sopenharmony_ci auto stop = now_ms() + 1000; 1323cb93a386Sopenharmony_ci do { 1324cb93a386Sopenharmony_ci time(loops, bench.get(), target); 1325cb93a386Sopenharmony_ci pool.drain(); 1326cb93a386Sopenharmony_ci } while (now_ms() < stop); 1327cb93a386Sopenharmony_ci } 1328cb93a386Sopenharmony_ci 1329cb93a386Sopenharmony_ci if (FLAGS_ms) { 1330cb93a386Sopenharmony_ci samples.reset(); 1331cb93a386Sopenharmony_ci auto stop = now_ms() + FLAGS_ms; 1332cb93a386Sopenharmony_ci do { 1333cb93a386Sopenharmony_ci samples.push_back(time(loops, bench.get(), target) / loops); 1334cb93a386Sopenharmony_ci pool.drain(); 1335cb93a386Sopenharmony_ci } while (now_ms() < stop); 1336cb93a386Sopenharmony_ci } else { 1337cb93a386Sopenharmony_ci samples.reset(FLAGS_samples); 1338cb93a386Sopenharmony_ci for (int s = 0; s < FLAGS_samples; s++) { 1339cb93a386Sopenharmony_ci samples[s] = time(loops, bench.get(), target) / loops; 1340cb93a386Sopenharmony_ci pool.drain(); 1341cb93a386Sopenharmony_ci } 1342cb93a386Sopenharmony_ci } 1343cb93a386Sopenharmony_ci 1344cb93a386Sopenharmony_ci // Scale each result to the benchmark's own units, time/unit. 1345cb93a386Sopenharmony_ci for (double& sample : samples) { 1346cb93a386Sopenharmony_ci sample *= (1.0 / bench->getUnits()); 1347cb93a386Sopenharmony_ci } 1348cb93a386Sopenharmony_ci 1349cb93a386Sopenharmony_ci SkTArray<SkString> keys; 1350cb93a386Sopenharmony_ci SkTArray<double> values; 1351cb93a386Sopenharmony_ci if (configs[i].backend == Benchmark::kGPU_Backend) { 1352cb93a386Sopenharmony_ci if (FLAGS_gpuStatsDump) { 1353cb93a386Sopenharmony_ci // TODO cache stats 1354cb93a386Sopenharmony_ci bench->getGpuStats(canvas, &keys, &values); 1355cb93a386Sopenharmony_ci } 1356cb93a386Sopenharmony_ci if (FLAGS_dmsaaStatsDump && bench->getDMSAAStats(canvas->recordingContext())) { 1357cb93a386Sopenharmony_ci const auto& dmsaaStats = canvas->recordingContext()->priv().dmsaaStats(); 1358cb93a386Sopenharmony_ci dmsaaStats.dumpKeyValuePairs(&keys, &values); 1359cb93a386Sopenharmony_ci dmsaaStats.dump(); 1360cb93a386Sopenharmony_ci combinedDMSAAStats.merge(dmsaaStats); 1361cb93a386Sopenharmony_ci } 1362cb93a386Sopenharmony_ci } 1363cb93a386Sopenharmony_ci 1364cb93a386Sopenharmony_ci bench->perCanvasPostDraw(canvas); 1365cb93a386Sopenharmony_ci 1366cb93a386Sopenharmony_ci if (Benchmark::kNonRendering_Backend != target->config.backend && 1367cb93a386Sopenharmony_ci !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) { 1368cb93a386Sopenharmony_ci SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config); 1369cb93a386Sopenharmony_ci pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName()); 1370cb93a386Sopenharmony_ci pngFilename.append(".png"); 1371cb93a386Sopenharmony_ci write_canvas_png(target, pngFilename); 1372cb93a386Sopenharmony_ci } 1373cb93a386Sopenharmony_ci 1374cb93a386Sopenharmony_ci // Building stats.plot often shows up in profiles, 1375cb93a386Sopenharmony_ci // so skip building it when we're not going to print it anyway. 1376cb93a386Sopenharmony_ci const bool want_plot = !FLAGS_quiet && !FLAGS_ms; 1377cb93a386Sopenharmony_ci 1378cb93a386Sopenharmony_ci Stats stats(samples, want_plot); 1379cb93a386Sopenharmony_ci log.beginObject(config); 1380cb93a386Sopenharmony_ci 1381cb93a386Sopenharmony_ci log.beginObject("options"); 1382cb93a386Sopenharmony_ci log.appendString("name", bench->getName()); 1383cb93a386Sopenharmony_ci benchStream.fillCurrentOptions(log); 1384cb93a386Sopenharmony_ci log.endObject(); // options 1385cb93a386Sopenharmony_ci 1386cb93a386Sopenharmony_ci // Metrics 1387cb93a386Sopenharmony_ci log.appendMetric("min_ms", stats.min); 1388cb93a386Sopenharmony_ci log.appendMetric("min_ratio", sk_ieee_double_divide(stats.median, stats.min)); 1389cb93a386Sopenharmony_ci log.beginArray("samples"); 1390cb93a386Sopenharmony_ci for (double sample : samples) { 1391cb93a386Sopenharmony_ci log.appendDoubleDigits(sample, 16); 1392cb93a386Sopenharmony_ci } 1393cb93a386Sopenharmony_ci log.endArray(); // samples 1394cb93a386Sopenharmony_ci benchStream.fillCurrentMetrics(log); 1395cb93a386Sopenharmony_ci if (!keys.empty()) { 1396cb93a386Sopenharmony_ci // dump to json, only SKPBench currently returns valid keys / values 1397cb93a386Sopenharmony_ci SkASSERT(keys.count() == values.count()); 1398cb93a386Sopenharmony_ci for (int j = 0; j < keys.count(); j++) { 1399cb93a386Sopenharmony_ci log.appendMetric(keys[j].c_str(), values[j]); 1400cb93a386Sopenharmony_ci } 1401cb93a386Sopenharmony_ci } 1402cb93a386Sopenharmony_ci 1403cb93a386Sopenharmony_ci log.endObject(); // config 1404cb93a386Sopenharmony_ci 1405cb93a386Sopenharmony_ci if (runs++ % FLAGS_flushEvery == 0) { 1406cb93a386Sopenharmony_ci log.flush(); 1407cb93a386Sopenharmony_ci } 1408cb93a386Sopenharmony_ci 1409cb93a386Sopenharmony_ci if (kAutoTuneLoops != FLAGS_loops) { 1410cb93a386Sopenharmony_ci if (configs.count() == 1) { 1411cb93a386Sopenharmony_ci config = ""; // Only print the config if we run the same bench on more than one. 1412cb93a386Sopenharmony_ci } 1413cb93a386Sopenharmony_ci SkDebugf("%4d/%-4dMB\t%s\t%s\n" 1414cb93a386Sopenharmony_ci , sk_tools::getCurrResidentSetSizeMB() 1415cb93a386Sopenharmony_ci , sk_tools::getMaxResidentSetSizeMB() 1416cb93a386Sopenharmony_ci , bench->getUniqueName() 1417cb93a386Sopenharmony_ci , config); 1418cb93a386Sopenharmony_ci } else if (FLAGS_quiet) { 1419cb93a386Sopenharmony_ci const char* mark = " "; 1420cb93a386Sopenharmony_ci const double stddev_percent = 1421cb93a386Sopenharmony_ci sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean); 1422cb93a386Sopenharmony_ci if (stddev_percent > 5) mark = "?"; 1423cb93a386Sopenharmony_ci if (stddev_percent > 10) mark = "!"; 1424cb93a386Sopenharmony_ci 1425cb93a386Sopenharmony_ci SkDebugf("%10.2f %s\t%s\t%s\n", 1426cb93a386Sopenharmony_ci stats.median*1e3, mark, bench->getUniqueName(), config); 1427cb93a386Sopenharmony_ci } else if (FLAGS_csv) { 1428cb93a386Sopenharmony_ci const double stddev_percent = 1429cb93a386Sopenharmony_ci sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean); 1430cb93a386Sopenharmony_ci SkDebugf("%g,%g,%g,%g,%g,%s,%s\n" 1431cb93a386Sopenharmony_ci , stats.min 1432cb93a386Sopenharmony_ci , stats.median 1433cb93a386Sopenharmony_ci , stats.mean 1434cb93a386Sopenharmony_ci , stats.max 1435cb93a386Sopenharmony_ci , stddev_percent 1436cb93a386Sopenharmony_ci , config 1437cb93a386Sopenharmony_ci , bench->getUniqueName() 1438cb93a386Sopenharmony_ci ); 1439cb93a386Sopenharmony_ci } else { 1440cb93a386Sopenharmony_ci const char* format = "%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"; 1441cb93a386Sopenharmony_ci const double stddev_percent = 1442cb93a386Sopenharmony_ci sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean); 1443cb93a386Sopenharmony_ci SkDebugf(format 1444cb93a386Sopenharmony_ci , sk_tools::getCurrResidentSetSizeMB() 1445cb93a386Sopenharmony_ci , sk_tools::getMaxResidentSetSizeMB() 1446cb93a386Sopenharmony_ci , loops 1447cb93a386Sopenharmony_ci , HUMANIZE(stats.min) 1448cb93a386Sopenharmony_ci , HUMANIZE(stats.median) 1449cb93a386Sopenharmony_ci , HUMANIZE(stats.mean) 1450cb93a386Sopenharmony_ci , HUMANIZE(stats.max) 1451cb93a386Sopenharmony_ci , stddev_percent 1452cb93a386Sopenharmony_ci , FLAGS_ms ? to_string(samples.count()).c_str() : stats.plot.c_str() 1453cb93a386Sopenharmony_ci , config 1454cb93a386Sopenharmony_ci , bench->getUniqueName() 1455cb93a386Sopenharmony_ci ); 1456cb93a386Sopenharmony_ci } 1457cb93a386Sopenharmony_ci 1458cb93a386Sopenharmony_ci if (FLAGS_gpuStats && Benchmark::kGPU_Backend == configs[i].backend) { 1459cb93a386Sopenharmony_ci target->dumpStats(); 1460cb93a386Sopenharmony_ci } 1461cb93a386Sopenharmony_ci 1462cb93a386Sopenharmony_ci if (FLAGS_verbose) { 1463cb93a386Sopenharmony_ci SkDebugf("Samples: "); 1464cb93a386Sopenharmony_ci for (int j = 0; j < samples.count(); j++) { 1465cb93a386Sopenharmony_ci SkDebugf("%s ", HUMANIZE(samples[j])); 1466cb93a386Sopenharmony_ci } 1467cb93a386Sopenharmony_ci SkDebugf("%s\n", bench->getUniqueName()); 1468cb93a386Sopenharmony_ci } 1469cb93a386Sopenharmony_ci cleanup_run(target); 1470cb93a386Sopenharmony_ci pool.drain(); 1471cb93a386Sopenharmony_ci } 1472cb93a386Sopenharmony_ci if (!configs.empty()) { 1473cb93a386Sopenharmony_ci log.endBench(); 1474cb93a386Sopenharmony_ci } 1475cb93a386Sopenharmony_ci } 1476cb93a386Sopenharmony_ci 1477cb93a386Sopenharmony_ci if (FLAGS_dmsaaStatsDump) { 1478cb93a386Sopenharmony_ci SkDebugf("<<Total Combined DMSAA Stats>>\n"); 1479cb93a386Sopenharmony_ci combinedDMSAAStats.dump(); 1480cb93a386Sopenharmony_ci } 1481cb93a386Sopenharmony_ci 1482cb93a386Sopenharmony_ci SkGraphics::PurgeAllCaches(); 1483cb93a386Sopenharmony_ci 1484cb93a386Sopenharmony_ci log.beginBench("memory_usage", 0, 0); 1485cb93a386Sopenharmony_ci log.beginObject("meta"); // config 1486cb93a386Sopenharmony_ci log.appendS32("max_rss_mb", sk_tools::getMaxResidentSetSizeMB()); 1487cb93a386Sopenharmony_ci log.endObject(); // config 1488cb93a386Sopenharmony_ci log.endBench(); 1489cb93a386Sopenharmony_ci 1490cb93a386Sopenharmony_ci RunSkSLMemoryBenchmarks(&log); 1491cb93a386Sopenharmony_ci 1492cb93a386Sopenharmony_ci log.endObject(); // results 1493cb93a386Sopenharmony_ci log.endObject(); // root 1494cb93a386Sopenharmony_ci log.flush(); 1495cb93a386Sopenharmony_ci 1496cb93a386Sopenharmony_ci return 0; 1497cb93a386Sopenharmony_ci} 1498