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