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