199f340680959c07a11b8cd654e501f92b41646a3joshualitt/* 299f340680959c07a11b8cd654e501f92b41646a3joshualitt * Copyright 2016 Google Inc. 399f340680959c07a11b8cd654e501f92b41646a3joshualitt * 499f340680959c07a11b8cd654e501f92b41646a3joshualitt * Use of this source code is governed by a BSD-style license that can be 599f340680959c07a11b8cd654e501f92b41646a3joshualitt * found in the LICENSE file. 699f340680959c07a11b8cd654e501f92b41646a3joshualitt */ 799f340680959c07a11b8cd654e501f92b41646a3joshualitt 8eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "GrCaps.h" 9eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "GrContextFactory.h" 1099f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "Benchmark.h" 1198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt#include "ResultsWriter.h" 1299f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "SkCommandLineFlags.h" 1399f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "SkOSFile.h" 1499f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "SkStream.h" 15eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "SkSurface.h" 16eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "SkTime.h" 17b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt#include "SkTLList.h" 18b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt#include "SkThreadUtils.h" 19eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "Stats.h" 20eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "Timer.h" 2199f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "VisualSKPBench.h" 22eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#include "gl/GrGLDefines.h" 23b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt#include "../private/SkMutex.h" 24b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt#include "../private/SkSemaphore.h" 25b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt#include "../private/SkGpuFenceSync.h" 2699f340680959c07a11b8cd654e501f92b41646a3joshualitt 2798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt// posix only for now 2898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt#include <unistd.h> 2998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt#include <sys/types.h> 3098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt#include <sys/wait.h> 3198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 3299f340680959c07a11b8cd654e501f92b41646a3joshualitt/* 3399f340680959c07a11b8cd654e501f92b41646a3joshualitt * This is an experimental GPU only benchmarking program. The initial implementation will only 3499f340680959c07a11b8cd654e501f92b41646a3joshualitt * support SKPs. 3599f340680959c07a11b8cd654e501f92b41646a3joshualitt */ 3699f340680959c07a11b8cd654e501f92b41646a3joshualitt 3799f340680959c07a11b8cd654e501f92b41646a3joshualitt// To get image decoders linked in we have to do the below magic 3899f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "SkForceLinking.h" 3999f340680959c07a11b8cd654e501f92b41646a3joshualitt#include "SkImageDecoder.h" 4099f340680959c07a11b8cd654e501f92b41646a3joshualitt__SK_FORCE_IMAGE_DECODER_LINKING; 4199f340680959c07a11b8cd654e501f92b41646a3joshualitt 42eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic const int kAutoTuneLoops = 0; 43eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 44eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic const int kDefaultLoops = 45eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#ifdef SK_DEBUG 46eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 1; 47eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#else 48eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt kAutoTuneLoops; 49eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt#endif 50eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 51eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic SkString loops_help_txt() { 52eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkString help; 53eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt help.printf("Number of times to run each bench. Set this to %d to auto-" 54eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt "tune for each bench. Timings are only reported when auto-tuning.", 55eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt kAutoTuneLoops); 56eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return help; 57eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 58eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 59eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_string(skps, "skps", "Directory to read skps from."); 6099f340680959c07a11b8cd654e501f92b41646a3joshualittDEFINE_string2(match, m, nullptr, 6199f340680959c07a11b8cd654e501f92b41646a3joshualitt "[~][^]substring[$] [...] of GM name to run.\n" 6299f340680959c07a11b8cd654e501f92b41646a3joshualitt "Multiple matches may be separated by spaces.\n" 6399f340680959c07a11b8cd654e501f92b41646a3joshualitt "~ causes a matching bench to always be skipped\n" 6499f340680959c07a11b8cd654e501f92b41646a3joshualitt "^ requires the start of the bench to match\n" 6599f340680959c07a11b8cd654e501f92b41646a3joshualitt "$ requires the end of the bench to match\n" 6699f340680959c07a11b8cd654e501f92b41646a3joshualitt "^ and $ requires an exact match\n" 6799f340680959c07a11b8cd654e501f92b41646a3joshualitt "If a bench does not match any list entry,\n" 6899f340680959c07a11b8cd654e501f92b41646a3joshualitt "it is skipped unless some list entry starts with ~"); 69eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_int32(gpuFrameLag, 5, "If unknown, estimated maximum number of frames GPU allows to lag."); 70eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_int32(samples, 10, "Number of samples to measure for each bench."); 71eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_int32(maxLoops, 1000000, "Never run a bench more times than this."); 72eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_int32(loops, kDefaultLoops, loops_help_txt().c_str()); 73eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_double(gpuMs, 5, "Target bench time in millseconds for GPU."); 74eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittDEFINE_string2(writePath, w, "", "If set, write bitmaps here as .pngs."); 75b35c82dc943073e9945c0beea2d49925b45428ddjoshualittDEFINE_bool(useBackgroundThread, true, "If false, kilobench will time cpu / gpu work together"); 76b35c82dc943073e9945c0beea2d49925b45428ddjoshualittDEFINE_bool(useMultiProcess, true, "If false, kilobench will run all tests in one process"); 7799f340680959c07a11b8cd654e501f92b41646a3joshualitt 7898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualittstatic SkString humanize(double ms) { 7998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt return HumanizeMs(ms); 8098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt} 8198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt#define HUMANIZE(ms) humanize(ms).c_str() 8298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 8399f340680959c07a11b8cd654e501f92b41646a3joshualittnamespace kilobench { 8499f340680959c07a11b8cd654e501f92b41646a3joshualittclass BenchmarkStream { 8599f340680959c07a11b8cd654e501f92b41646a3joshualittpublic: 8699f340680959c07a11b8cd654e501f92b41646a3joshualitt BenchmarkStream() : fCurrentSKP(0) { 8799f340680959c07a11b8cd654e501f92b41646a3joshualitt for (int i = 0; i < FLAGS_skps.count(); i++) { 8899f340680959c07a11b8cd654e501f92b41646a3joshualitt if (SkStrEndsWith(FLAGS_skps[i], ".skp")) { 8999f340680959c07a11b8cd654e501f92b41646a3joshualitt fSKPs.push_back() = FLAGS_skps[i]; 9099f340680959c07a11b8cd654e501f92b41646a3joshualitt } else { 9199f340680959c07a11b8cd654e501f92b41646a3joshualitt SkOSFile::Iter it(FLAGS_skps[i], ".skp"); 9299f340680959c07a11b8cd654e501f92b41646a3joshualitt SkString path; 9399f340680959c07a11b8cd654e501f92b41646a3joshualitt while (it.next(&path)) { 9499f340680959c07a11b8cd654e501f92b41646a3joshualitt fSKPs.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str()); 9599f340680959c07a11b8cd654e501f92b41646a3joshualitt } 9699f340680959c07a11b8cd654e501f92b41646a3joshualitt } 9799f340680959c07a11b8cd654e501f92b41646a3joshualitt } 9899f340680959c07a11b8cd654e501f92b41646a3joshualitt } 9999f340680959c07a11b8cd654e501f92b41646a3joshualitt 10099f340680959c07a11b8cd654e501f92b41646a3joshualitt Benchmark* next() { 10199f340680959c07a11b8cd654e501f92b41646a3joshualitt Benchmark* bench = nullptr; 10299f340680959c07a11b8cd654e501f92b41646a3joshualitt // skips non matching benches 10399f340680959c07a11b8cd654e501f92b41646a3joshualitt while ((bench = this->innerNext()) && 10499f340680959c07a11b8cd654e501f92b41646a3joshualitt (SkCommandLineFlags::ShouldSkip(FLAGS_match, bench->getUniqueName()) || 10599f340680959c07a11b8cd654e501f92b41646a3joshualitt !bench->isSuitableFor(Benchmark::kGPU_Backend))) { 10699f340680959c07a11b8cd654e501f92b41646a3joshualitt delete bench; 10799f340680959c07a11b8cd654e501f92b41646a3joshualitt } 10899f340680959c07a11b8cd654e501f92b41646a3joshualitt return bench; 10999f340680959c07a11b8cd654e501f92b41646a3joshualitt } 11099f340680959c07a11b8cd654e501f92b41646a3joshualitt 11199f340680959c07a11b8cd654e501f92b41646a3joshualittprivate: 11299f340680959c07a11b8cd654e501f92b41646a3joshualitt static bool ReadPicture(const char* path, SkAutoTUnref<SkPicture>* pic) { 11399f340680959c07a11b8cd654e501f92b41646a3joshualitt // Not strictly necessary, as it will be checked again later, 11499f340680959c07a11b8cd654e501f92b41646a3joshualitt // but helps to avoid a lot of pointless work if we're going to skip it. 11599f340680959c07a11b8cd654e501f92b41646a3joshualitt if (SkCommandLineFlags::ShouldSkip(FLAGS_match, path)) { 11699f340680959c07a11b8cd654e501f92b41646a3joshualitt return false; 11799f340680959c07a11b8cd654e501f92b41646a3joshualitt } 11899f340680959c07a11b8cd654e501f92b41646a3joshualitt 11999f340680959c07a11b8cd654e501f92b41646a3joshualitt SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path)); 12099f340680959c07a11b8cd654e501f92b41646a3joshualitt if (stream.get() == nullptr) { 12199f340680959c07a11b8cd654e501f92b41646a3joshualitt SkDebugf("Could not read %s.\n", path); 12299f340680959c07a11b8cd654e501f92b41646a3joshualitt return false; 12399f340680959c07a11b8cd654e501f92b41646a3joshualitt } 12499f340680959c07a11b8cd654e501f92b41646a3joshualitt 12599f340680959c07a11b8cd654e501f92b41646a3joshualitt pic->reset(SkPicture::CreateFromStream(stream.get())); 12699f340680959c07a11b8cd654e501f92b41646a3joshualitt if (pic->get() == nullptr) { 12799f340680959c07a11b8cd654e501f92b41646a3joshualitt SkDebugf("Could not read %s as an SkPicture.\n", path); 12899f340680959c07a11b8cd654e501f92b41646a3joshualitt return false; 12999f340680959c07a11b8cd654e501f92b41646a3joshualitt } 13099f340680959c07a11b8cd654e501f92b41646a3joshualitt return true; 13199f340680959c07a11b8cd654e501f92b41646a3joshualitt } 13299f340680959c07a11b8cd654e501f92b41646a3joshualitt 13399f340680959c07a11b8cd654e501f92b41646a3joshualitt Benchmark* innerNext() { 13499f340680959c07a11b8cd654e501f92b41646a3joshualitt // Render skps 13599f340680959c07a11b8cd654e501f92b41646a3joshualitt while (fCurrentSKP < fSKPs.count()) { 13699f340680959c07a11b8cd654e501f92b41646a3joshualitt const SkString& path = fSKPs[fCurrentSKP++]; 13799f340680959c07a11b8cd654e501f92b41646a3joshualitt SkAutoTUnref<SkPicture> pic; 13899f340680959c07a11b8cd654e501f92b41646a3joshualitt if (!ReadPicture(path.c_str(), &pic)) { 13999f340680959c07a11b8cd654e501f92b41646a3joshualitt continue; 14099f340680959c07a11b8cd654e501f92b41646a3joshualitt } 14199f340680959c07a11b8cd654e501f92b41646a3joshualitt 14299f340680959c07a11b8cd654e501f92b41646a3joshualitt SkString name = SkOSPath::Basename(path.c_str()); 14399f340680959c07a11b8cd654e501f92b41646a3joshualitt return new VisualSKPBench(name.c_str(), pic.get()); 14499f340680959c07a11b8cd654e501f92b41646a3joshualitt } 14599f340680959c07a11b8cd654e501f92b41646a3joshualitt 14699f340680959c07a11b8cd654e501f92b41646a3joshualitt return nullptr; 14799f340680959c07a11b8cd654e501f92b41646a3joshualitt } 14899f340680959c07a11b8cd654e501f92b41646a3joshualitt 14999f340680959c07a11b8cd654e501f92b41646a3joshualitt SkTArray<SkString> fSKPs; 15099f340680959c07a11b8cd654e501f92b41646a3joshualitt int fCurrentSKP; 15199f340680959c07a11b8cd654e501f92b41646a3joshualitt}; 15299f340680959c07a11b8cd654e501f92b41646a3joshualitt 153eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstruct GPUTarget { 154eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt void setup() { 155b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fGL->makeCurrent(); 156eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // Make sure we're done with whatever came before. 157b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SK_GL(*fGL, Finish()); 158eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 159eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 160eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkCanvas* beginTiming(SkCanvas* canvas) { return canvas; } 161eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 162b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void endTiming(bool usePlatformSwapBuffers) { 163b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (fGL) { 164b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SK_GL(*fGL, Flush()); 165b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (usePlatformSwapBuffers) { 166b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fGL->swapBuffers(); 167b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else { 168b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fGL->waitOnSyncOrSwap(); 169b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 170eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 171eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 172b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void finish() { 173b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SK_GL(*fGL, Finish()); 174eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 175eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 176eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bool needsFrameTiming(int* maxFrameLag) const { 177b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (!fGL->getMaxGpuFrameLag(maxFrameLag)) { 178eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // Frame lag is unknown. 179eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt *maxFrameLag = FLAGS_gpuFrameLag; 180eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 181eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return true; 182eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 183eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 184eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bool init(Benchmark* bench, GrContextFactory* factory, bool useDfText, 185eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt GrContextFactory::GLContextType ctxType, 186eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt GrContextFactory::GLContextOptions ctxOptions, int numSamples) { 187eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt GrContext* context = factory->get(ctxType, ctxOptions); 188eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt int maxRTSize = context->caps()->maxRenderTargetSize(); 189eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkImageInfo info = SkImageInfo::Make(SkTMin(bench->getSize().fX, maxRTSize), 190eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkTMin(bench->getSize().fY, maxRTSize), 191eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt kN32_SkColorType, kPremul_SkAlphaType); 192eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt uint32_t flags = useDfText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 193eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 0; 194eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); 195b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fSurface.reset(SkSurface::NewRenderTarget(context, 1965ec26ae9bfca635ccc98283aad5deda11519d826bsalomon SkBudgeted::kNo, info, 197b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt numSamples, &props)); 198b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fGL = factory->getContextInfo(ctxType, ctxOptions).fGLContext; 199b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (!fSurface.get()) { 200eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 201eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 202eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 203eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // Kilobench should only be used on platforms with fence sync support 204b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkASSERT(fGL->fenceSyncSupport()); 205eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return true; 206eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 207eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 208eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkCanvas* getCanvas() const { 209b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (!fSurface.get()) { 210eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return nullptr; 211eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 212b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return fSurface->getCanvas(); 213eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 214eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 215eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bool capturePixels(SkBitmap* bmp) { 216eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkCanvas* canvas = this->getCanvas(); 217eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!canvas) { 218eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 219eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 220eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bmp->setInfo(canvas->imageInfo()); 221eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!canvas->readPixels(bmp, 0, 0)) { 222eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("Can't read canvas pixels.\n"); 223eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 224eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 225eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return true; 226eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 227eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 228b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkGLContext* gl() { return fGL; } 229b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 230eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittprivate: 231b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkGLContext* fGL; 232b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoTDelete<SkSurface> fSurface; 233eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt}; 234eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 235eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic bool write_canvas_png(GPUTarget* target, const SkString& filename) { 236eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 237eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (filename.isEmpty()) { 238eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 239eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 240eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (target->getCanvas() && 241eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt kUnknown_SkColorType == target->getCanvas()->imageInfo().colorType()) { 242eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 243eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 244eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 245eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkBitmap bmp; 246eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 247eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!target->capturePixels(&bmp)) { 248eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 249eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 250eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 251eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkString dir = SkOSPath::Dirname(filename.c_str()); 252eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!sk_mkdir(dir.c_str())) { 253eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("Can't make dir %s.\n", dir.c_str()); 254eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 255eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 256eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkFILEWStream stream(filename.c_str()); 257eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!stream.isValid()) { 258eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("Can't write %s.\n", filename.c_str()); 259eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 260eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 261eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!SkImageEncoder::EncodeStream(&stream, bmp, SkImageEncoder::kPNG_Type, 100)) { 262eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("Can't encode a PNG.\n"); 263eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return false; 264eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 265eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return true; 266eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 267eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 268eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic int detect_forever_loops(int loops) { 269eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // look for a magic run-forever value 270eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (loops < 0) { 271eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops = SK_MaxS32; 272eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 273eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return loops; 274eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 275eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 276eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic int clamp_loops(int loops) { 277eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (loops < 1) { 278eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("ERROR: clamping loops from %d to 1. " 279eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt "There's probably something wrong with the bench.\n", loops); 280eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return 1; 281eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 282eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (loops > FLAGS_maxLoops) { 283eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("WARNING: clamping loops from %d to FLAGS_maxLoops, %d.\n", loops, FLAGS_maxLoops); 284eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return FLAGS_maxLoops; 285eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 286eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return loops; 287eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 288eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 289eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic double now_ms() { return SkTime::GetNSecs() * 1e-6; } 290b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 291b35c82dc943073e9945c0beea2d49925b45428ddjoshualittstruct TimingThread { 292b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt TimingThread(SkGLContext* mainContext) 293b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt : fFenceSync(mainContext->fenceSync()) 294b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , fMainContext(mainContext) 295b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , fDone(false) {} 296b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 297b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt static void Loop(void* data) { 298b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt TimingThread* timingThread = reinterpret_cast<TimingThread*>(data); 299b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt timingThread->timingLoop(); 300b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 301b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 302b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // To ensure waiting for the sync actually does something, we check to make sure the we exceed 303b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // some small value 304b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt const double kMinElapsed = 1e-6; 305b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt bool sanity(double start) const { 306b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double elapsed = now_ms() - start; 307b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return elapsed > kMinElapsed; 308b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 309b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 310b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void waitFence(SkPlatformGpuFence sync) { 311b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkDEBUGCODE(double start = now_ms()); 312b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fFenceSync->waitFence(sync, false); 313b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkASSERT(sanity(start)); 314b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 315b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 316b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void timingLoop() { 317b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // Create a context which shares display lists with the main thread 318b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoTDelete<SkGLContext> glContext(SkCreatePlatformGLContext(kNone_GrGLStandard, 319b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fMainContext)); 320b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt glContext->makeCurrent(); 321b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 322b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // Basic timing methodology is: 323b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // 1) Wait on semaphore until main thread indicates its time to start timing the frame 324b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // 2) Wait on frame start sync, record time. This is start of the frame. 325b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // 3) Wait on semaphore until main thread indicates its time to finish timing the frame 326b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // 4) Wait on frame end sync, record time. FrameEndTime - FrameStartTime = frame time 327b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // 5) Wait on semaphore until main thread indicates we should time the next frame or quit 328b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt while (true) { 329b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fSemaphore.wait(); 330b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 331b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // get start sync 332b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkPlatformGpuFence startSync = this->popStartSync(); 333b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 334b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // wait on sync 335b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt this->waitFence(startSync); 336b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double start = kilobench::now_ms(); 337b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 338b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // do we want to sleep here? 339b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // wait for end sync 340b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fSemaphore.wait(); 341b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 342b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // get end sync 343b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkPlatformGpuFence endSync = this->popEndSync(); 344b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 345b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // wait on sync 346b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt this->waitFence(endSync); 347b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double elapsed = kilobench::now_ms() - start; 348b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 349b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // No mutex needed, client won't touch timings until we're done 350b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fTimings.push_back(elapsed); 351b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 352b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // clean up fences 353b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fFenceSync->deleteFence(startSync); 354b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fFenceSync->deleteFence(endSync); 355b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 356b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fSemaphore.wait(); 357b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (this->isDone()) { 358b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt break; 359b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 360b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 361b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 362b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 363b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void pushStartSync() { this->pushSync(&fFrameStartSyncs, &fFrameStartSyncsMutex); } 364b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 365b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkPlatformGpuFence popStartSync() { 366b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return this->popSync(&fFrameStartSyncs, &fFrameStartSyncsMutex); 367b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 368b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 369b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void pushEndSync() { this->pushSync(&fFrameEndSyncs, &fFrameEndSyncsMutex); } 370b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 371b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkPlatformGpuFence popEndSync() { return this->popSync(&fFrameEndSyncs, &fFrameEndSyncsMutex); } 372b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 373b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void setDone() { 374b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoMutexAcquire done(fDoneMutex); 375b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fDone = true; 376b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fSemaphore.signal(); 377b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 378b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 379b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt typedef SkTLList<SkPlatformGpuFence, 1> SyncQueue; 380b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 381b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt void pushSync(SyncQueue* queue, SkMutex* mutex) { 382b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoMutexAcquire am(mutex); 383b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt *queue->addToHead() = fFenceSync->insertFence(); 384b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt fSemaphore.signal(); 385b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 386b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 387b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkPlatformGpuFence popSync(SyncQueue* queue, SkMutex* mutex) { 388b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoMutexAcquire am(mutex); 389b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkPlatformGpuFence sync = *queue->head(); 390b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt queue->popHead(); 391b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return sync; 392b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 393b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 394b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt bool isDone() { 395b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoMutexAcquire am1(fFrameStartSyncsMutex); 396b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoMutexAcquire done(fDoneMutex); 397b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (fDone && fFrameStartSyncs.isEmpty()) { 398b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return true; 399b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else { 400b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return false; 401b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 402eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 403b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 404b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt const SkTArray<double>& timings() const { SkASSERT(fDone); return fTimings; } 405b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 406b35c82dc943073e9945c0beea2d49925b45428ddjoshualittprivate: 407b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkGpuFenceSync* fFenceSync; 408b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkSemaphore fSemaphore; 409b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkMutex fFrameStartSyncsMutex; 410b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SyncQueue fFrameStartSyncs; 411b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkMutex fFrameEndSyncsMutex; 412b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SyncQueue fFrameEndSyncs; 413b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkTArray<double> fTimings; 414b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkMutex fDoneMutex; 415b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkGLContext* fMainContext; 416b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt bool fDone; 417b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt}; 418b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 419b35c82dc943073e9945c0beea2d49925b45428ddjoshualittstatic double time(int loops, Benchmark* bench, GPUTarget* target, TimingThread* timingThread) { 420b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkCanvas* canvas = target->getCanvas(); 421b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt canvas->clear(SK_ColorWHITE); 422eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bench->preDraw(canvas); 423b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 424b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (timingThread) { 425b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt timingThread->pushStartSync(); 426b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 427eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt double start = now_ms(); 428eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt canvas = target->beginTiming(canvas); 429eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bench->draw(loops, canvas); 430b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt canvas->flush(); 431b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt target->endTiming(timingThread ? true : false); 432b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 433eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt double elapsed = now_ms() - start; 434b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (timingThread) { 435b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt timingThread->pushEndSync(); 436b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt timingThread->setDone(); 437b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 438eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt bench->postDraw(canvas); 439eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return elapsed; 440eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 441eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 442b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt// TODO For now we don't use the background timing thread to tune loops 443eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualittstatic int setup_gpu_bench(GPUTarget* target, Benchmark* bench, int maxGpuFrameLag) { 444eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // First, figure out how many loops it'll take to get a frame up to FLAGS_gpuMs. 445eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt int loops = bench->calculateLoops(FLAGS_loops); 446eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (kAutoTuneLoops == loops) { 447eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops = 1; 448eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt double elapsed = 0; 449eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt do { 450eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (1<<30 == loops) { 451eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // We're about to wrap. Something's wrong with the bench. 452eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops = 0; 453eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt break; 454eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 455eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops *= 2; 456eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // If the GPU lets frames lag at all, we need to make sure we're timing 457eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // _this_ round, not still timing last round. 458eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt for (int i = 0; i < maxGpuFrameLag; i++) { 459b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt elapsed = time(loops, bench, target, nullptr); 460eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 461eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } while (elapsed < FLAGS_gpuMs); 462eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 463eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // We've overshot at least a little. Scale back linearly. 464eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops = (int)ceil(loops * FLAGS_gpuMs / elapsed); 465eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops = clamp_loops(loops); 466eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 467eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // Make sure we're not still timing our calibration. 468b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt target->finish(); 469eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } else { 470eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt loops = detect_forever_loops(loops); 471eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 472eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 473eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // Pretty much the same deal as the calibration: do some warmup to make 474eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt // sure we're timing steady-state pipelined frames. 475eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt for (int i = 0; i < maxGpuFrameLag - 1; i++) { 476b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt time(loops, bench, target, nullptr); 477eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 478eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 479eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt return loops; 480eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 481eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 48298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualittstruct AutoSetupContextBenchAndTarget { 48398eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt AutoSetupContextBenchAndTarget(Benchmark* bench) : fBenchmark(bench) { 48498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt GrContextOptions grContextOpts; 48598eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt fCtxFactory.reset(new GrContextFactory(grContextOpts)); 486eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 48798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt SkAssertResult(fTarget.init(bench, fCtxFactory, false, 48898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt GrContextFactory::kNative_GLContextType, 48998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt GrContextFactory::kNone_GLContextOptions, 0)); 490eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 49198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt fCanvas = fTarget.getCanvas(); 49298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt fTarget.setup(); 493eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 49498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt bench->perCanvasPreDraw(fCanvas); 49598eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt fTarget.needsFrameTiming(&fMaxFrameLag); 49698eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 49798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 49898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt int getLoops() { return setup_gpu_bench(&fTarget, fBenchmark, fMaxFrameLag); } 499eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 500b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double timeSample(int loops, TimingThread* timingThread) { 50198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt for (int i = 0; i < fMaxFrameLag; i++) { 502b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt time(loops, fBenchmark, &fTarget, timingThread); 50398eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 50498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 505b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return time(loops, fBenchmark, &fTarget, timingThread) / loops; 506eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 507b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 50898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt void teardownBench() { fBenchmark->perCanvasPostDraw(fCanvas); } 50998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 51098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt SkAutoTDelete<GrContextFactory> fCtxFactory; 51198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt GPUTarget fTarget; 51298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt SkCanvas* fCanvas; 51398eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt Benchmark* fBenchmark; 51498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt int fMaxFrameLag; 51598eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt}; 516eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 51798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualittint setup_loops(Benchmark* bench) { 51898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt AutoSetupContextBenchAndTarget ascbt(bench); 51998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt int loops = ascbt.getLoops(); 52098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt ascbt.teardownBench(); 521eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 522eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt if (!FLAGS_writePath.isEmpty() && FLAGS_writePath[0]) { 523eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkString pngFilename = SkOSPath::Join(FLAGS_writePath[0], "gpu"); 524eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt pngFilename = SkOSPath::Join(pngFilename.c_str(), bench->getUniqueName()); 525eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt pngFilename.append(".png"); 52698eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt write_canvas_png(&ascbt.fTarget, pngFilename); 527eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt } 52898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt return loops; 529eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt} 530eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 531b35c82dc943073e9945c0beea2d49925b45428ddjoshualittstruct Sample { 532b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double fCpu; 533b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double fGpu; 534b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt}; 535b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 536b35c82dc943073e9945c0beea2d49925b45428ddjoshualittSample time_sample(Benchmark* bench, int loops) { 53798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt AutoSetupContextBenchAndTarget ascbt(bench); 538b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 539b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt Sample sample; 540b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (FLAGS_useBackgroundThread) { 541b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt TimingThread timingThread(ascbt.fTarget.gl()); 542b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkAutoTDelete<SkThread> nativeThread(new SkThread(TimingThread::Loop, &timingThread)); 543b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt nativeThread->start(); 544b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sample.fCpu = ascbt.timeSample(loops, &timingThread); 545b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt nativeThread->join(); 546b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 547b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // return the min 548b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt double min = SK_ScalarMax; 549b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt for (int i = 0; i < timingThread.timings().count(); i++) { 550b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt min = SkTMin(min, timingThread.timings()[i]); 551b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 552b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sample.fGpu = min; 553b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else { 554b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sample.fCpu = ascbt.timeSample(loops, nullptr); 555b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 556b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 55798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt ascbt.teardownBench(); 55899f340680959c07a11b8cd654e501f92b41646a3joshualitt 55998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt return sample; 56098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt} 561eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 56298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt} // namespace kilobench 56398eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 56498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualittstatic const int kOutResultSize = 1024; 565eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 566b35c82dc943073e9945c0beea2d49925b45428ddjoshualittvoid printResult(const SkTArray<double>& samples, int loops, const char* name, const char* mod) { 567b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkString newName(name); 568b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt newName.appendf("_%s", mod); 569b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt Stats stats(samples); 570b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt const double stddev_percent = 100 * sqrt(stats.var) / stats.mean; 571b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkDebugf("%d\t%s\t%s\t%s\t%s\t%.0f%%\t%s\t%s\t%s\n" 572b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , loops 573b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , HUMANIZE(stats.min) 574b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , HUMANIZE(stats.median) 575b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , HUMANIZE(stats.mean) 576b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , HUMANIZE(stats.max) 577b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , stddev_percent 578b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , stats.plot.c_str() 579b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , "gpu" 580b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt , newName.c_str() 581b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt ); 582b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt} 583b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 58498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualittint kilobench_main() { 58599f340680959c07a11b8cd654e501f92b41646a3joshualitt kilobench::BenchmarkStream benchStream; 586eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 587eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt SkDebugf("loops\tmin\tmedian\tmean\tmax\tstddev\t%-*s\tconfig\tbench\n", 588eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt FLAGS_samples, "samples"); 589eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 59098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt int descriptors[2]; 59198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt if (pipe(descriptors) != 0) { 59298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt SkFAIL("Failed to open a pipe\n"); 59398eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 59498eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 59599f340680959c07a11b8cd654e501f92b41646a3joshualitt while (Benchmark* b = benchStream.next()) { 59699f340680959c07a11b8cd654e501f92b41646a3joshualitt SkAutoTDelete<Benchmark> bench(b); 597eb60d671201cd88a1231eb22dbb637fe31ea76d8joshualitt 598b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt int loops = 1; 599b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkTArray<double> cpuSamples; 600b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkTArray<double> gpuSamples; 60198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt for (int i = 0; i < FLAGS_samples + 1; i++) { 60298eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt // We fork off a new process to setup the grcontext and run the test while we wait 603b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (FLAGS_useMultiProcess) { 604b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt int childPid = fork(); 605b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (childPid > 0) { 606b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt char result[kOutResultSize]; 607b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (read(descriptors[0], result, kOutResultSize) < 0) { 608b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkFAIL("Failed to read from pipe\n"); 609b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 610b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 611b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // if samples == 0 then parse # of loops 612b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // else parse float 613b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (i == 0) { 614b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sscanf(result, "%d", &loops); 615b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else { 616b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sscanf(result, "%lf %lf", &cpuSamples.push_back(), 617b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt &gpuSamples.push_back()); 618b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 619b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 620b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // wait until exit 621b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt int status; 622b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt waitpid(childPid, &status, 0); 623b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else if (0 == childPid) { 624b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt char result[kOutResultSize]; 625b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (i == 0) { 626b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sprintf(result, "%d", kilobench::setup_loops(bench)); 627b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else { 628b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt kilobench::Sample sample = kilobench::time_sample(bench, loops); 629b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt sprintf(result, "%lf %lf", sample.fCpu, sample.fGpu); 630b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 631b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt 632b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt // Make sure to write the null terminator 633b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (write(descriptors[1], result, strlen(result) + 1) < 0) { 634b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkFAIL("Failed to write to pipe\n"); 635b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 636b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt return 0; 63798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } else { 638b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt SkFAIL("Fork failed\n"); 63998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 640b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } else { 64198eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt if (i == 0) { 642b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt loops = kilobench::setup_loops(bench); 64398eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } else { 644b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt kilobench::Sample sample = kilobench::time_sample(bench, loops); 645b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt cpuSamples.push_back(sample.fCpu); 646b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt gpuSamples.push_back(sample.fGpu); 64798eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 64898eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 64998eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 65098eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt 651b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt printResult(cpuSamples, loops, bench->getUniqueName(), "cpu"); 652b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt if (FLAGS_useBackgroundThread) { 653b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt printResult(gpuSamples, loops, bench->getUniqueName(), "gpu"); 654b35c82dc943073e9945c0beea2d49925b45428ddjoshualitt } 65598eb3d3776ba64099a19c92ab7aac4f2e323d857joshualitt } 65699f340680959c07a11b8cd654e501f92b41646a3joshualitt return 0; 65799f340680959c07a11b8cd654e501f92b41646a3joshualitt} 65899f340680959c07a11b8cd654e501f92b41646a3joshualitt 65999f340680959c07a11b8cd654e501f92b41646a3joshualitt#if !defined SK_BUILD_FOR_IOS 66099f340680959c07a11b8cd654e501f92b41646a3joshualittint main(int argc, char** argv) { 66199f340680959c07a11b8cd654e501f92b41646a3joshualitt SkCommandLineFlags::Parse(argc, argv); 66299f340680959c07a11b8cd654e501f92b41646a3joshualitt return kilobench_main(); 66399f340680959c07a11b8cd654e501f92b41646a3joshualitt} 66499f340680959c07a11b8cd654e501f92b41646a3joshualitt#endif 665