Home | History | Annotate | Download | only in bench
      1 
      2 /*
      3  * Copyright 2012 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "Benchmark.h"
     10 #include "SkCanvas.h"
     11 #include "SkRTree.h"
     12 #include "SkRandom.h"
     13 #include "SkString.h"
     14 
     15 // confine rectangles to a smallish area, so queries generally hit something, and overlap occurs:
     16 static const SkScalar GENERATE_EXTENTS = 1000.0f;
     17 static const int NUM_BUILD_RECTS = 500;
     18 static const int NUM_QUERY_RECTS = 5000;
     19 static const int GRID_WIDTH = 100;
     20 
     21 typedef SkRect (*MakeRectProc)(SkRandom&, int, int);
     22 
     23 // Time how long it takes to build an R-Tree either bulk-loaded or not
     24 class RTreeBuildBench : public Benchmark {
     25 public:
     26     RTreeBuildBench(const char* name, MakeRectProc proc, bool bulkLoad,
     27                     SkBBoxHierarchy* tree)
     28         : fTree(tree)
     29         , fProc(proc)
     30         , fBulkLoad(bulkLoad) {
     31         fName.append("rtree_");
     32         fName.append(name);
     33         fName.append("_build");
     34         if (fBulkLoad) {
     35             fName.append("_bulk");
     36         }
     37     }
     38 
     39     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
     40         return backend == kNonRendering_Backend;
     41     }
     42 
     43     virtual ~RTreeBuildBench() {
     44         fTree->unref();
     45     }
     46 protected:
     47     virtual const char* onGetName() SK_OVERRIDE {
     48         return fName.c_str();
     49     }
     50     virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
     51         SkRandom rand;
     52         for (int i = 0; i < loops; ++i) {
     53             for (int j = 0; j < NUM_BUILD_RECTS; ++j) {
     54                 fTree->insert(reinterpret_cast<void*>(j), fProc(rand, j, NUM_BUILD_RECTS),
     55                               fBulkLoad);
     56             }
     57             fTree->flushDeferredInserts();
     58             fTree->clear();
     59         }
     60     }
     61 private:
     62     SkBBoxHierarchy* fTree;
     63     MakeRectProc fProc;
     64     SkString fName;
     65     bool fBulkLoad;
     66     typedef Benchmark INHERITED;
     67 };
     68 
     69 // Time how long it takes to perform queries on an R-Tree, bulk-loaded or not
     70 class RTreeQueryBench : public Benchmark {
     71 public:
     72     enum QueryType {
     73         kSmall_QueryType, // small queries
     74         kLarge_QueryType, // large queries
     75         kRandom_QueryType,// randomly sized queries
     76         kFull_QueryType   // queries that cover everything
     77     };
     78 
     79     RTreeQueryBench(const char* name, MakeRectProc proc, bool bulkLoad,
     80                     QueryType q, SkBBoxHierarchy* tree)
     81         : fTree(tree)
     82         , fProc(proc)
     83         , fBulkLoad(bulkLoad)
     84         , fQuery(q) {
     85         fName.append("rtree_");
     86         fName.append(name);
     87         fName.append("_query");
     88         if (fBulkLoad) {
     89             fName.append("_bulk");
     90         }
     91     }
     92 
     93     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
     94         return backend == kNonRendering_Backend;
     95     }
     96 
     97     virtual ~RTreeQueryBench() {
     98         fTree->unref();
     99     }
    100 protected:
    101     virtual const char* onGetName() SK_OVERRIDE {
    102         return fName.c_str();
    103     }
    104     virtual void onPreDraw() SK_OVERRIDE {
    105         SkRandom rand;
    106         for (int j = 0; j < NUM_QUERY_RECTS; ++j) {
    107             fTree->insert(reinterpret_cast<void*>(j),
    108                           fProc(rand, j, NUM_QUERY_RECTS),
    109                           fBulkLoad);
    110         }
    111         fTree->flushDeferredInserts();
    112     }
    113 
    114     virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
    115         SkRandom rand;
    116         for (int i = 0; i < loops; ++i) {
    117             SkTDArray<void*> hits;
    118             SkRect query;
    119             switch(fQuery) {
    120                 case kSmall_QueryType:
    121                     query.fLeft   = rand.nextRangeF(0, GENERATE_EXTENTS);
    122                     query.fTop    = rand.nextRangeF(0, GENERATE_EXTENTS);
    123                     query.fRight  = query.fLeft + (GENERATE_EXTENTS / 20);
    124                     query.fBottom = query.fTop  + (GENERATE_EXTENTS / 20);
    125                     break;
    126                 case kLarge_QueryType:
    127                     query.fLeft   = rand.nextRangeF(0, GENERATE_EXTENTS);
    128                     query.fTop    = rand.nextRangeF(0, GENERATE_EXTENTS);
    129                     query.fRight  = query.fLeft + (GENERATE_EXTENTS / 2);
    130                     query.fBottom = query.fTop  + (GENERATE_EXTENTS / 2);
    131                     break;
    132                 case kFull_QueryType:
    133                     query.fLeft   = -GENERATE_EXTENTS;
    134                     query.fTop    = -GENERATE_EXTENTS;
    135                     query.fRight  = 2 * GENERATE_EXTENTS;
    136                     query.fBottom = 2 * GENERATE_EXTENTS;
    137                     break;
    138                 default: // fallthrough
    139                 case kRandom_QueryType:
    140                     query.fLeft   = rand.nextRangeF(0, GENERATE_EXTENTS);
    141                     query.fTop    = rand.nextRangeF(0, GENERATE_EXTENTS);
    142                     query.fRight  = query.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
    143                     query.fBottom = query.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/2);
    144                     break;
    145             };
    146             fTree->search(query, &hits);
    147         }
    148     }
    149 private:
    150     SkBBoxHierarchy* fTree;
    151     MakeRectProc fProc;
    152     SkString fName;
    153     bool fBulkLoad;
    154     QueryType fQuery;
    155     typedef Benchmark INHERITED;
    156 };
    157 
    158 static inline SkRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) {
    159     SkRect out = SkRect::MakeWH(SkIntToScalar(index+1), SkIntToScalar(index+1));
    160     return out;
    161 }
    162 
    163 static inline SkRect make_XYordered_rects(SkRandom& rand, int index, int numRects) {
    164     SkRect out;
    165     out.fLeft   = SkIntToScalar(index % GRID_WIDTH);
    166     out.fTop    = SkIntToScalar(index / GRID_WIDTH);
    167     out.fRight  = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
    168     out.fBottom = out.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
    169     return out;
    170 }
    171 static inline SkRect make_YXordered_rects(SkRandom& rand, int index, int numRects) {
    172     SkRect out;
    173     out.fLeft   = SkIntToScalar(index / GRID_WIDTH);
    174     out.fTop    = SkIntToScalar(index % GRID_WIDTH);
    175     out.fRight  = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
    176     out.fBottom = out.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/3);
    177     return out;
    178 }
    179 
    180 static inline SkRect make_random_rects(SkRandom& rand, int index, int numRects) {
    181     SkRect out;
    182     out.fLeft   = rand.nextRangeF(0, GENERATE_EXTENTS);
    183     out.fTop    = rand.nextRangeF(0, GENERATE_EXTENTS);
    184     out.fRight  = out.fLeft + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
    185     out.fBottom = out.fTop  + 1 + rand.nextRangeF(0, GENERATE_EXTENTS/5);
    186     return out;
    187 }
    188 
    189 ///////////////////////////////////////////////////////////////////////////////
    190 
    191 DEF_BENCH(
    192     return SkNEW_ARGS(RTreeBuildBench, ("XYordered", &make_XYordered_rects, false,
    193                       SkRTree::Create(5, 16)));
    194 )
    195 DEF_BENCH(
    196     return SkNEW_ARGS(RTreeBuildBench, ("XYordered", &make_XYordered_rects, true,
    197                       SkRTree::Create(5, 16)));
    198 )
    199 DEF_BENCH(
    200     return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)XYordered", &make_XYordered_rects, true,
    201                       SkRTree::Create(5, 16, 1, false)));
    202 )
    203 DEF_BENCH(
    204     return SkNEW_ARGS(RTreeQueryBench, ("XYordered", &make_XYordered_rects, true,
    205                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16)));
    206 )
    207 DEF_BENCH(
    208     return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)XYordered", &make_XYordered_rects, true,
    209                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false)));
    210 )
    211 
    212 DEF_BENCH(
    213     return SkNEW_ARGS(RTreeBuildBench, ("YXordered", &make_YXordered_rects, false,
    214                       SkRTree::Create(5, 16)));
    215 )
    216 DEF_BENCH(
    217     return SkNEW_ARGS(RTreeBuildBench, ("YXordered", &make_YXordered_rects, true,
    218                       SkRTree::Create(5, 16)));
    219 )
    220 DEF_BENCH(
    221     return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)YXordered", &make_YXordered_rects, true,
    222                       SkRTree::Create(5, 16, 1, false)));
    223 )
    224 DEF_BENCH(
    225     return SkNEW_ARGS(RTreeQueryBench, ("YXordered", &make_YXordered_rects, true,
    226                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16)));
    227 )
    228 DEF_BENCH(
    229     return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)YXordered", &make_YXordered_rects, true,
    230                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false)));
    231 )
    232 
    233 DEF_BENCH(
    234     return SkNEW_ARGS(RTreeBuildBench, ("random", &make_random_rects, false,
    235                       SkRTree::Create(5, 16)));
    236 )
    237 DEF_BENCH(
    238     return SkNEW_ARGS(RTreeBuildBench, ("random", &make_random_rects, true,
    239                       SkRTree::Create(5, 16)));
    240 )
    241 DEF_BENCH(
    242     return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)random", &make_random_rects, true,
    243                       SkRTree::Create(5, 16, 1, false)));
    244 )
    245 DEF_BENCH(
    246     return SkNEW_ARGS(RTreeQueryBench, ("random", &make_random_rects, true,
    247                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16)));
    248 )
    249 DEF_BENCH(
    250     return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)random", &make_random_rects, true,
    251                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false)));
    252 )
    253 
    254 DEF_BENCH(
    255     return SkNEW_ARGS(RTreeBuildBench, ("concentric",
    256                       &make_concentric_rects_increasing, true, SkRTree::Create(5, 16)));
    257 )
    258 DEF_BENCH(
    259     return SkNEW_ARGS(RTreeBuildBench, ("(unsorted)concentric",
    260                       &make_concentric_rects_increasing, true, SkRTree::Create(5, 16, 1, false)));
    261 )
    262 DEF_BENCH(
    263     return SkNEW_ARGS(RTreeQueryBench, ("concentric", &make_concentric_rects_increasing, true,
    264                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16)));
    265 )
    266 DEF_BENCH(
    267     return SkNEW_ARGS(RTreeQueryBench, ("(unsorted)concentric", &make_concentric_rects_increasing, true,
    268                       RTreeQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false)));
    269 )
    270