Home | History | Annotate | Download | only in bench
      1 /*
      2  * Copyright 2013 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 "SkChecksum.h"
     11 #include "SkFont.h"
     12 #include "SkPaint.h"
     13 #include "SkPath.h"
     14 #include "SkString.h"
     15 #include "SkTemplates.h"
     16 
     17 #include "gUniqueGlyphIDs.h"
     18 
     19 #define gUniqueGlyphIDs_Sentinel    0xFFFF
     20 
     21 static int count_glyphs(const uint16_t start[]) {
     22     const uint16_t* curr = start;
     23     while (*curr != gUniqueGlyphIDs_Sentinel) {
     24         curr += 1;
     25     }
     26     return static_cast<int>(curr - start);
     27 }
     28 
     29 class FontCacheBench : public Benchmark {
     30 public:
     31     FontCacheBench()  {}
     32 
     33 protected:
     34     const char* onGetName() override {
     35         return "fontcache";
     36     }
     37 
     38     void onDraw(int loops, SkCanvas* canvas) override {
     39         SkFont font;
     40         font.setEdging(SkFont::Edging::kAntiAlias);
     41 
     42         const uint16_t* array = gUniqueGlyphIDs;
     43         while (*array != gUniqueGlyphIDs_Sentinel) {
     44             int count = count_glyphs(array);
     45             for (int i = 0; i < loops; ++i) {
     46                 (void)font.measureText(array, count * sizeof(uint16_t), kGlyphID_SkTextEncoding);
     47             }
     48             array += count + 1;    // skip the sentinel
     49         }
     50     }
     51 
     52 private:
     53     typedef Benchmark INHERITED;
     54 };
     55 
     56 ///////////////////////////////////////////////////////////////////////////////
     57 
     58 static uint32_t rotr(uint32_t value, unsigned bits) {
     59     return (value >> bits) | (value << (32 - bits));
     60 }
     61 
     62 typedef uint32_t (*HasherProc)(uint32_t);
     63 
     64 static uint32_t hasher0(uint32_t value) {
     65     value = value ^ (value >> 16);
     66     return value ^ (value >> 8);
     67 }
     68 
     69 static const struct {
     70     const char* fName;
     71     HasherProc  fHasher;
     72 } gRec[] = {
     73     { "hasher0",  hasher0 },
     74     { "hasher2",  SkChecksum::Mix },
     75 };
     76 
     77 #define kMaxHashBits   12
     78 #define kMaxHashCount  (1 << kMaxHashBits)
     79 
     80 static int count_collisions(const uint16_t array[], int count, HasherProc proc,
     81                             unsigned hashMask) {
     82     char table[kMaxHashCount];
     83     sk_bzero(table, sizeof(table));
     84 
     85     int collisions = 0;
     86     for (int i = 0; i < count; ++i) {
     87         int index = proc(array[i]) & hashMask;
     88         collisions += table[index];
     89         table[index] = 1;
     90     }
     91     return collisions;
     92 }
     93 
     94 static void dump_array(const uint16_t array[], int count) {
     95     for (int i = 0; i < count; ++i) {
     96         SkDebugf(" %d,", array[i]);
     97     }
     98     SkDebugf("\n");
     99 }
    100 
    101 class FontCacheEfficiency : public Benchmark {
    102 public:
    103     FontCacheEfficiency()  {
    104         if (false) dump_array(nullptr, 0);
    105         if (false) rotr(0, 0);
    106     }
    107 
    108 protected:
    109     const char* onGetName() override {
    110         return "fontefficiency";
    111     }
    112 
    113     void onDraw(int loops, SkCanvas* canvas) override {
    114         static bool gDone;
    115         if (gDone) {
    116             return;
    117         }
    118         gDone = true;
    119 
    120         for (int hashBits = 6; hashBits <= 12; hashBits += 1) {
    121             int hashMask = ((1 << hashBits) - 1);
    122             for (int limit = 32; limit <= 1024; limit <<= 1) {
    123                 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
    124                     int collisions = 0;
    125                     int glyphs = 0;
    126                     const uint16_t* array = gUniqueGlyphIDs;
    127                     while (*array != gUniqueGlyphIDs_Sentinel) {
    128                         int count = SkMin32(count_glyphs(array), limit);
    129                         collisions += count_collisions(array, count, gRec[i].fHasher, hashMask);
    130                         glyphs += count;
    131                         array += count + 1;    // skip the sentinel
    132                     }
    133                     SkDebugf("hashBits [%d] limit [%d] collisions [%d / %d = %1.2g%%] using %s\n", hashBits, limit, collisions, glyphs,
    134                              collisions * 100.0 / glyphs, gRec[i].fName);
    135                 }
    136             }
    137         }
    138     }
    139 
    140 private:
    141     typedef Benchmark INHERITED;
    142 };
    143 DEF_BENCH( return new FontCacheBench(); )
    144 
    145 // undefine this to run the efficiency test
    146 //DEF_BENCH( return new FontCacheEfficiency(); )
    147 
    148 ///////////////////////////////////////////////////////////////////////////////
    149 
    150 class FontPathBench : public Benchmark {
    151     SkFont fFont;
    152     uint16_t fGlyphs[100];
    153     SkString fName;
    154     const bool fOneAtATime;
    155 
    156 public:
    157     FontPathBench(bool oneAtATime) : fOneAtATime(oneAtATime) {
    158         fName.printf("font-path-%s", oneAtATime ? "loop" : "batch");
    159     }
    160 
    161 protected:
    162     const char* onGetName() override {
    163         return fName.c_str();
    164     }
    165 
    166     bool isSuitableFor(Backend backend) override {
    167         return backend == kNonRendering_Backend;
    168     }
    169 
    170     void onDelayedSetup() override {
    171         fFont.setSize(32);
    172         for (size_t i = 0; i < SK_ARRAY_COUNT(fGlyphs); ++i) {
    173             fGlyphs[i] = i;
    174         }
    175     }
    176 
    177     void onDraw(int loops, SkCanvas* canvas) override {
    178         SkPath path;
    179         for (int i = 0; i < loops; ++i) {
    180             if (fOneAtATime) {
    181                 for (size_t i = 0; i < SK_ARRAY_COUNT(fGlyphs); ++i) {
    182                     fFont.getPath(fGlyphs[i], &path);
    183                 }
    184             } else {
    185                 fFont.getPaths(fGlyphs, SK_ARRAY_COUNT(fGlyphs),
    186                                [](const SkPath* src, const SkMatrix& mx, void* ctx) {
    187                                    if (src) {
    188                                        src->transform(mx, static_cast<SkPath*>(ctx));
    189                                    }
    190                                }, &path);
    191             }
    192         }
    193     }
    194 
    195 private:
    196     typedef Benchmark INHERITED;
    197 };
    198 DEF_BENCH( return new FontPathBench(true); )
    199 DEF_BENCH( return new FontPathBench(false); )
    200