nanobench.cpp 55 KB

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