1c216a01c96d83bd9a90e214af64913e93d39aaccRichard Smith/*
259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith * Copyright 2013 Google Inc.
359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith *
459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith * Use of this source code is governed by a BSD-style license that can be
559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith * found in the LICENSE file.
69eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith */
79eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith
859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith#include "Timer.h"
959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith#include "Benchmark.h"
1059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith#include "LazyDecodeBitmap.h"
111d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "PictureBenchmark.h"
121d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "PictureRenderer.h"
131d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "SkCommandLineFlags.h"
141d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "SkForceLinking.h"
151d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "SkGraphics.h"
161d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "SkStream.h"
171d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "SkString.h"
181d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith#include "SkTArray.h"
191d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith
201d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smithtypedef sk_tools::PictureRenderer::BBoxHierarchyType BBoxType;
211d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smithstatic const int kBBoxTypeCount = sk_tools::PictureRenderer::kLast_BBoxHierarchyType + 1;
2259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
2359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
2459efe266b804330f4c1f3a1b0ff783e67dd90378Richard SmithDEFINE_string2(skps, r, "", "The list of SKPs to benchmark.");
2559efe266b804330f4c1f3a1b0ff783e67dd90378Richard SmithDEFINE_string(bb_types, "", "The set of bbox types to test. If empty, all are tested. "
2659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                       "Should be one or more of none, quadtree, rtree, tilegrid.");
2759efe266b804330f4c1f3a1b0ff783e67dd90378Richard SmithDEFINE_int32(record, 100, "Number of times to record each SKP.");
2859efe266b804330f4c1f3a1b0ff783e67dd90378Richard SmithDEFINE_int32(playback, 1, "Number of times to playback each SKP.");
2959efe266b804330f4c1f3a1b0ff783e67dd90378Richard SmithDEFINE_int32(tilesize, 256, "The size of a tile.");
3059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
3159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithstruct Measurement {
3259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    SkString fName;
3359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    double fRecordAverage[kBBoxTypeCount];
3459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    double fPlaybackAverage[kBBoxTypeCount];
3559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith};
3659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
3759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithconst char* kBBoxHierarchyTypeNames[kBBoxTypeCount] = {
3859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    "none", // kNone_BBoxHierarchyType
3959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    "quadtree", // kQuadTree_BBoxHierarchyType
40f15fda02e9c8c82b4a716618f4010b9af8bff796Richard Smith    "rtree", // kRTree_BBoxHierarchyType
419eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    "tilegrid", // kTileGrid_BBoxHierarchyType
429eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith};
439eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith
4459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithstatic SkPicture* pic_from_path(const char path[]) {
4559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    SkFILEStream stream(path);
4659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    if (!stream.isValid()) {
479eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        SkDebugf("-- Can't open '%s'\n", path);
489eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        return NULL;
499eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    }
5059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    return SkPicture::CreateFromStream(&stream, &sk_tools::LazyDecodeBitmap);
5159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith}
5259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
5359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith/**
549eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith * This function is the sink to which all work ends up going.
559eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith * @param renderer The renderer to use to perform the work.
5659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith *                 To measure rendering, use a TiledPictureRenderer.
579eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith *                 To measure recording, use a RecordPictureRenderer.
589eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith * @param bBoxType The bounding box hierarchy type to use.
599eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith * @param pic The picture to draw to the renderer.
609eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith * @param numRepeats The number of times to repeat the draw.
619eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith * @param timer The timer used to benchmark the work.
6259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith */
6359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithstatic void do_benchmark_work(sk_tools::PictureRenderer* renderer,
6459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        BBoxType bBoxType,
6559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        SkPicture* pic,
6659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        const int numRepeats,
6759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        Timer* timer) {
689eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    renderer->setBBoxHierarchyType(bBoxType);
6959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    renderer->setGridSize(FLAGS_tilesize, FLAGS_tilesize);
7059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    renderer->init(pic, NULL, NULL, NULL, false);
71f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith
72f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith    SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats);
73f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith    for (int i = 0; i < numRepeats; ++i) {
74f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        renderer->setup();
75f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        // Render once to fill caches
76f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        renderer->render();
77f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        // Render again to measure
78f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        timer->start();
79f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        renderer->render();
80f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith        timer->end();
81f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith    }
82f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith}
83f64699e8db3946e21b5f4a0421cbc58a3e439599Richard Smith
8459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithint tool_main(int argc, char** argv);
8559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithint tool_main(int argc, char** argv) {
8659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    SkCommandLineFlags::Parse(argc, argv);
8759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    SkAutoGraphics ag;
881d238ea926bbdd04356ce475934fcd4cac654c4bRichard Smith    bool includeBBoxType[kBBoxTypeCount];
896180245e9f63d2927b185ec251fb75aba30f1cacRichard Smith    for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
9059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        includeBBoxType[bBoxType] = (FLAGS_bb_types.count() == 0) ||
9159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            FLAGS_bb_types.contains(kBBoxHierarchyTypeNames[bBoxType]);
9259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    }
9359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    // go through all the pictures
9459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    SkTArray<Measurement> measurements;
958ef7b203332b0c8d65876a1f5e6d1db4e6f40e4bRichard Smith    for (int index = 0; index < FLAGS_skps.count(); ++index) {
968ef7b203332b0c8d65876a1f5e6d1db4e6f40e4bRichard Smith        const char* path = FLAGS_skps[index];
9759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        SkPicture* picture = pic_from_path(path);
9859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        if (NULL == picture) {
9959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            SkDebugf("Couldn't create picture. Ignoring path: %s\n", path);
10059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            continue;
10159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        }
10259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        SkDebugf("Benchmarking path: %s\n", path);
103099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith        Measurement& measurement = measurements.push_back();
104099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith        measurement.fName = path;
105099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith        for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
106099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith            if (!includeBBoxType[bBoxType]) { continue; }
107099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith            if (FLAGS_playback > 0) {
108099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith                sk_tools::TiledPictureRenderer playbackRenderer;
109099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith                Timer playbackTimer;
110099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith                do_benchmark_work(&playbackRenderer, (BBoxType)bBoxType,
11159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                                  picture, FLAGS_playback, &playbackTimer);
11259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                measurement.fPlaybackAverage[bBoxType] = playbackTimer.fCpu;
11359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            }
11459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            if (FLAGS_record > 0) {
11559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                sk_tools::RecordPictureRenderer recordRenderer;
11659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                Timer recordTimer;
1179eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith                do_benchmark_work(&recordRenderer, (BBoxType)bBoxType,
11859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                                  picture, FLAGS_record, &recordTimer);
11959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                measurement.fRecordAverage[bBoxType] = recordTimer.fCpu;
12059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            }
12159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        }
12259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    }
12359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
12459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    Measurement globalMeasurement;
12559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
12659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        if (!includeBBoxType[bBoxType]) { continue; }
12759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        globalMeasurement.fPlaybackAverage[bBoxType] = 0;
12859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        globalMeasurement.fRecordAverage[bBoxType] = 0;
1299eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        for (int index = 0; index < measurements.count(); ++index) {
1309eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith            const Measurement& measurement = measurements[index];
1319eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith            globalMeasurement.fPlaybackAverage[bBoxType] +=
1329eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith                measurement.fPlaybackAverage[bBoxType];
1339eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith            globalMeasurement.fRecordAverage[bBoxType] +=
13459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                measurement.fRecordAverage[bBoxType];
13559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        }
13659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        globalMeasurement.fPlaybackAverage[bBoxType] /= measurements.count();
13759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        globalMeasurement.fRecordAverage[bBoxType] /= measurements.count();
13859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    }
13959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
14059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    // Output gnuplot readable histogram data..
1419eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    const char* pbTitle = "bbh_shootout_playback.dat";
1429eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    const char* recTitle = "bbh_shootout_record.dat";
1439eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    SkFILEWStream playbackOut(pbTitle);
1449eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith    SkFILEWStream recordOut(recTitle);
1457098cbd601ad915aed22d4b5850da99359f25bf3Richard Smith    recordOut.writeText("# ");
1467098cbd601ad915aed22d4b5850da99359f25bf3Richard Smith    playbackOut.writeText("# ");
14759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    SkDebugf("---\n");
14859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
14959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        if (!includeBBoxType[bBoxType]) { continue; }
15059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        SkString out;
15159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        out.printf("%s ", kBBoxHierarchyTypeNames[bBoxType]);
1529eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        recordOut.writeText(out.c_str());
15359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        playbackOut.writeText(out.c_str());
15459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
15559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        if (FLAGS_record > 0) {
15659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            SkDebugf("Average %s recording time: %.3fms\n",
15759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                kBBoxHierarchyTypeNames[bBoxType],
15859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                globalMeasurement.fRecordAverage[bBoxType]);
15959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        }
16059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        if (FLAGS_playback > 0) {
1619eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith            SkDebugf("Average %s playback time: %.3fms\n",
16259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                kBBoxHierarchyTypeNames[bBoxType],
16359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith                globalMeasurement.fPlaybackAverage[bBoxType]);
16459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        }
16559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    }
16659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    recordOut.writeText("\n");
16759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    playbackOut.writeText("\n");
16859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    // Write to file, and save recording averages.
16959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    for (int index = 0; index < measurements.count(); ++index) {
170d7c56e1114bfe7d461786903bb720d2c6efc05a1Richard Smith        const Measurement& measurement = measurements[index];
17159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        SkString pbLine;
17259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        SkString recLine;
17359efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
17459efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        pbLine.printf("%d", index);
17559efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        recLine.printf("%d", index);
17659efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        for (int bBoxType = 0; bBoxType < kBBoxTypeCount; ++bBoxType) {
17759efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            if (!includeBBoxType[bBoxType]) { continue; }
17859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            pbLine.appendf(" %f", measurement.fPlaybackAverage[bBoxType]);
17959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith            recLine.appendf(" %f", measurement.fRecordAverage[bBoxType]);
18059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith        }
1819eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        pbLine.appendf("\n");
1829eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        recLine.appendf("\n");
1839eed49c2bb0f37bbfefefd0998b6303a686a66c0Richard Smith        playbackOut.writeText(pbLine.c_str());
1841bf9a9e6a5bdc0de7939908855dcddf46b661800Richard Smith        recordOut.writeText(recLine.c_str());
1851bf9a9e6a5bdc0de7939908855dcddf46b661800Richard Smith    }
1861bf9a9e6a5bdc0de7939908855dcddf46b661800Richard Smith    SkDebugf("\nWrote data to gnuplot-readable files: %s %s\n", pbTitle, recTitle);
1871bf9a9e6a5bdc0de7939908855dcddf46b661800Richard Smith    return 0;
18859efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith}
18959efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith
19059efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
19159efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smithint main(int argc, char** argv) {
19259efe266b804330f4c1f3a1b0ff783e67dd90378Richard Smith    return tool_main(argc, argv);
193099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith}
194099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith#endif
195099e7f647ccda915513f2b2ec53352dc756082d3Richard Smith