Flutter Engine
The Flutter Engine
Classes | Macros | Functions | Variables
nanobench.cpp File Reference
#include <ctype.h>
#include "bench/nanobench.h"
#include "bench/AndroidCodecBench.h"
#include "bench/Benchmark.h"
#include "bench/CodecBench.h"
#include "bench/CodecBenchPriv.h"
#include "bench/GMBench.h"
#include "bench/MSKPBench.h"
#include "bench/RecordingBench.h"
#include "bench/ResultsWriter.h"
#include "bench/SKPAnimationBench.h"
#include "bench/SKPBench.h"
#include "bench/SkGlyphCacheBench.h"
#include "bench/SkSLBench.h"
#include "include/codec/SkAndroidCodec.h"
#include "include/codec/SkCodec.h"
#include "include/codec/SkJpegDecoder.h"
#include "include/codec/SkPngDecoder.h"
#include "include/core/SkBBHFactory.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkData.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/encode/SkPngEncoder.h"
#include "include/private/base/SkMacros.h"
#include "src/base/SkAutoMalloc.h"
#include "src/base/SkLeanWindows.h"
#include "src/base/SkTime.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkOSFile.h"
#include "src/core/SkTaskGroup.h"
#include "src/core/SkTraceEvent.h"
#include "src/utils/SkJSONWriter.h"
#include "src/utils/SkOSPath.h"
#include "src/utils/SkShaderUtils.h"
#include "tools/AutoreleasePool.h"
#include "tools/CrashHandler.h"
#include "tools/MSKPPlayer.h"
#include "tools/ProcStats.h"
#include "tools/Stats.h"
#include "tools/ToolUtils.h"
#include "tools/flags/CommonFlags.h"
#include "tools/flags/CommonFlagsConfig.h"
#include "tools/fonts/FontToolUtils.h"
#include "tools/ios_utils.h"
#include "tools/trace/EventTracingPriv.h"
#include "tools/trace/SkDebugfTracer.h"
#include <cinttypes>
#include <memory>
#include <optional>
#include <stdlib.h>
#include <thread>
#include <unistd.h>
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#include "src/gpu/ganesh/SkGr.h"
#include "tools/gpu/GrContextFactory.h"

Go to the source code of this file.

Classes

struct  GPUTarget
 
class  BenchmarkStream
 
class  NanobenchShaderErrorHandler
 

Macros

#define HUMANIZE(ms)   humanize(ms).c_str()
 
#define kBogusContextType   skgpu::ContextType::kGL
 
#define kBogusContextOverrides   GrContextFactory::ContextOverrides::kNone
 
#define CPU_CONFIG(name, backend, color, alpha)
 

Functions

static SkString loops_help_txt ()
 
static SkString to_string (int n)
 
static DEFINE_int (loops, kAutoTuneLoops, loops_help_txt().c_str())
 
static DEFINE_int (samples, 10, "Number of samples to measure for each bench.")
 
static DEFINE_int (ms, 0, "If >0, run each bench for this many ms instead of obeying --samples.")
 
static DEFINE_int (overheadLoops, 100000, "Loops to estimate timer overhead.")
 
static DEFINE_double (overheadGoal, 0.0001, "Loop until timer overhead is at most this fraction of our measurments.")
 
static DEFINE_double (gpuMs, 5, "Target bench time in millseconds for GPU.")
 
static DEFINE_int (gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag.")
 
static DEFINE_string (outResultsFile, "", "If given, write results here as JSON.")
 
static DEFINE_int (maxCalibrationAttempts, 3, "Try up to this many times to guess loops for a bench, or skip the bench.")
 
static DEFINE_int (maxLoops, 1000000, "Never run a bench more times than this.")
 
static DEFINE_string (clip, "0,0,1000,1000", "Clip for SKPs.")
 
static DEFINE_string (scales, "1.0", "Space-separated scales for SKPs.")
 
static DEFINE_string (zoom, "1.0,0", "Comma-separated zoomMax,zoomPeriodMs factors for a periodic SKP zoom " "function that ping-pongs between 1.0 and zoomMax.")
 
static DEFINE_bool (bbh, true, "Build a BBH for SKPs?")
 
static DEFINE_bool (loopSKP, true, "Loop SKPs like we do for micro benches?")
 
static DEFINE_int (flushEvery, 10, "Flush --outResultsFile every Nth run.")
 
static DEFINE_bool (gpuStats, false, "Print GPU stats after each gpu benchmark?")
 
static DEFINE_bool (gpuStatsDump, false, "Dump GPU stats after each benchmark to json")
 
static DEFINE_bool (dmsaaStatsDump, false, "Dump DMSAA stats after each benchmark to json")
 
static DEFINE_bool (keepAlive, false, "Print a message every so often so that we don't time out")
 
static DEFINE_bool (csv, false, "Print status in CSV format")
 
static DEFINE_string (sourceType, "", "Apply usual --match rules to source type: bench, gm, skp, image, etc.")
 
static DEFINE_string (benchType, "", "Apply usual --match rules to bench type: micro, recording, " "piping, playback, skcodec, etc.")
 
static DEFINE_bool (forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter")
 
static DEFINE_bool (forceRasterPipelineHP, false, "sets gSkForceRasterPipelineBlitter and gForceHighPrecisionRasterPipeline")
 
static DEFINE_bool2 (pre_log, p, false, "Log before running each test. May be incomprehensible when threading")
 
static DEFINE_bool (cpu, true, "Run CPU-bound work?")
 
static DEFINE_bool (gpu, true, "Run GPU-bound work?")
 
static DEFINE_bool (dryRun, false, "just print the tests that would be run, without actually running them.")
 
static DEFINE_string (images, "", "List of images and/or directories to decode. A directory with no images" " is treated as a fatal error.")
 
static DEFINE_bool (simpleCodec, false, "Runs of a subset of the codec tests, always N32, Premul or Opaque")
 
static DEFINE_string2 (match, m, nullptr, "[~][^]substring[$] [...] of name to run.\n" "Multiple matches may be separated by spaces.\n" "~ causes a matching name to always be skipped\n" "^ requires the start of the name to match\n" "$ requires the end of the name to match\n" "^ and $ requires an exact match\n" "If a name does not match any list entry,\n" "it is skipped unless some list entry starts with ~")
 
static DEFINE_bool2 (quiet, q, false, "if true, don't print status updates.")
 
static DEFINE_bool2 (verbose, v, false, "enable verbose output from the test driver.")
 
static DEFINE_string (skps, "skps", "Directory to read skps from.")
 
static DEFINE_string (mskps, "mskps", "Directory to read mskps from.")
 
static DEFINE_string (svgs, "", "Directory to read SVGs from, or a single SVG file.")
 
static DEFINE_string (texttraces, "", "Directory to read TextBlobTrace files from.")
 
static DEFINE_int_2 (threads, j, -1, "Run threadsafe tests on a threadpool with this many extra threads, " "defaulting to one extra thread per core.")
 
static DEFINE_string2 (writePath, w, "", "If set, write bitmaps here as .pngs.")
 
static DEFINE_string (key, "", "Space-separated key/value pairs to add to JSON identifying this builder.")
 
static DEFINE_string (properties, "", "Space-separated key/value pairs to add to JSON identifying this run.")
 
static DEFINE_bool (purgeBetweenBenches, false, "Call SkGraphics::PurgeAllCaches() between each benchmark?")
 
static DEFINE_bool (splitPerfettoTracesByBenchmark, true, "Create separate perfetto trace files for each benchmark?\n" "Will only take effect if perfetto tracing is enabled. See --trace.")
 
static DEFINE_bool (runtimeCPUDetection, true, "Skip runtime CPU detection and optimization")
 
static double now_ms ()
 
static SkString humanize (double ms)
 
static double time (int loops, Benchmark *bench, Target *target)
 
static double estimate_timer_overhead ()
 
static int detect_forever_loops (int loops)
 
static int clamp_loops (int loops)
 
static bool write_canvas_png (Target *target, const SkString &filename)
 
static int setup_cpu_bench (const double overhead, Target *target, Benchmark *bench)
 
static int setup_gpu_bench (Target *target, Benchmark *bench, int maxGpuFrameLag)
 
static std::optional< Configcreate_config (const SkCommandLineConfig *config)
 
void create_configs (TArray< Config > *configs)
 
static Targetis_enabled (Benchmark *bench, const Config &config)
 
static void cleanup_run (Target *target)
 
static void collect_files (const CommandLineFlags::StringArray &paths, const char *ext, TArray< SkString > *list)
 
static void start_keepalive ()
 
int main (int argc, char **argv)
 

Variables

bool gSkForceRasterPipelineBlitter
 
bool gForceHighPrecisionRasterPipeline
 
GrContextOptions grContextOpts
 
static const int kAutoTuneLoops = 0
 
static int kFailedLoops = -2
 

Macro Definition Documentation

◆ CPU_CONFIG

#define CPU_CONFIG (   name,
  backend,
  color,
  alpha 
)
Value:
if (config->getBackend().equals(name)) { \
if (!FLAGS_cpu) { \
SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str()); \
return std::nullopt; \
} \
return Config{SkString(name), \
color, \
alpha, \
config->refColorSpace(), \
0, \
kBogusContextType, \
kBogusContextOverrides, \
0}; \
}
const char * backend
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32

◆ HUMANIZE

#define HUMANIZE (   ms)    humanize(ms).c_str()

Definition at line 220 of file nanobench.cpp.

◆ kBogusContextOverrides

#define kBogusContextOverrides   GrContextFactory::ContextOverrides::kNone

Definition at line 558 of file nanobench.cpp.

◆ kBogusContextType

#define kBogusContextType   skgpu::ContextType::kGL

Definition at line 557 of file nanobench.cpp.

Function Documentation

◆ clamp_loops()

static int clamp_loops ( int  loops)
static

Definition at line 428 of file nanobench.cpp.

428 {
429 if (loops < 1) {
430 SkDebugf("ERROR: clamping loops from %d to 1. "
431 "There's probably something wrong with the bench.\n", loops);
432 return 1;
433 }
434 if (loops > FLAGS_maxLoops) {
435 SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops);
436 return FLAGS_maxLoops;
437 }
438 return loops;
439}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1

◆ cleanup_run()

static void cleanup_run ( Target target)
static

Definition at line 772 of file nanobench.cpp.

772 {
773 delete target;
774}
uint32_t * target

◆ collect_files()

static void collect_files ( const CommandLineFlags::StringArray paths,
const char *  ext,
TArray< SkString > *  list 
)
static

Definition at line 776 of file nanobench.cpp.

778 {
779 for (int i = 0; i < paths.size(); ++i) {
780 if (SkStrEndsWith(paths[i], ext)) {
781 list->push_back(SkString(paths[i]));
782 } else {
783 SkOSFile::Iter it(paths[i], ext);
785 while (it.next(&path)) {
786 list->push_back(SkOSPath::Join(paths[i], path.c_str()));
787 }
788 }
789 }
790}
bool SkStrEndsWith(const char string[], const char suffixStr[])
Definition: SkString.cpp:68
static SkString Join(const char *rootPath, const char *relativePath)
Definition: SkOSPath.cpp:14
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57

◆ create_config()

static std::optional< Config > create_config ( const SkCommandLineConfig config)
static

Definition at line 560 of file nanobench.cpp.

560 {
561 if (const auto* gpuConfig = config->asConfigGpu()) {
562 if (!FLAGS_gpu) {
563 SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str());
564 return std::nullopt;
565 }
566
567 const auto ctxType = gpuConfig->getContextType();
568 const auto ctxOverrides = gpuConfig->getContextOverrides();
569 const auto sampleCount = gpuConfig->getSamples();
570 const auto colorType = gpuConfig->getColorType();
571 if (gpuConfig->getSurfType() != SkCommandLineConfigGpu::SurfType::kDefault) {
572 SkDebugf("This tool only supports the default surface type.");
573 return std::nullopt;
574 }
575
577 if (const auto ctx = factory.get(ctxType, ctxOverrides)) {
578 GrBackendFormat format = ctx->defaultBackendFormat(colorType, GrRenderable::kYes);
579 int supportedSampleCount =
580 ctx->priv().caps()->getRenderTargetSampleCount(sampleCount, format);
581 if (sampleCount != supportedSampleCount) {
582 SkDebugf("Configuration '%s' sample count %d is not a supported sample count.\n",
583 config->getTag().c_str(),
584 sampleCount);
585 return std::nullopt;
586 }
587 } else {
588 SkDebugf("No context was available matching config '%s'.\n", config->getTag().c_str());
589 return std::nullopt;
590 }
591
592 return Config{gpuConfig->getTag(),
594 colorType,
596 config->refColorSpace(),
597 sampleCount,
598 ctxType,
599 ctxOverrides,
600 gpuConfig->getSurfaceFlags()};
601 }
602#if defined(SK_GRAPHITE)
603 if (const auto* gpuConfig = config->asConfigGraphite()) {
604 if (!FLAGS_gpu) {
605 SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str());
606 return std::nullopt;
607 }
608
609 const auto graphiteCtxType = gpuConfig->getContextType();
610 const auto sampleCount = 1; // TODO: gpuConfig->getSamples();
611 const auto colorType = gpuConfig->getColorType();
612
613 using ContextFactory = skiatest::graphite::ContextFactory;
614
615 ContextFactory factory(gpuConfig->asConfigGraphite()->getOptions());
616 skiatest::graphite::ContextInfo ctxInfo = factory.getContextInfo(graphiteCtxType);
617 skgpu::graphite::Context* ctx = ctxInfo.fContext;
618 if (ctx) {
619 // TODO: Add graphite ctx queries for supported sample count by color type.
620#if 0
621 GrBackendFormat format = ctx->defaultBackendFormat(colorType, GrRenderable::kYes);
622 int supportedSampleCount =
623 ctx->priv().caps()->getRenderTargetSampleCount(sampleCount, format);
624 if (sampleCount != supportedSampleCount) {
625 SkDebugf("Configuration '%s' sample count %d is not a supported sample count.\n",
626 config->getTag().c_str(),
627 sampleCount);
628 return std::nullopt;
629 }
630#else
631 if (sampleCount > 1) {
632 SkDebugf("Configuration '%s' sample count %d is not a supported sample count.\n",
633 config->getTag().c_str(),
634 sampleCount);
635 return std::nullopt;
636 }
637#endif
638 } else {
639 SkDebugf("No context was available matching config '%s'.\n", config->getTag().c_str());
640 return std::nullopt;
641 }
642
643 return Config{gpuConfig->getTag(),
645 colorType,
647 config->refColorSpace(),
648 sampleCount,
649 graphiteCtxType,
651 0};
652 }
653#endif
654
655#define CPU_CONFIG(name, backend, color, alpha) \
656 if (config->getBackend().equals(name)) { \
657 if (!FLAGS_cpu) { \
658 SkDebugf("Skipping config '%s' as requested.\n", config->getTag().c_str()); \
659 return std::nullopt; \
660 } \
661 return Config{SkString(name), \
662 Benchmark::backend, \
663 color, \
664 alpha, \
665 config->refColorSpace(), \
666 0, \
667 kBogusContextType, \
668 kBogusContextOverrides, \
669 0}; \
670 }
671
672 CPU_CONFIG("nonrendering", Backend::kNonRendering, kUnknown_SkColorType, kUnpremul_SkAlphaType)
673
676 CPU_CONFIG("8888", Backend::kRaster, kN32_SkColorType, kPremul_SkAlphaType)
681
682#undef CPU_CONFIG
683
684 SkDebugf("Unknown config '%s'.\n", config->getTag().c_str());
685 return std::nullopt;
686}
kUnpremul_SkAlphaType
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kSRGBA_8888_SkColorType
Definition: SkColorType.h:53
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
sk_sp< SkColorSpace > refColorSpace() const
const SkString & getTag() const
virtual const SkCommandLineConfigGpu * asConfigGpu() const
virtual const SkCommandLineConfigGraphite * asConfigGraphite() const
const char * c_str() const
Definition: SkString.h:133
const Caps * caps() const
Definition: ContextPriv.h:32
@ kRaster
Suitable for thread which raster data.
Definition: embedder.h:266
uint32_t uint32_t * format
#define kBogusContextOverrides
Definition: nanobench.cpp:558
#define CPU_CONFIG(name, backend, color, alpha)
GrContextOptions grContextOpts
Definition: nanobench.cpp:107
skgpu::graphite::Context * fContext

◆ create_configs()

void create_configs ( TArray< Config > *  configs)

Definition at line 689 of file nanobench.cpp.

689 {
691 ParseConfigs(FLAGS_config, &array);
692 for (int i = 0; i < array.size(); ++i) {
693 if (std::optional<Config> config = create_config(array[i].get())) {
694 configs->push_back(*config);
695 }
696 }
697
698 // If no just default configs were requested, then we're okay.
699 if (array.size() == 0 || FLAGS_config.size() == 0 ||
700 // Otherwise, make sure that all specified configs have been created.
701 array.size() == configs->size()) {
702 return;
703 }
704 exit(1);
705}
void ParseConfigs(const CommandLineFlags::StringArray &configs, SkCommandLineConfigArray *outResult)
int size() const
Definition: SkTArray.h:421
exit(kErrorExitCode)
const myers::Point & get(const myers::Segment &)
static std::optional< Config > create_config(const SkCommandLineConfig *config)
Definition: nanobench.cpp:560

◆ DEFINE_bool() [1/16]

static DEFINE_bool ( bbh  ,
true  ,
"Build a BBH for SKPs?"   
)
static

◆ DEFINE_bool() [2/16]

static DEFINE_bool ( cpu  ,
true  ,
"Run CPU-bound work?"   
)
static

◆ DEFINE_bool() [3/16]

static DEFINE_bool ( csv  ,
false  ,
"Print status in CSV format  
)
static

◆ DEFINE_bool() [4/16]

static DEFINE_bool ( dmsaaStatsDump  ,
false  ,
"Dump DMSAA stats after each benchmark to json"   
)
static

◆ DEFINE_bool() [5/16]

static DEFINE_bool ( dryRun  ,
false  ,
"just print the tests that would be  run,
without actually running them."   
)
static

◆ DEFINE_bool() [6/16]

static DEFINE_bool ( forceRasterPipeline  ,
false  ,
"sets gSkForceRasterPipelineBlitter  
)
static

◆ DEFINE_bool() [7/16]

static DEFINE_bool ( forceRasterPipelineHP  ,
false  ,
"sets gSkForceRasterPipelineBlitter and gForceHighPrecisionRasterPipeline  
)
static

◆ DEFINE_bool() [8/16]

static DEFINE_bool ( gpu  ,
true  ,
"Run GPU-bound work?"   
)
static

◆ DEFINE_bool() [9/16]

static DEFINE_bool ( gpuStats  ,
false  ,
"Print GPU stats after each gpu benchmark?"   
)
static

◆ DEFINE_bool() [10/16]

static DEFINE_bool ( gpuStatsDump  ,
false  ,
"Dump GPU stats after each benchmark to json"   
)
static

◆ DEFINE_bool() [11/16]

static DEFINE_bool ( keepAlive  ,
false  ,
"Print a message every so often so that we don't time out"   
)
static

◆ DEFINE_bool() [12/16]

static DEFINE_bool ( loopSKP  ,
true  ,
"Loop SKPs like we do for micro benches?"   
)
static

◆ DEFINE_bool() [13/16]

static DEFINE_bool ( purgeBetweenBenches  ,
false  ,
"Call SkGraphics::PurgeAllCaches() between each benchmark?"   
)
static

◆ DEFINE_bool() [14/16]

static DEFINE_bool ( runtimeCPUDetection  ,
true  ,
"Skip runtime CPU detection and optimization"   
)
static

◆ DEFINE_bool() [15/16]

static DEFINE_bool ( simpleCodec  ,
false  ,
"Runs of a subset of the codec  tests,
always  N32,
Premul or Opaque"   
)
static

◆ DEFINE_bool() [16/16]

static DEFINE_bool ( splitPerfettoTracesByBenchmark  ,
true  ,
"Create separate perfetto trace files for each benchmark?\n" "Will only take effect if perfetto tracing is enabled. See --trace."   
)
static

◆ DEFINE_bool2() [1/3]

static DEFINE_bool2 ( pre_log  ,
,
false  ,
"Log before running each test. May be incomprehensible when threading"   
)
static

◆ DEFINE_bool2() [2/3]

static DEFINE_bool2 ( quiet  ,
,
false  ,
"if  true,
don 't print status updates."   
)
static

◆ DEFINE_bool2() [3/3]

static DEFINE_bool2 ( verbose  ,
,
false  ,
"enable verbose output from the test driver."   
)
static

◆ DEFINE_double() [1/2]

static DEFINE_double ( gpuMs  ,
,
"Target bench time in millseconds for GPU."   
)
static

◆ DEFINE_double() [2/2]

static DEFINE_double ( overheadGoal  ,
0.  0001,
"Loop until timer overhead is at most this fraction of our measurments."   
)
static

◆ DEFINE_int() [1/8]

static DEFINE_int ( flushEvery  ,
10  ,
"Flush --outResultsFile every Nth run."   
)
static

◆ DEFINE_int() [2/8]

static DEFINE_int ( gpuFrameLag  ,
,
"If  unknown,
estimated maximum number of frames GPU allows to lag."   
)
static

◆ DEFINE_int() [3/8]

static DEFINE_int ( loops  ,
kAutoTuneLoops  ,
loops_help_txt().c_str()   
)
static

◆ DEFINE_int() [4/8]

static DEFINE_int ( maxCalibrationAttempts  ,
,
"Try up to this many times to guess loops for a  bench,
or skip the bench."   
)
static

◆ DEFINE_int() [5/8]

static DEFINE_int ( maxLoops  ,
1000000  ,
"Never run a bench more times than this."   
)
static

◆ DEFINE_int() [6/8]

static DEFINE_int ( ms  ,
,
If,
,
run each bench for this many ms instead of obeying --samples."   
)
static

◆ DEFINE_int() [7/8]

static DEFINE_int ( overheadLoops  ,
100000  ,
"Loops to estimate timer overhead."   
)
static

◆ DEFINE_int() [8/8]

static DEFINE_int ( samples  ,
10  ,
"Number of samples to measure for each bench."   
)
static

◆ DEFINE_int_2()

static DEFINE_int_2 ( threads  ,
,
1,
"Run threadsafe tests on a threadpool with this many extra  threads,
" "defaulting to one extra thread per core."   
)
static

◆ DEFINE_string() [1/13]

static DEFINE_string ( benchType  ,
""  ,
"Apply usual --match rules to bench type:  micro,
recording  ,
" "  piping,
playback  ,
skcodec  ,
etc."   
)
static

◆ DEFINE_string() [2/13]

static DEFINE_string ( clip  ,
0,
,
1000  ,
1000"  ,
"Clip for SKPs."   
)
static

◆ DEFINE_string() [3/13]

static DEFINE_string ( images  ,
""  ,
"List of images and/or directories to decode. A directory with no images" " is treated as a fatal error."   
)
static

◆ DEFINE_string() [4/13]

static DEFINE_string ( key  ,
""  ,
"Space-separated key/value pairs to add to JSON identifying this builder."   
)
static

◆ DEFINE_string() [5/13]

static DEFINE_string ( mskps  ,
"mskps"  ,
"Directory to read mskps from."   
)
static

◆ DEFINE_string() [6/13]

static DEFINE_string ( outResultsFile  ,
""  ,
"If  given,
write results here as JSON."   
)
static

◆ DEFINE_string() [7/13]

static DEFINE_string ( properties  ,
""  ,
"Space-separated key/value pairs to add to JSON identifying this run."   
)
static

◆ DEFINE_string() [8/13]

static DEFINE_string ( scales  ,
"1.0"  ,
"Space-separated scales for SKPs."   
)
static

◆ DEFINE_string() [9/13]

static DEFINE_string ( skps  ,
"skps"  ,
"Directory to read skps from."   
)
static

◆ DEFINE_string() [10/13]

static DEFINE_string ( sourceType  ,
""  ,
"Apply usual --match rules to source type:  bench,
gm  ,
skp  ,
image  ,
etc."   
)
static

◆ DEFINE_string() [11/13]

static DEFINE_string ( svgs  ,
""  ,
"Directory to read SVGs  from,
or a single SVG file."   
)
static

◆ DEFINE_string() [12/13]

static DEFINE_string ( texttraces  ,
""  ,
"Directory to read TextBlobTrace files from."   
)
static

◆ DEFINE_string() [13/13]

static DEFINE_string ( zoom  ,
"1.  0,
0"  ,
"Comma-separated  zoomMax,
zoomPeriodMs factors for a periodic SKP zoom " "function that ping-pongs between 1.0 and zoomMax."   
)
static

◆ DEFINE_string2() [1/2]

static DEFINE_string2 ( match  ,
,
nullptr  ,
"substring of name to run.\n" "Multiple matches may be separated by spaces.\n" "~ causes a matching name to always be skipped\n" "^ requires the start of the name to match\n" "$ requires the end of the name to match\n" "^ and $ requires an exact match\n" "If a name does not match any list  entry[~][^][$][...],
\n" "it is skipped unless some list entry starts with ~"   
)
static

◆ DEFINE_string2() [2/2]

static DEFINE_string2 ( writePath  ,
w  ,
""  ,
"If  set,
write bitmaps here as .pngs."   
)
static

◆ detect_forever_loops()

static int detect_forever_loops ( int  loops)
static

Definition at line 420 of file nanobench.cpp.

420 {
421 // look for a magic run-forever value
422 if (loops < 0) {
423 loops = SK_MaxS32;
424 }
425 return loops;
426}
static constexpr int32_t SK_MaxS32
Definition: SkMath.h:21

◆ estimate_timer_overhead()

static double estimate_timer_overhead ( )
static

Definition at line 411 of file nanobench.cpp.

411 {
412 double overhead = 0;
413 for (int i = 0; i < FLAGS_overheadLoops; i++) {
414 double start = now_ms();
415 overhead += now_ms() - start;
416 }
417 return overhead / FLAGS_overheadLoops;
418}
static double now_ms()
Definition: nanobench.cpp:214

◆ humanize()

static SkString humanize ( double  ms)
static

Definition at line 216 of file nanobench.cpp.

216 {
217 if (FLAGS_verbose) return SkStringPrintf("%" PRIu64, (uint64_t)(ms*1e6));
218 return HumanizeMs(ms);
219}
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
SkString HumanizeMs(double ms)
Definition: Timer.cpp:9

◆ is_enabled()

static Target * is_enabled ( Benchmark bench,
const Config config 
)
static

Definition at line 714 of file nanobench.cpp.

714 {
715 if (!bench->isSuitableFor(config.backend)) {
716 return nullptr;
717 }
718
720 SkImageInfo::Make(bench->getSize(), config.color, config.alpha, config.colorSpace);
721
722 Target* target = nullptr;
723
724 switch (config.backend) {
726 target = new GPUTarget(config);
727 break;
728#if defined(SK_GRAPHITE)
730 target = new GraphiteTarget(config);
731 break;
732#endif
733 default:
734 target = new Target(config);
735 break;
736 }
737
738 if (!target->init(info, bench)) {
739 delete target;
740 return nullptr;
741 }
742 return target;
743}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static void bench(NanoJSONResultsWriter *log, const char *name, int bytes)
Definition: SkSLBench.cpp:285
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)

◆ loops_help_txt()

static SkString loops_help_txt ( )
static

Definition at line 111 of file nanobench.cpp.

111 {
113 help.printf("Number of times to run each bench. Set this to %d to auto-"
114 "tune for each bench. Timings are only reported when auto-tuning.",
116 return help;
117}
help
Definition: zip.py:79
static const int kAutoTuneLoops
Definition: nanobench.cpp:109

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 1349 of file nanobench.cpp.

1349 {
1351
1353
1354#if defined(SK_BUILD_FOR_IOS)
1355 cd_Documents();
1356#endif
1358 if (FLAGS_runtimeCPUDetection) {
1360 }
1361
1362 // Our benchmarks only currently decode .png or .jpg files
1365
1366 SkTaskGroup::Enabler enabled(FLAGS_threads);
1367
1369
1370 NanobenchShaderErrorHandler errorHandler;
1371 grContextOpts.fShaderErrorHandler = &errorHandler;
1372
1373 if (kAutoTuneLoops != FLAGS_loops) {
1374 FLAGS_samples = 1;
1375 FLAGS_gpuFrameLag = 0;
1376 }
1377
1378 if (!FLAGS_writePath.isEmpty()) {
1379 SkDebugf("Writing files to %s.\n", FLAGS_writePath[0]);
1380 if (!sk_mkdir(FLAGS_writePath[0])) {
1381 SkDebugf("Could not create %s. Files won't be written.\n", FLAGS_writePath[0]);
1382 FLAGS_writePath.set(0, nullptr);
1383 }
1384 }
1385
1386 std::unique_ptr<SkWStream> logStream(new SkNullWStream);
1387 if (!FLAGS_outResultsFile.isEmpty()) {
1388#if defined(SK_RELEASE)
1389 logStream.reset(new SkFILEWStream(FLAGS_outResultsFile[0]));
1390#else
1391 SkDebugf("I'm ignoring --outResultsFile because this is a Debug build.");
1392 return 1;
1393#endif
1394 }
1396 log.beginObject(); // root
1397
1398 if (1 == FLAGS_properties.size() % 2) {
1399 SkDebugf("ERROR: --properties must be passed with an even number of arguments.\n");
1400 return 1;
1401 }
1402 for (int i = 1; i < FLAGS_properties.size(); i += 2) {
1403 log.appendCString(FLAGS_properties[i-1], FLAGS_properties[i]);
1404 }
1405
1406 if (1 == FLAGS_key.size() % 2) {
1407 SkDebugf("ERROR: --key must be passed with an even number of arguments.\n");
1408 return 1;
1409 }
1410 if (FLAGS_key.size()) {
1411 log.beginObject("key");
1412 for (int i = 1; i < FLAGS_key.size(); i += 2) {
1413 log.appendCString(FLAGS_key[i - 1], FLAGS_key[i]);
1414 }
1415 log.endObject(); // key
1416 }
1417
1418 const double overhead = estimate_timer_overhead();
1419 if (!FLAGS_quiet && !FLAGS_csv) {
1420 SkDebugf("Timer overhead: %s\n", HUMANIZE(overhead));
1421 }
1422
1423 TArray<double> samples;
1424
1425 if (kAutoTuneLoops != FLAGS_loops) {
1426 SkDebugf("Fixed number of loops; times would only be misleading so we won't print them.\n");
1427 } else if (FLAGS_quiet) {
1428 SkDebugf("! -> high variance, ? -> moderate variance\n");
1429 SkDebugf(" micros \tbench\n");
1430 } else if (FLAGS_csv) {
1431 SkDebugf("min,median,mean,max,stddev,config,bench\n");
1432 } else if (FLAGS_ms) {
1433 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\tsamples\tconfig\tbench\n");
1434 } else {
1435 SkDebugf("curr/maxrss\tloops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n",
1436 FLAGS_samples, "samples");
1437 }
1438
1439 GrRecordingContextPriv::DMSAAStats combinedDMSAAStats;
1440
1443
1444 if (FLAGS_keepAlive) {
1446 }
1447
1448 gSkForceRasterPipelineBlitter = FLAGS_forceRasterPipelineHP || FLAGS_forceRasterPipeline;
1449 gForceHighPrecisionRasterPipeline = FLAGS_forceRasterPipelineHP;
1450
1451 // The SkSL memory benchmark must run before any GPU painting occurs. SkSL allocates memory for
1452 // its modules the first time they are accessed, and this test is trying to measure the size of
1453 // those allocations. If a paint has already occurred, some modules will have already been
1454 // loaded, so we won't be able to capture a delta for them.
1455 log.beginObject("results");
1457
1458 int runs = 0;
1459 BenchmarkStream benchStream;
1461 while (Benchmark* b = benchStream.next()) {
1462 std::unique_ptr<Benchmark> bench(b);
1463 if (CommandLineFlags::ShouldSkip(FLAGS_match, bench->getUniqueName())) {
1464 continue;
1465 }
1466
1467 if (!configs.empty()) {
1468 log.beginBench(
1469 bench->getUniqueName(), bench->getSize().width(), bench->getSize().height());
1470 bench->delayedSetup();
1471 }
1472 for (int i = 0; i < configs.size(); ++i) {
1474 if (!target) {
1475 continue;
1476 }
1477
1478 // During HWUI output this canvas may be nullptr.
1479 SkCanvas* canvas = target->getCanvas();
1480 const char* config = target->config.name.c_str();
1481
1482 if (FLAGS_pre_log || FLAGS_dryRun) {
1483 SkDebugf("Running %s\t%s\n"
1484 , bench->getUniqueName()
1485 , config);
1486 if (FLAGS_dryRun) {
1487 continue;
1488 }
1489 }
1490
1491 if (FLAGS_purgeBetweenBenches) {
1493 }
1494
1495 if (FLAGS_splitPerfettoTracesByBenchmark) {
1497 }
1498 TRACE_EVENT2("skia", "Benchmark", "name", TRACE_STR_COPY(bench->getUniqueName()),
1499 "config", TRACE_STR_COPY(config));
1500
1501 target->setup();
1502 bench->perCanvasPreDraw(canvas);
1503
1504 int maxFrameLag;
1505 int loops = target->needsFrameTiming(&maxFrameLag)
1506 ? setup_gpu_bench(target, bench.get(), maxFrameLag)
1507 : setup_cpu_bench(overhead, target, bench.get());
1508
1509 if (kFailedLoops == loops) {
1510 // Can't be timed. A warning note has already been printed.
1512 continue;
1513 }
1514
1515 if (runs == 0 && FLAGS_ms < 1000) {
1516 // Run the first bench for 1000ms to warm up the nanobench if FLAGS_ms < 1000.
1517 // Otherwise, the first few benches' measurements will be inaccurate.
1518 auto stop = now_ms() + 1000;
1519 do {
1520 time(loops, bench.get(), target);
1521 pool.drain();
1522 } while (now_ms() < stop);
1523 }
1524
1525 if (FLAGS_ms) {
1526 samples.clear();
1527 auto stop = now_ms() + FLAGS_ms;
1528 do {
1529 samples.push_back(time(loops, bench.get(), target) / loops);
1530 pool.drain();
1531 } while (now_ms() < stop);
1532 } else {
1533 samples.reset(FLAGS_samples);
1534 for (int s = 0; s < FLAGS_samples; s++) {
1535 samples[s] = time(loops, bench.get(), target) / loops;
1536 pool.drain();
1537 }
1538 }
1539
1540 // Scale each result to the benchmark's own units, time/unit.
1541 for (double& sample : samples) {
1542 sample *= (1.0 / bench->getUnits());
1543 }
1544
1545 TArray<SkString> keys;
1548 if (FLAGS_gpuStatsDump) {
1549 // TODO cache stats
1550 bench->getGpuStats(canvas, &keys, &values);
1551 }
1552 if (FLAGS_dmsaaStatsDump && bench->getDMSAAStats(canvas->recordingContext())) {
1553 const auto& dmsaaStats = canvas->recordingContext()->priv().dmsaaStats();
1554 dmsaaStats.dumpKeyValuePairs(&keys, &values);
1555 dmsaaStats.dump();
1556 combinedDMSAAStats.merge(dmsaaStats);
1557 }
1558 }
1559
1560 bench->perCanvasPostDraw(canvas);
1561
1562 if (Benchmark::Backend::kNonRendering != target->config.backend &&
1563 !FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) {
1564 SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], config);
1565 pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName());
1566 pngFilename.append(".png");
1567 write_canvas_png(target, pngFilename);
1568 }
1569
1570 // Building stats.plot often shows up in profiles,
1571 // so skip building it when we're not going to print it anyway.
1572 const bool want_plot = !FLAGS_quiet && !FLAGS_ms;
1573
1574 Stats stats(samples, want_plot);
1575 log.beginObject(config);
1576
1577 log.beginObject("options");
1578 log.appendCString("name", bench->getName());
1579 benchStream.fillCurrentOptions(log);
1580 log.endObject(); // options
1581
1582 // Metrics
1583 log.appendMetric("min_ms", stats.min);
1584 log.appendMetric("min_ratio", sk_ieee_double_divide(stats.median, stats.min));
1585 log.beginArray("samples");
1586 for (double sample : samples) {
1587 log.appendDoubleDigits(sample, 16);
1588 }
1589 log.endArray(); // samples
1590 benchStream.fillCurrentMetrics(log);
1591 if (!keys.empty()) {
1592 // dump to json, only SKPBench currently returns valid keys / values
1593 SkASSERT(keys.size() == values.size());
1594 for (int j = 0; j < keys.size(); j++) {
1595 log.appendMetric(keys[j].c_str(), values[j]);
1596 }
1597 }
1598
1599 log.endObject(); // config
1600
1601 if (runs++ % FLAGS_flushEvery == 0) {
1602 log.flush();
1603 }
1604
1605 if (kAutoTuneLoops != FLAGS_loops) {
1606 if (configs.size() == 1) {
1607 config = ""; // Only print the config if we run the same bench on more than one.
1608 }
1609 SkDebugf("%4d/%-4dMB\t%s\t%s "
1612 , bench->getUniqueName()
1613 , config);
1614 SkDebugf("\n");
1615 } else if (FLAGS_quiet) {
1616 const char* mark = " ";
1617 const double stddev_percent =
1618 sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean);
1619 if (stddev_percent > 5) mark = "?";
1620 if (stddev_percent > 10) mark = "!";
1621
1622 SkDebugf("%10.2f %s\t%s\t%s\n",
1623 stats.median*1e3, mark, bench->getUniqueName(), config);
1624 } else if (FLAGS_csv) {
1625 const double stddev_percent =
1626 sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean);
1627 SkDebugf("%g,%g,%g,%g,%g,%s,%s\n"
1628 , stats.min
1629 , stats.median
1630 , stats.mean
1631 , stats.max
1632 , stddev_percent
1633 , config
1634 , bench->getUniqueName()
1635 );
1636 } else {
1637 const double stddev_percent =
1638 sk_ieee_double_divide(100 * sqrt(stats.var), stats.mean);
1639 SkDebugf("%4d/%-4dMB\t%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n"
1642 , loops
1643 , HUMANIZE(stats.min)
1644 , HUMANIZE(stats.median)
1645 , HUMANIZE(stats.mean)
1646 , HUMANIZE(stats.max)
1647 , stddev_percent
1648 , FLAGS_ms ? to_string(samples.size()).c_str() : stats.plot.c_str()
1649 , config
1650 , bench->getUniqueName()
1651 );
1652 }
1653
1654 if (FLAGS_gpuStats && Benchmark::Backend::kGanesh == configs[i].backend) {
1655 target->dumpStats();
1656 }
1657
1658 if (FLAGS_verbose) {
1659 SkDebugf("Samples: ");
1660 for (int j = 0; j < samples.size(); j++) {
1661 SkDebugf("%s ", HUMANIZE(samples[j]));
1662 }
1663 SkDebugf("%s\n", bench->getUniqueName());
1664 }
1666 pool.drain();
1667 }
1668 if (!configs.empty()) {
1669 log.endBench();
1670 }
1671 }
1672
1673 if (FLAGS_dmsaaStatsDump) {
1674 SkDebugf("<<Total Combined DMSAA Stats>>\n");
1675 combinedDMSAAStats.dump();
1676 }
1677
1679
1680 log.beginBench("memory_usage", 0, 0);
1681 log.beginObject("meta"); // config
1682 log.appendS32("max_rss_mb", sk_tools::getMaxResidentSetSizeMB());
1683 log.endObject(); // config
1684 log.endBench();
1685
1686 log.endObject(); // results
1687 log.endObject(); // root
1688 log.flush();
1689
1690 return 0;
1691}
AutoreleasePool pool
void SetupCrashHandler()
void initializeEventTracingForTools(const char *traceFlag)
GrRecordingContextPriv::DMSAAStats combinedDMSAAStats
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr double sk_ieee_double_divide(double numer, double denom)
bool sk_mkdir(const char *path)
void RunSkSLModuleBenchmarks(NanoJSONResultsWriter *log)
Definition: SkSLBench.cpp:296
#define TRACE_EVENT_API_NEW_TRACE_SECTION
Definition: SkTraceEvent.h:120
#define TRACE_STR_COPY(str)
Definition: SkTraceEvent.h:63
Benchmark * next()
Definition: nanobench.cpp:901
void fillCurrentOptions(NanoJSONResultsWriter &log) const
Definition: nanobench.cpp:1252
void fillCurrentMetrics(NanoJSONResultsWriter &log) const
Definition: nanobench.cpp:1264
static bool ShouldSkip(const SkTDArray< const char * > &strings, const char *name)
static void Parse(int argc, const char *const *argv)
GrRecordingContextPriv priv()
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
static void PurgeAllCaches()
Definition: SkGraphics.cpp:40
static void Init()
Definition: SkGraphics.cpp:22
void append(const char text[])
Definition: SkString.h:203
bool empty() const
Definition: SkTArray.h:199
void reset(int n)
Definition: SkTArray.h:144
static bool b
struct MyStruct s
static void mark(SkCanvas *canvas, SkScalar x, SkScalar y, Fn &&fn)
Definition: gm.cpp:211
void cd_Documents(void)
Definition: ios_utils.m:12
char ** argv
Definition: library.h:9
void SetCtxOptions(struct GrContextOptions *)
void SK_API Register(Decoder d)
Definition: SkCodec.cpp:135
constexpr SkCodecs::Decoder Decoder()
Definition: SkJpegDecoder.h:38
constexpr SkCodecs::Decoder Decoder()
Definition: SkPngDecoder.h:38
dictionary stats
Definition: malisc.py:20
int getCurrResidentSetSizeMB()
Definition: ProcStats.cpp:92
int getMaxResidentSetSizeMB()
Definition: ProcStats.cpp:87
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
static int kFailedLoops
Definition: nanobench.cpp:474
static Target * is_enabled(Benchmark *bench, const Config &config)
Definition: nanobench.cpp:714
void create_configs(TArray< Config > *configs)
Definition: nanobench.cpp:689
static void cleanup_run(Target *target)
Definition: nanobench.cpp:772
static int setup_gpu_bench(Target *target, Benchmark *bench, int maxGpuFrameLag)
Definition: nanobench.cpp:519
static bool write_canvas_png(Target *target, const SkString &filename)
Definition: nanobench.cpp:441
static SkString to_string(int n)
Definition: nanobench.cpp:119
static void start_keepalive()
Definition: nanobench.cpp:1324
#define HUMANIZE(ms)
Definition: nanobench.cpp:220
static double time(int loops, Benchmark *bench, Target *target)
Definition: nanobench.cpp:394
bool gForceHighPrecisionRasterPipeline
static double estimate_timer_overhead()
Definition: nanobench.cpp:411
static int setup_cpu_bench(const double overhead, Target *target, Benchmark *bench)
Definition: nanobench.cpp:475
bool gSkForceRasterPipelineBlitter
Definition: SkBlitter.cpp:44
ShaderErrorHandler * fShaderErrorHandler
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
Definition: trace_event.h:145

◆ now_ms()

static double now_ms ( )
static

Definition at line 214 of file nanobench.cpp.

214{ return SkTime::GetNSecs() * 1e-6; }
double GetNSecs()
Definition: SkTime.cpp:17

◆ setup_cpu_bench()

static int setup_cpu_bench ( const double  overhead,
Target target,
Benchmark bench 
)
static

Definition at line 475 of file nanobench.cpp.

475 {
476 // First figure out approximately how many loops of bench it takes to make overhead negligible.
477 double bench_plus_overhead = 0.0;
478 int round = 0;
479 int loops = bench->shouldLoop() ? FLAGS_loops : 1;
480 if (kAutoTuneLoops == loops) {
481 while (bench_plus_overhead < overhead) {
482 if (round++ == FLAGS_maxCalibrationAttempts) {
483 SkDebugf("WARNING: Can't estimate loops for %s (%s vs. %s); skipping.\n",
484 bench->getUniqueName(), HUMANIZE(bench_plus_overhead), HUMANIZE(overhead));
485 return kFailedLoops;
486 }
487 bench_plus_overhead = time(1, bench, target);
488 }
489 }
490
491 // Later we'll just start and stop the timer once but loop N times.
492 // We'll pick N to make timer overhead negligible:
493 //
494 // overhead
495 // ------------------------- < FLAGS_overheadGoal
496 // overhead + N * Bench Time
497 //
498 // where bench_plus_overhead ~=~ overhead + Bench Time.
499 //
500 // Doing some math, we get:
501 //
502 // (overhead / FLAGS_overheadGoal) - overhead
503 // ------------------------------------------ < N
504 // bench_plus_overhead - overhead)
505 //
506 // Luckily, this also works well in practice. :)
507 if (kAutoTuneLoops == loops) {
508 const double numer = overhead / FLAGS_overheadGoal - overhead;
509 const double denom = bench_plus_overhead - overhead;
510 loops = (int)ceil(numer / denom);
511 loops = clamp_loops(loops);
512 } else {
513 loops = detect_forever_loops(loops);
514 }
515
516 return loops;
517}
static void round(SkPoint *p)
SIN Vec< N, float > ceil(const Vec< N, float > &x)
Definition: SkVx.h:702
static int detect_forever_loops(int loops)
Definition: nanobench.cpp:420
static int clamp_loops(int loops)
Definition: nanobench.cpp:428

◆ setup_gpu_bench()

static int setup_gpu_bench ( Target target,
Benchmark bench,
int  maxGpuFrameLag 
)
static

Definition at line 519 of file nanobench.cpp.

519 {
520 // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs.
521 int loops = bench->shouldLoop() ? FLAGS_loops : 1;
522 if (kAutoTuneLoops == loops) {
523 loops = 1;
524 double elapsed = 0;
525 do {
526 if (1<<30 == loops) {
527 // We're about to wrap. Something's wrong with the bench.
528 loops = 0;
529 break;
530 }
531 loops *= 2;
532 // If the GPU lets frames lag at all, we need to make sure we're timing
533 // _this_ round, not still timing last round.
534 for (int i = 0; i < maxGpuFrameLag; i++) {
535 elapsed = time(loops, bench, target);
536 }
537 } while (elapsed < FLAGS_gpuMs);
538
539 // We've overshot at least a little. Scale back linearly.
540 loops = (int)ceil(loops * FLAGS_gpuMs / elapsed);
541 loops = clamp_loops(loops);
542
543 // Make sure we're not still timing our calibration.
544 target->submitWorkAndSyncCPU();
545 } else {
546 loops = detect_forever_loops(loops);
547 }
548 // Pretty much the same deal as the calibration: do some warmup to make
549 // sure we're timing steady-state pipelined frames.
550 for (int i = 0; i < maxGpuFrameLag; i++) {
551 time(loops, bench, target);
552 }
553
554 return loops;
555}

◆ start_keepalive()

static void start_keepalive ( )
static

Definition at line 1324 of file nanobench.cpp.

1324 {
1325 static std::thread* intentionallyLeaked = new std::thread([]{
1326 for (;;) {
1327 static const int kSec = 1200;
1328 #if defined(SK_BUILD_FOR_WIN)
1329 Sleep(kSec * 1000);
1330 #else
1331 sleep(kSec);
1332 #endif
1333 SkDebugf("\nBenchmarks still running...\n");
1334 }
1335 });
1336 (void)intentionallyLeaked;
1337 SK_INTENTIONALLY_LEAKED(intentionallyLeaked);
1338}
#define SK_INTENTIONALLY_LEAKED(X)
Definition: SkMacros.h:55

◆ time()

static double time ( int  loops,
Benchmark bench,
Target target 
)
static

Definition at line 394 of file nanobench.cpp.

394 {
395 SkCanvas* canvas = target->getCanvas();
396 if (canvas) {
397 canvas->clear(SK_ColorWHITE);
398 }
399 bench->preDraw(canvas);
400 double start = now_ms();
401 canvas = target->beginTiming(canvas);
402
403 bench->draw(loops, canvas);
404
405 target->endTiming();
406 double elapsed = now_ms() - start;
407 bench->postDraw(canvas);
408 return elapsed;
409}
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void clear(SkColor color)
Definition: SkCanvas.h:1199

◆ to_string()

static SkString to_string ( int  n)
static

Definition at line 119 of file nanobench.cpp.

119 {
120 SkString str;
121 str.appendS32(n);
122 return str;
123}
void appendS32(int32_t value)
Definition: SkString.h:208

◆ write_canvas_png()

static bool write_canvas_png ( Target target,
const SkString filename 
)
static

Definition at line 441 of file nanobench.cpp.

441 {
442
443 if (filename.isEmpty()) {
444 return false;
445 }
446 if (target->getCanvas() &&
447 kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) {
448 return false;
449 }
450
451 SkBitmap bmp;
452
453 if (!target->capturePixels(&bmp)) {
454 return false;
455 }
456
457 SkString dir = SkOSPath::Dirname(filename.c_str());
458 if (!sk_mkdir(dir.c_str())) {
459 SkDebugf("Can't make dir %s.\n", dir.c_str());
460 return false;
461 }
462 SkFILEWStream stream(filename.c_str());
463 if (!stream.isValid()) {
464 SkDebugf("Can't write %s.\n", filename.c_str());
465 return false;
466 }
467 if (!SkPngEncoder::Encode(&stream, bmp.pixmap(), {})) {
468 SkDebugf("Can't encode a PNG.\n");
469 return false;
470 }
471 return true;
472}
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
static SkString Dirname(const char *fullPath)
Definition: SkOSPath.cpp:36
bool isEmpty() const
Definition: SkString.h:130
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145

Variable Documentation

◆ gForceHighPrecisionRasterPipeline

bool gForceHighPrecisionRasterPipeline
extern

Definition at line 29 of file SkRasterPipeline.cpp.

◆ grContextOpts

GrContextOptions grContextOpts

Definition at line 107 of file nanobench.cpp.

◆ gSkForceRasterPipelineBlitter

bool gSkForceRasterPipelineBlitter
extern

Definition at line 44 of file SkBlitter.cpp.

◆ kAutoTuneLoops

const int kAutoTuneLoops = 0
static

Definition at line 109 of file nanobench.cpp.

◆ kFailedLoops

int kFailedLoops = -2
static

Definition at line 474 of file nanobench.cpp.