blob: c6aab7a5ba0ef8c941f2d646ea480452ec79b48d [file] [log] [blame]
reed@google.com8af03712013-06-11 19:18:44 +00001/*
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
reed@google.com664621a2013-06-11 19:24:08 +000015#include "gUniqueGlyphIDs.h"
reed@google.comc2652302013-06-12 15:50:26 +000016#define gUniqueGlyphIDs_Sentinel 0xFFFF
17
18static 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}
reed@google.com8af03712013-06-11 19:18:44 +000025
26class FontCacheBench : public SkBenchmark {
reed@google.comc2652302013-06-12 15:50:26 +000027 enum {
28 N = SkBENCHLOOP(50)
29 };
reed@google.com8af03712013-06-11 19:18:44 +000030
reed@google.comc2652302013-06-12 15:50:26 +000031public:
32 FontCacheBench(void* param) : INHERITED(param) {}
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +000033
reed@google.com8af03712013-06-11 19:18:44 +000034protected:
35 virtual const char* onGetName() SK_OVERRIDE {
36 return "fontcache";
37 }
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +000038
reed@google.com8af03712013-06-11 19:18:44 +000039 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
40 SkPaint paint;
41 this->setupPaint(&paint);
42 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +000043
reed@google.com2fef6d22013-06-11 20:25:53 +000044 const uint16_t* array = gUniqueGlyphIDs;
reed@google.comc2652302013-06-12 15:50:26 +000045 while (*array != gUniqueGlyphIDs_Sentinel) {
46 size_t count = count_glyphs(array);
reed@google.com2fef6d22013-06-11 20:25:53 +000047 for (int i = 0; i < N; ++i) {
reed@google.comc2652302013-06-12 15:50:26 +000048 paint.measureText(array, count * sizeof(uint16_t));
reed@google.com2fef6d22013-06-11 20:25:53 +000049 }
reed@google.comc2652302013-06-12 15:50:26 +000050 array += count + 1; // skip the sentinel
reed@google.com8af03712013-06-11 19:18:44 +000051 }
52 }
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +000053
reed@google.comc2652302013-06-12 15:50:26 +000054private:
55 typedef SkBenchmark INHERITED;
56};
reed@google.com8af03712013-06-11 19:18:44 +000057
reed@google.comc2652302013-06-12 15:50:26 +000058///////////////////////////////////////////////////////////////////////////////
59
60static uint32_t rotr(uint32_t value, unsigned bits) {
61 return (value >> bits) | (value << (32 - bits));
62}
63
64typedef uint32_t (*HasherProc)(uint32_t);
65
66static uint32_t hasher0(uint32_t value) {
67 value = value ^ (value >> 16);
68 return value ^ (value >> 8);
69}
70
71static uint32_t hasher2(uint32_t h) {
72 h ^= h >> 16;
73 h *= 0x85ebca6b;
74 h ^= h >> 13;
75 h *= 0xc2b2ae35;
76 h ^= h >> 16;
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +000077
reed@google.comc2652302013-06-12 15:50:26 +000078 h ^= (h >> 8);
79 return h;
80}
81
82static 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
93static int count_collisions(const uint16_t array[], int count, HasherProc proc,
94 unsigned hashMask) {
95 char table[kMaxHashCount];
96 sk_bzero(table, sizeof(table));
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +000097
reed@google.comc2652302013-06-12 15:50:26 +000098 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
107static 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
114class FontCacheEfficiency : public SkBenchmark {
115public:
116 FontCacheEfficiency(void* param) : INHERITED(param) {
117 if (false) dump_array(NULL, 0);
118 if (false) rotr(0, 0);
119 }
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +0000120
reed@google.comc2652302013-06-12 15:50:26 +0000121protected:
122 virtual const char* onGetName() SK_OVERRIDE {
123 return "fontefficiency";
124 }
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +0000125
reed@google.comc2652302013-06-12 15:50:26 +0000126 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 }
skia.committer@gmail.coma707fd52013-06-13 07:00:51 +0000152
reed@google.com8af03712013-06-11 19:18:44 +0000153private:
154 typedef SkBenchmark INHERITED;
155};
156
157///////////////////////////////////////////////////////////////////////////////
158
159DEF_BENCH( return new FontCacheBench(p); )
reed@google.comc2652302013-06-12 15:50:26 +0000160
161// undefine this to run the efficiency test
162//DEF_BENCH( return new FontCacheEfficiency(p); )