/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Benchmark.h" #include "SkCanvas.h" #include "SkRTree.h" #include "SkRandom.h" #include "SkString.h" // confine rectangles to a smallish area, so queries generally hit something, and overlap occurs: static const SkScalar GENERATE_EXTENTS = 1000.0f; static const int NUM_BUILD_RECTS = 500; static const int NUM_QUERY_RECTS = 5000; static const int GRID_WIDTH = 100; typedef SkRect (*MakeRectProc)(SkRandom&, int, int); // Time how long it takes to build an R-Tree either bulk-loaded or not class RTreeBuildBench : public Benchmark { public: RTreeBuildBench(const char* name, MakeRectProc proc, SkRTree* tree) : fTree(tree) , fProc(proc) { fName.printf("rtree_%s_build", name); } virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { return backend == kNonRendering_Backend; } virtual ~RTreeBuildBench() { fTree->unref(); } protected: virtual const char* onGetName() SK_OVERRIDE { return fName.c_str(); } virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { SkRandom rand; SkAutoTMalloc rects(NUM_BUILD_RECTS); for (int i = 0; i < NUM_BUILD_RECTS; ++i) { rects[i] = fProc(rand, i, NUM_BUILD_RECTS); } for (int i = 0; i < loops; ++i) { fTree->insert(&rects, NUM_BUILD_RECTS); SkASSERT(rects != NULL); // It'd break this bench if the tree took ownership of rects. fTree->clear(); } } private: SkRTree* fTree; MakeRectProc fProc; SkString fName; typedef Benchmark INHERITED; }; // Time how long it takes to perform queries on an R-Tree, bulk-loaded or not class RTreeQueryBench : public Benchmark { public: RTreeQueryBench(const char* name, MakeRectProc proc, SkRTree* tree) : fTree(tree) , fProc(proc) { fName.printf("rtree_%s_query", name); } virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { return backend == kNonRendering_Backend; } virtual ~RTreeQueryBench() { fTree->unref(); } protected: virtual const char* onGetName() SK_OVERRIDE { return fName.c_str(); } virtual void onPreDraw() SK_OVERRIDE { SkRandom rand; SkAutoTMalloc rects(NUM_QUERY_RECTS); for (int i = 0; i < NUM_QUERY_RECTS; ++i) { rects[i] = fProc(rand, i, NUM_QUERY_RECTS); } fTree->insert(&rects, NUM_QUERY_RECTS); } virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { SkRandom rand; for (int i = 0; i < loops; ++i) { SkTDArray hits; SkRect query; query.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS); query.fTop = rand.nextRangeF(0, GENERATE_EXTENTS); query.fRight = query.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2); query.fBottom = query.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2); fTree->search(query, &hits); } } private: SkBBoxHierarchy* fTree; MakeRectProc fProc; SkString fName; typedef Benchmark INHERITED; }; static inline SkRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) { SkRect out = SkRect::MakeWH(SkIntToScalar(index+1), SkIntToScalar(index+1)); return out; } static inline SkRect make_XYordered_rects(SkRandom& rand, int index, int numRects) { SkRect out; out.fLeft = SkIntToScalar(index % GRID_WIDTH); out.fTop = SkIntToScalar(index / GRID_WIDTH); out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3); out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3); return out; } static inline SkRect make_YXordered_rects(SkRandom& rand, int index, int numRects) { SkRect out; out.fLeft = SkIntToScalar(index / GRID_WIDTH); out.fTop = SkIntToScalar(index % GRID_WIDTH); out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3); out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3); return out; } static inline SkRect make_random_rects(SkRandom& rand, int index, int numRects) { SkRect out; out.fLeft = rand.nextRangeF(0, GENERATE_EXTENTS); out.fTop = rand.nextRangeF(0, GENERATE_EXTENTS); out.fRight = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5); out.fBottom = out.fTop + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5); return out; } /////////////////////////////////////////////////////////////////////////////// DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("XY_sorted", &make_XYordered_rects, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("XY_unsorted", &make_XYordered_rects, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("YX_sorted", &make_YXordered_rects, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("YX_unsorted", &make_YXordered_rects, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("random_sorted", &make_random_rects, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("random_unsorted", &make_random_rects, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("concentric_sorted", &make_concentric_rects_increasing, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeBuildBench, ("concentric_unsorted", &make_concentric_rects_increasing, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("XY_sorted", &make_XYordered_rects, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("XY_unsorted", &make_XYordered_rects, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("YX_sorted", &make_YXordered_rects, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("YX_unsorted", &make_YXordered_rects, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("random_sorted", &make_random_rects, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("random_unsorted", &make_random_rects, SkRTree::Create(5, 16, 1, false)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("concentric_sorted", &make_concentric_rects_increasing, SkRTree::Create(5, 16)));) DEF_BENCH(return SkNEW_ARGS(RTreeQueryBench, ("concentric_unsorted", &make_concentric_rects_increasing, SkRTree::Create(5, 16, 1, false)));)