OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBenchmark.h" | 8 #include "SkBenchmark.h" |
9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
10 #include "SkFontHost.h" | 10 #include "SkFontHost.h" |
11 #include "SkPaint.h" | 11 #include "SkPaint.h" |
12 #include "SkString.h" | 12 #include "SkString.h" |
13 #include "SkTemplates.h" | 13 #include "SkTemplates.h" |
14 | 14 |
15 #include "gUniqueGlyphIDs.h" | 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 } |
16 | 25 |
17 class FontCacheBench : public SkBenchmark { | 26 class FontCacheBench : public SkBenchmark { |
18 enum { N = SkBENCHLOOP(50) }; | 27 enum { |
| 28 N = SkBENCHLOOP(50) |
| 29 }; |
| 30 |
19 public: | 31 public: |
20 FontCacheBench(void* param) : INHERITED(param) { | 32 FontCacheBench(void* param) : INHERITED(param) {} |
21 } | 33 |
22 | |
23 protected: | 34 protected: |
24 virtual const char* onGetName() SK_OVERRIDE { | 35 virtual const char* onGetName() SK_OVERRIDE { |
25 return "fontcache"; | 36 return "fontcache"; |
26 } | 37 } |
27 | 38 |
28 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { | 39 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { |
29 SkPaint paint; | 40 SkPaint paint; |
30 this->setupPaint(&paint); | 41 this->setupPaint(&paint); |
31 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 42 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
32 | 43 |
33 const uint16_t* array = gUniqueGlyphIDs; | 44 const uint16_t* array = gUniqueGlyphIDs; |
34 while (*array != 0xFFFF) { | 45 while (*array != gUniqueGlyphIDs_Sentinel) { |
35 const uint16_t* end = array + 1; | 46 size_t count = count_glyphs(array); |
36 while (*end != 0xFFFF) { | 47 for (int i = 0; i < N; ++i) { |
37 end += 1; | 48 paint.measureText(array, count * sizeof(uint16_t)); |
38 } | 49 } |
39 for (int i = 0; i < N; ++i) { | 50 array += count + 1; // skip the sentinel |
40 size_t len = (end - array) * sizeof(uint16_t); | |
41 paint.measureText(array, len); | |
42 } | |
43 array = end + 1; // skip the sentinel | |
44 } | 51 } |
45 } | 52 } |
46 | 53 |
47 private: | 54 private: |
48 typedef SkBenchmark INHERITED; | 55 typedef SkBenchmark INHERITED; |
49 }; | 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].fHa
sher, 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 }; |
50 | 156 |
51 /////////////////////////////////////////////////////////////////////////////// | 157 /////////////////////////////////////////////////////////////////////////////// |
52 | 158 |
53 DEF_BENCH( return new FontCacheBench(p); ) | 159 DEF_BENCH( return new FontCacheBench(p); ) |
| 160 |
| 161 // undefine this to run the efficiency test |
| 162 //DEF_BENCH( return new FontCacheEfficiency(p); ) |
OLD | NEW |