• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bench/Benchmark.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkFont.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkString.h"
14 #include "include/private/SkChecksum.h"
15 #include "include/private/SkTemplates.h"
16 
17 #include "bench/gUniqueGlyphIDs.h"
18 
19 #define gUniqueGlyphIDs_Sentinel    0xFFFF
20 
count_glyphs(const uint16_t start[])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:
FontCacheBench()31     FontCacheBench()  {}
32 
33 protected:
onGetName()34     const char* onGetName() override {
35         return "fontcache";
36     }
37 
onDraw(int loops,SkCanvas * canvas)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), SkTextEncoding::kGlyphID);
47             }
48             array += count + 1;    // skip the sentinel
49         }
50     }
51 
52 private:
53     using INHERITED = Benchmark;
54 };
55 
56 ///////////////////////////////////////////////////////////////////////////////
57 
rotr(uint32_t value,unsigned bits)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 
hasher0(uint32_t value)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 
count_collisions(const uint16_t array[],int count,HasherProc proc,unsigned hashMask)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 
dump_array(const uint16_t array[],int count)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:
FontCacheEfficiency()103     FontCacheEfficiency()  {
104         if (false) dump_array(nullptr, 0);
105         if (false) rotr(0, 0);
106     }
107 
108 protected:
onGetName()109     const char* onGetName() override {
110         return "fontefficiency";
111     }
112 
onDraw(int loops,SkCanvas * canvas)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 = std::min(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     using INHERITED = Benchmark;
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:
FontPathBench(bool oneAtATime)157     FontPathBench(bool oneAtATime) : fOneAtATime(oneAtATime) {
158         fName.printf("font-path-%s", oneAtATime ? "loop" : "batch");
159     }
160 
161 protected:
onGetName()162     const char* onGetName() override {
163         return fName.c_str();
164     }
165 
isSuitableFor(Backend backend)166     bool isSuitableFor(Backend backend) override {
167         return backend == kNonRendering_Backend;
168     }
169 
onDelayedSetup()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 
onDraw(int loops,SkCanvas * canvas)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     using INHERITED = Benchmark;
197 };
198 DEF_BENCH( return new FontPathBench(true); )
199 DEF_BENCH( return new FontPathBench(false); )
200