bbh_shootout.cpp revision 0817fb6e1eaa4da6d915f3b9e1201db524a4aad5
1d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org/*
2d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org * Copyright 2013 Google Inc.
3d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org *
4d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org * Use of this source code is governed by a BSD-style license that can be
5d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org * found in the LICENSE file.
6d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org */
7d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
8d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "BenchTimer.h"
9d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "LazyDecodeBitmap.h"
10d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "PictureBenchmark.h"
11d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "PictureRenderer.h"
12d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "SkBenchmark.h"
13d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "SkForceLinking.h"
14d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "SkGraphics.h"
15d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "SkStream.h"
16d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "SkString.h"
17d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org#include "TimerData.h"
18d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
19d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const int kNumNormalRecordings = SkBENCHLOOP(10);
20d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const int kNumRTreeRecordings = SkBENCHLOOP(10);
21d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const int kNumPlaybacks = SkBENCHLOOP(4);
22d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const size_t kNumBaseBenchmarks = 3;
23d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const size_t kNumTileSizes = 3;
24d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const size_t kNumBbhPlaybackBenchmarks = 3;
25d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic const size_t kNumBenchmarks = kNumBaseBenchmarks + kNumBbhPlaybackBenchmarks;
26d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
27d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgenum BenchmarkType {
28d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    kNormal_BenchmarkType = 0,
29d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    kRTree_BenchmarkType,
30d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org};
31d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
32d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstruct Histogram {
33d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    Histogram() {
34d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        // Make fCpuTime negative so that we don't mess with stats:
35d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        fCpuTime = SkIntToScalar(-1);
36d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
37d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkScalar fCpuTime;
38d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkString fPath;
39d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org};
40d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
41d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgtypedef void (*BenchmarkFunction)
42992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary Clark    (BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
43d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
44d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org// Defined below.
45d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic void benchmark_playback(
46d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
47d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic void benchmark_recording(
48d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        BenchmarkType, const SkISize&, const SkString&, SkPicture*, BenchTimer*);
49d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
50d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org/**
51d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org * Acts as a POD containing information needed to run a benchmark.
52d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org * Provides static methods to poll benchmark info from an index.
53d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org */
54d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstruct BenchmarkControl {
55d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkISize fTileSize;
56d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    BenchmarkType fType;
57d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    BenchmarkFunction fFunction;
58eb9a46cbbb475e862a084aa2224ec18d4ac5e95breed@google.com    SkString fName;
59d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
60d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    /**
61d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org     * Will construct a BenchmarkControl instance from an index between 0 an kNumBenchmarks.
62d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org     */
63d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    static BenchmarkControl Make(size_t i) {
64d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        SkASSERT(kNumBenchmarks > i);
65d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        BenchmarkControl benchControl;
66d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        benchControl.fTileSize = getTileSize(i);
67d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        benchControl.fType = getBenchmarkType(i);
68d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        benchControl.fFunction = getBenchmarkFunc(i);
69d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        benchControl.fName = getBenchmarkName(i);
70d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        return benchControl;
71d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
72d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
73d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    enum BaseBenchmarks {
74d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        kNormalRecord = 0,
75d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        kRTreeRecord,
76d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        kNormalPlayback,
77eb9a46cbbb475e862a084aa2224ec18d4ac5e95breed@google.com    };
78d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
79d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    static SkISize fTileSizes[kNumTileSizes];
80d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
81d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    static SkISize getTileSize(size_t i) {
82d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        // Two of the base benchmarks don't need a tile size. But to maintain simplicity
83d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        // down the pipeline we have to let a couple of values unused.
84d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        if (i < kNumBaseBenchmarks) {
85d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            return SkISize::Make(256, 256);
86d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
87d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        if (i >= kNumBaseBenchmarks && i < kNumBenchmarks) {
88d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            return fTileSizes[i - kNumBaseBenchmarks];
89d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
90d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        SkASSERT(0);
91d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        return SkISize::Make(0, 0);
92d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
93d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
94d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    static BenchmarkType getBenchmarkType(size_t i) {
95d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        if (i < kNumBaseBenchmarks) {
96d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            switch (i) {
97d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                case kNormalRecord:
98d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                    return kNormal_BenchmarkType;
99d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                case kNormalPlayback:
100d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                    return kNormal_BenchmarkType;
101d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                case kRTreeRecord:
102d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                    return kRTree_BenchmarkType;
103d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            }
104d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
105d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        if (i < kNumBenchmarks) {
106d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            return kRTree_BenchmarkType;
107d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
108d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        SkASSERT(0);
109d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        return kRTree_BenchmarkType;
110d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
111d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
112d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    static BenchmarkFunction getBenchmarkFunc(size_t i) {
113d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        // Base functions.
114d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        switch (i) {
115d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            case kNormalRecord:
116d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                return benchmark_recording;
117d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            case kNormalPlayback:
118d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                return benchmark_playback;
119a90c6803865766d28e92091f56f718f5e41fe80fcommit-bot@chromium.org            case kRTreeRecord:
120d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                return benchmark_recording;
121d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
122d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        // RTree playbacks
123d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        if (i < kNumBenchmarks) {
124d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            return benchmark_playback;
125d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
126d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        SkASSERT(0);
127d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        return NULL;
128d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
129d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
130d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    static SkString getBenchmarkName(size_t i) {
131d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        // Base benchmark names
132d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        switch (i) {
133d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            case kNormalRecord:
134d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                return SkString("normal_recording");
135d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            case kNormalPlayback:
136d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                return SkString("normal_playback");
137cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org            case kRTreeRecord:
138cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org                return SkString("rtree_recording");
139cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org        }
140cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org        // RTree benchmark names.
141cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org        if (i < kNumBenchmarks) {
142cac5fd597f6e2495f50aaa6bcbe3dadc56f0b977commit-bot@chromium.org            SkASSERT(i >= kNumBaseBenchmarks);
143d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            SkString name;
144d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            name.printf("rtree_playback_%dx%d",
145d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                    fTileSizes[i - kNumBaseBenchmarks].fWidth,
146d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org                    fTileSizes[i - kNumBaseBenchmarks].fHeight);
147d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            return name;
148d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
149d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        } else {
150d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org            SkASSERT(0);
151d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        }
152d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        return SkString("");
153d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
154d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
155d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org};
156d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
157d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgSkISize BenchmarkControl::fTileSizes[kNumTileSizes] = {
158d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkISize::Make(256, 256),
159d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkISize::Make(512, 512),
160d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkISize::Make(1024, 1024),
161d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org};
162d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
163d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.orgstatic SkPicture* pic_from_path(const char path[]) {
164d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    SkFILEStream stream(path);
165d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    if (!stream.isValid()) {
166d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        SkDebugf("-- Can't open '%s'\n", path);
167d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org        return NULL;
168d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    }
169d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org    return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap);
170d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org}
171d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org
172d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org/**
173d8f82a4c44b844fed98d3ecc0072e0626b06bb37senorblanco@chromium.org * This function is the sink to which all work ends up going.
174 * Renders the picture into the renderer. It may or may not use an RTree.
175 * The renderer is chosen upstream. If we want to measure recording, we will
176 * use a RecordPictureRenderer. If we want to measure rendering, we eill use a
177 * TiledPictureRenderer.
178 */
179static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
180        int benchmarkType, const SkString& path, SkPicture* pic,
181        const int numRepeats, const char *msg, BenchTimer* timer) {
182    SkString msgPrefix;
183
184    switch (benchmarkType){
185        case kNormal_BenchmarkType:
186            msgPrefix.set("Normal");
187            renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kNone_BBoxHierarchyType);
188            break;
189        case kRTree_BenchmarkType:
190            msgPrefix.set("RTree");
191            renderer->setBBoxHierarchyType(sk_tools::PictureRenderer::kRTree_BBoxHierarchyType);
192            break;
193        default:
194            SkASSERT(0);
195            break;
196    }
197
198    renderer->init(pic);
199
200    /**
201     * If the renderer is not tiled, assume we are measuring recording.
202     */
203    bool isPlayback = (NULL != renderer->getTiledRenderer());
204
205    SkDebugf("%s %s %s %d times...\n", msgPrefix.c_str(), msg, path.c_str(), numRepeats);
206    for (int i = 0; i < numRepeats; ++i) {
207        renderer->setup();
208        // Render once to fill caches.
209        renderer->render(NULL);
210        // Render again to measure
211        timer->start();
212        bool result = renderer->render(NULL);
213        timer->end();
214        // We only care about a false result on playback. RecordPictureRenderer::render will always
215        // return false because we are passing a NULL file name on purpose; which is fine.
216        if(isPlayback && !result) {
217            SkDebugf("Error rendering during playback.\n");
218        }
219    }
220    renderer->end();
221}
222
223/**
224 * Call do_benchmark_work with a tiled renderer using the default tile dimensions.
225 */
226static void benchmark_playback(
227        BenchmarkType benchmarkType, const SkISize& tileSize,
228        const SkString& path, SkPicture* pic, BenchTimer* timer) {
229    sk_tools::TiledPictureRenderer renderer;
230
231    SkString message("tiled_playback");
232    message.appendf("_%dx%d", tileSize.fWidth, tileSize.fHeight);
233    do_benchmark_work(&renderer, benchmarkType,
234            path, pic, kNumPlaybacks, message.c_str(), timer);
235}
236
237/**
238 * Call do_benchmark_work with a RecordPictureRenderer.
239 */
240static void benchmark_recording(
241        BenchmarkType benchmarkType, const SkISize& tileSize,
242        const SkString& path, SkPicture* pic, BenchTimer* timer) {
243    sk_tools::RecordPictureRenderer renderer;
244    int numRecordings = 0;
245    switch(benchmarkType) {
246        case kRTree_BenchmarkType:
247            numRecordings = kNumRTreeRecordings;
248            break;
249        case kNormal_BenchmarkType:
250            numRecordings = kNumNormalRecordings;
251            break;
252    }
253    do_benchmark_work(&renderer, benchmarkType, path, pic, numRecordings, "recording", timer);
254}
255
256/**
257 * Takes argc,argv along with one of the benchmark functions defined above.
258 * Will loop along all skp files and perform measurments.
259 *
260 * Returns a SkScalar representing CPU time taken during benchmark.
261 * As a side effect, it spits the timer result to stdout.
262 * Will return -1.0 on error.
263 */
264static bool benchmark_loop(
265        int argc,
266        char **argv,
267        const BenchmarkControl& benchControl,
268        Histogram* histogram) {
269
270    static const SkString timeFormat("%f");
271    TimerData timerData(timeFormat, timeFormat);
272    for (int index = 1; index < argc; ++index) {
273        BenchTimer timer;
274        SkString path(argv[index]);
275        SkAutoTUnref<SkPicture> pic(pic_from_path(path.c_str()));
276        if (NULL == pic) {
277            SkDebugf("Couldn't create picture. Ignoring path: %s\n", path.c_str());
278            continue;
279        }
280        benchControl.fFunction(benchControl.fType, benchControl.fTileSize, path, pic, &timer);
281        timerData.appendTimes(&timer, argc - 1 == index);
282
283        histogram[index - 1].fPath = path;
284        histogram[index - 1].fCpuTime = SkDoubleToScalar(timer.fCpu);
285    }
286
287    const SkString timerResult = timerData.getResult(
288            /*logPerIter = */ false,
289            /*printMin = */ false,
290            /*repeatDraw = */ 1,
291            /*configName = */ benchControl.fName.c_str(),
292            /*showWallTime = */ false,
293            /*showTruncatedWallTime = */ false,
294            /*showCpuTime = */ true,
295            /*showTruncatedCpuTime = */ false,
296            /*showGpuTime = */ false);
297
298    const char findStr[] = "= ";
299    int pos = timerResult.find(findStr);
300    if (-1 == pos) {
301        SkDebugf("Unexpected output from TimerData::getResult(...). Unable to parse.");
302        return false;
303    }
304
305    SkScalar cpuTime = SkDoubleToScalar(atof(timerResult.c_str() + pos + sizeof(findStr) - 1));
306    if (cpuTime == 0) {  // atof returns 0.0 on error.
307        SkDebugf("Unable to read value from timer result.\n");
308        return false;
309    }
310    return true;
311}
312
313int tool_main(int argc, char** argv);
314int tool_main(int argc, char** argv) {
315    SkAutoGraphics ag;
316    SkString usage;
317    usage.printf("Usage: filename [filename]*\n");
318
319    if (argc < 2) {
320        SkDebugf("%s\n", usage.c_str());
321        return -1;
322    }
323
324    Histogram histograms[argc - 1][kNumBenchmarks];
325
326    for (size_t i = 0; i < kNumBenchmarks; ++i) {
327        bool success = benchmark_loop(
328                argc, argv,
329                BenchmarkControl::Make(i),
330                histograms[i]);
331        if (!success) {
332            SkDebugf("benchmark_loop failed at index %d", i);
333        }
334    }
335
336    // Output gnuplot readable histogram data..
337    const char* pbTitle = "bbh_shootout_playback.dat";
338    const char* recTitle = "bbh_shootout_record.dat";
339    SkFILEWStream playbackOut(pbTitle);
340    SkFILEWStream recordOut(recTitle);
341    recordOut.writeText("# ");
342    playbackOut.writeText("# ");
343    for (size_t i = 0; i < kNumBenchmarks; ++i) {
344        SkString out;
345        out.printf("%s ", BenchmarkControl::getBenchmarkName(i).c_str());
346        if (BenchmarkControl::getBenchmarkFunc(i) == &benchmark_recording) {
347            recordOut.writeText(out.c_str());
348        }
349        if (BenchmarkControl::getBenchmarkFunc(i) == &benchmark_playback) {
350            playbackOut.writeText(out.c_str());
351        }
352    }
353    recordOut.writeText("\n");
354    playbackOut.writeText("\n");
355
356    for (int i = 0; i < argc - 1; ++i) {
357        SkString pbLine;
358        SkString recLine;
359        // ==== Write record info
360        recLine.printf("%d ", i);
361        recLine.appendf("%f ", histograms[0][i].fCpuTime);  // Append normal_record time
362        recLine.appendf("%f", histograms[1][i].fCpuTime);  // Append rtree_record time
363
364        // ==== Write playback info
365        pbLine.printf("%d ", i);
366        pbLine.appendf("%f ", histograms[2][i].fCpuTime);  // Start with normal playback time.
367        // Append all playback benchmark times.
368        for (size_t j = kNumBbhPlaybackBenchmarks; j < kNumBenchmarks; ++j) {
369            pbLine.appendf("%f ", histograms[j][i].fCpuTime);
370        }
371        pbLine.remove(pbLine.size() - 1, 1);  // Remove trailing space from line.
372        pbLine.appendf("\n");
373        recLine.appendf("\n");
374        playbackOut.writeText(pbLine.c_str());
375        recordOut.writeText(recLine.c_str());
376    }
377    SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle);
378
379    return 0;
380}
381
382#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
383int main(int argc, char** argv) {
384    return tool_main(argc, argv);
385}
386#endif
387
388
389