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