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 "SkBenchmark.h"
      9 #include "SkCanvas.h"
     10 #include "SkFontHost.h"
     11 #include "SkPaint.h"
     12 #include "SkString.h"
     13 #include "SkTemplates.h"
     14 
     15 #include "gUniqueGlyphIDs.h"
     16 #define gUniqueGlyphIDs_Sentinel    0xFFFF
     17 
     18 static int count_glyphs(const uint16_t start[]) {
     19     const uint16_t* curr = start;
     20     while (*curr != gUniqueGlyphIDs_Sentinel) {
     21         curr += 1;
     22     }
     23     return curr - start;
     24 }
     25 
     26 class FontCacheBench : public SkBenchmark {
     27     enum {
     28         N = SkBENCHLOOP(50)
     29     };
     30 
     31 public:
     32     FontCacheBench(void* param) : INHERITED(param) {}
     33 
     34 protected:
     35     virtual const char* onGetName() SK_OVERRIDE {
     36         return "fontcache";
     37     }
     38 
     39     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
     40         SkPaint paint;
     41         this->setupPaint(&paint);
     42         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     43 
     44         const uint16_t* array = gUniqueGlyphIDs;
     45         while (*array != gUniqueGlyphIDs_Sentinel) {
     46             size_t count = count_glyphs(array);
     47             for (int i = 0; i < N; ++i) {
     48                 paint.measureText(array, count * sizeof(uint16_t));
     49             }
     50             array += count + 1;    // skip the sentinel
     51         }
     52     }
     53 
     54 private:
     55     typedef SkBenchmark INHERITED;
     56 };
     57 
     58 ///////////////////////////////////////////////////////////////////////////////
     59 
     60 static uint32_t rotr(uint32_t value, unsigned bits) {
     61     return (value >> bits) | (value << (32 - bits));
     62 }
     63 
     64 typedef uint32_t (*HasherProc)(uint32_t);
     65 
     66 static uint32_t hasher0(uint32_t value) {
     67     value = value ^ (value >> 16);
     68     return value ^ (value >> 8);
     69 }
     70 
     71 static uint32_t hasher2(uint32_t h) {
     72     h ^= h >> 16;
     73     h *= 0x85ebca6b;
     74     h ^= h >> 13;
     75     h *= 0xc2b2ae35;
     76     h ^= h >> 16;
     77 
     78     h ^= (h >> 8);
     79     return h;
     80 }
     81 
     82 static const struct {
     83     const char* fName;
     84     HasherProc  fHasher;
     85 } gRec[] = {
     86     { "hasher0",  hasher0 },
     87     { "hasher2",  hasher2 },
     88 };
     89 
     90 #define kMaxHashBits   12
     91 #define kMaxHashCount  (1 << kMaxHashBits)
     92 
     93 static int count_collisions(const uint16_t array[], int count, HasherProc proc,
     94                             unsigned hashMask) {
     95     char table[kMaxHashCount];
     96     sk_bzero(table, sizeof(table));
     97 
     98     int collisions = 0;
     99     for (int i = 0; i < count; ++i) {
    100         int index = proc(array[i]) & hashMask;
    101         collisions += table[index];
    102         table[index] = 1;
    103     }
    104     return collisions;
    105 }
    106 
    107 static void dump_array(const uint16_t array[], int count) {
    108     for (int i = 0; i < count; ++i) {
    109         SkDebugf(" %d,", array[i]);
    110     }
    111     SkDebugf("\n");
    112 }
    113 
    114 class FontCacheEfficiency : public SkBenchmark {
    115 public:
    116     FontCacheEfficiency(void* param) : INHERITED(param) {
    117         if (false) dump_array(NULL, 0);
    118         if (false) rotr(0, 0);
    119     }
    120 
    121 protected:
    122     virtual const char* onGetName() SK_OVERRIDE {
    123         return "fontefficiency";
    124     }
    125 
    126     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    127         static bool gDone;
    128         if (gDone) {
    129             return;
    130         }
    131         gDone = true;
    132 
    133         for (int hashBits = 6; hashBits <= 12; hashBits += 1) {
    134             int hashMask = ((1 << hashBits) - 1);
    135             for (int limit = 32; limit <= 1024; limit <<= 1) {
    136                 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
    137                     int collisions = 0;
    138                     int glyphs = 0;
    139                     const uint16_t* array = gUniqueGlyphIDs;
    140                     while (*array != gUniqueGlyphIDs_Sentinel) {
    141                         int count = SkMin32(count_glyphs(array), limit);
    142                         collisions += count_collisions(array, count, gRec[i].fHasher, hashMask);
    143                         glyphs += count;
    144                         array += count + 1;    // skip the sentinel
    145                     }
    146                     SkDebugf("hashBits [%d] limit [%d] collisions [%d / %d = %1.2g%%] using %s\n", hashBits, limit, collisions, glyphs,
    147                              collisions * 100.0 / glyphs, gRec[i].fName);
    148                 }
    149             }
    150         }
    151     }
    152 
    153 private:
    154     typedef SkBenchmark INHERITED;
    155 };
    156 
    157 ///////////////////////////////////////////////////////////////////////////////
    158 
    159 DEF_BENCH( return new FontCacheBench(p); )
    160 
    161 // undefine this to run the efficiency test
    162 //DEF_BENCH( return new FontCacheEfficiency(p); )
    163