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