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