• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 "src/core/SkStrike.h"
9 
10 #include "bench/Benchmark.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkGraphics.h"
14 #include "include/core/SkTypeface.h"
15 #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
16 #include "src/base/SkTLazy.h"
17 #include "src/core/SkStrikeSpec.h"
18 #include "src/core/SkTaskGroup.h"
19 #include "src/core/SkTextBlobTrace.h"
20 #include "tools/Resources.h"
21 #include "tools/ToolUtils.h"
22 
do_font_stuff(SkFont * font)23 static void do_font_stuff(SkFont* font) {
24     SkPaint defaultPaint;
25     for (SkScalar i = 8; i < 64; i++) {
26         font->setSize(i);
27         auto strikeSpec = SkStrikeSpec::MakeMask(
28                 *font,  defaultPaint, SkSurfaceProps(0, kUnknown_SkPixelGeometry),
29                 SkScalerContextFlags::kNone, SkMatrix::I());
30         SkPackedGlyphID glyphs['z'];
31         for (int c = ' '; c < 'z'; c++) {
32             glyphs[c] = SkPackedGlyphID{font->unicharToGlyph(c)};
33         }
34         constexpr size_t glyphCount = 'z' - ' ';
35         SkSpan<const SkPackedGlyphID> glyphIDs{&glyphs[SkTo<int>(' ')], glyphCount};
36         SkBulkGlyphMetricsAndImages images{strikeSpec};
37         for (int lookups = 0; lookups < 10; lookups++) {
38             (void)images.glyphs(glyphIDs);
39         }
40     }
41 }
42 
43 class SkGlyphCacheBasic : public Benchmark {
44 public:
SkGlyphCacheBasic(size_t cacheSize)45     explicit SkGlyphCacheBasic(size_t cacheSize) : fCacheSize(cacheSize) { }
46 
47 protected:
onGetName()48     const char* onGetName() override {
49         fName.printf("SkGlyphCacheBasic%dK", (int)(fCacheSize >> 10));
50         return fName.c_str();
51     }
52 
isSuitableFor(Backend backend)53     bool isSuitableFor(Backend backend) override {
54         return backend == kNonRendering_Backend;
55     }
56 
onDraw(int loops,SkCanvas *)57     void onDraw(int loops, SkCanvas*) override {
58         size_t oldCacheLimitSize = SkGraphics::GetFontCacheLimit();
59         SkGraphics::SetFontCacheLimit(fCacheSize);
60         SkFont font;
61         font.setEdging(SkFont::Edging::kAntiAlias);
62         font.setSubpixel(true);
63         font.setTypeface(ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()));
64 
65         for (int work = 0; work < loops; work++) {
66             do_font_stuff(&font);
67         }
68         SkGraphics::SetFontCacheLimit(oldCacheLimitSize);
69     }
70 
71 private:
72     using INHERITED = Benchmark;
73     const size_t fCacheSize;
74     SkString fName;
75 };
76 
77 class SkGlyphCacheStressTest : public Benchmark {
78 public:
SkGlyphCacheStressTest(int cacheSize)79     explicit SkGlyphCacheStressTest(int cacheSize) : fCacheSize(cacheSize) { }
80 
81 protected:
onGetName()82     const char* onGetName() override {
83         fName.printf("SkGlyphCacheStressTest%dK", (int)(fCacheSize >> 10));
84         return fName.c_str();
85     }
86 
isSuitableFor(Backend backend)87     bool isSuitableFor(Backend backend) override {
88         return backend == kNonRendering_Backend;
89     }
90 
onDraw(int loops,SkCanvas *)91     void onDraw(int loops, SkCanvas*) override {
92         size_t oldCacheLimitSize = SkGraphics::GetFontCacheLimit();
93         SkGraphics::SetFontCacheLimit(fCacheSize);
94         sk_sp<SkTypeface> typefaces[] = {
95                 ToolUtils::create_portable_typeface("serif", SkFontStyle::Italic()),
96                 ToolUtils::create_portable_typeface("sans-serif", SkFontStyle::Italic())};
97 
98         for (int work = 0; work < loops; work++) {
99             SkTaskGroup().batch(16, [&](int threadIndex) {
100                 SkFont font;
101                 font.setEdging(SkFont::Edging::kAntiAlias);
102                 font.setSubpixel(true);
103                 font.setTypeface(typefaces[threadIndex % 2]);
104                 do_font_stuff(&font);
105             });
106         }
107         SkGraphics::SetFontCacheLimit(oldCacheLimitSize);
108     }
109 
110 private:
111     using INHERITED = Benchmark;
112     const size_t fCacheSize;
113     SkString fName;
114 };
115 
116 DEF_BENCH( return new SkGlyphCacheBasic(256 * 1024); )
117 DEF_BENCH( return new SkGlyphCacheBasic(32 * 1024 * 1024); )
118 DEF_BENCH( return new SkGlyphCacheStressTest(256 * 1024); )
119 DEF_BENCH( return new SkGlyphCacheStressTest(32 * 1024 * 1024); )
120 
121 namespace {
122 class DiscardableManager : public SkStrikeServer::DiscardableHandleManager,
123                            public SkStrikeClient::DiscardableHandleManager {
124 public:
DiscardableManager()125     DiscardableManager() { sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount)); }
126     ~DiscardableManager() override = default;
127 
128     // Server implementation.
createHandle()129     SkDiscardableHandleId createHandle() override {
130         SkAutoMutexExclusive l(fMutex);
131 
132         // Handles starts as locked.
133         fLockedHandles.add(++fNextHandleId);
134         return fNextHandleId;
135     }
lockHandle(SkDiscardableHandleId id)136     bool lockHandle(SkDiscardableHandleId id) override {
137         SkAutoMutexExclusive l(fMutex);
138 
139         if (id <= fLastDeletedHandleId) return false;
140         fLockedHandles.add(id);
141         return true;
142     }
143 
144     // Client implementation.
deleteHandle(SkDiscardableHandleId id)145     bool deleteHandle(SkDiscardableHandleId id) override {
146         SkAutoMutexExclusive l(fMutex);
147 
148         return id <= fLastDeletedHandleId;
149     }
150 
notifyCacheMiss(SkStrikeClient::CacheMissType type,int fontSize)151     void notifyCacheMiss(SkStrikeClient::CacheMissType type, int fontSize) override {
152         SkAutoMutexExclusive l(fMutex);
153 
154         fCacheMissCount[type]++;
155     }
isHandleDeleted(SkDiscardableHandleId id)156     bool isHandleDeleted(SkDiscardableHandleId id) override {
157         SkAutoMutexExclusive l(fMutex);
158 
159         return id <= fLastDeletedHandleId;
160     }
161 
unlockAll()162     void unlockAll() {
163         SkAutoMutexExclusive l(fMutex);
164 
165         fLockedHandles.reset();
166     }
unlockAndDeleteAll()167     void unlockAndDeleteAll() {
168         SkAutoMutexExclusive l(fMutex);
169 
170         fLockedHandles.reset();
171         fLastDeletedHandleId = fNextHandleId;
172     }
lockedHandles() const173     const SkTHashSet<SkDiscardableHandleId>& lockedHandles() const {
174         SkAutoMutexExclusive l(fMutex);
175 
176         return fLockedHandles;
177     }
handleCount()178     SkDiscardableHandleId handleCount() {
179         SkAutoMutexExclusive l(fMutex);
180 
181         return fNextHandleId;
182     }
cacheMissCount(uint32_t type)183     int cacheMissCount(uint32_t type) {
184         SkAutoMutexExclusive l(fMutex);
185 
186         return fCacheMissCount[type];
187     }
hasCacheMiss() const188     bool hasCacheMiss() const {
189         SkAutoMutexExclusive l(fMutex);
190 
191         for (uint32_t i = 0; i <= SkStrikeClient::CacheMissType::kLast; ++i) {
192             if (fCacheMissCount[i] > 0) return true;
193         }
194         return false;
195     }
resetCacheMissCounts()196     void resetCacheMissCounts() {
197         SkAutoMutexExclusive l(fMutex);
198         sk_bzero(&fCacheMissCount, sizeof(fCacheMissCount));
199     }
200 
201 private:
202     // The tests below run in parallel on multiple threads and use the same
203     // process global SkStrikeCache. So the implementation needs to be
204     // thread-safe.
205     mutable SkMutex fMutex;
206 
207     SkDiscardableHandleId fNextHandleId = 0u;
208     SkDiscardableHandleId fLastDeletedHandleId = 0u;
209     SkTHashSet<SkDiscardableHandleId> fLockedHandles;
210     int fCacheMissCount[SkStrikeClient::CacheMissType::kLast + 1u];
211 };
212 
213 class DiffCanvasBench : public Benchmark {
214     SkString fBenchName;
215     std::function<std::unique_ptr<SkStreamAsset>()> fDataProvider;
216     std::vector<SkTextBlobTrace::Record> fTrace;
217     sk_sp<DiscardableManager> fDiscardableManager;
218     SkTLazy<SkStrikeServer> fServer;
219 
onGetName()220     const char* onGetName() override { return fBenchName.c_str(); }
221 
isSuitableFor(Backend b)222     bool isSuitableFor(Backend b) override { return b == kNonRendering_Backend; }
223 
onDraw(int loops,SkCanvas * modelCanvas)224     void onDraw(int loops, SkCanvas* modelCanvas) override {
225         SkSurfaceProps props;
226         if (modelCanvas) { modelCanvas->getProps(&props); }
227         std::unique_ptr<SkCanvas> canvas = fServer->makeAnalysisCanvas(1024, 1024, props,
228                                                                        nullptr, true, true);
229         loops *= 100;
230         while (loops --> 0) {
231             for (const auto& record : fTrace) {
232                 canvas->drawTextBlob(
233                         record.blob.get(), record.offset.x(), record.offset.y(),record.paint);
234             }
235         }
236     }
237 
onDelayedSetup()238     void onDelayedSetup() override {
239         auto stream = fDataProvider();
240         fDiscardableManager = sk_make_sp<DiscardableManager>();
241         fServer.init(fDiscardableManager.get());
242         fTrace = SkTextBlobTrace::CreateBlobTrace(stream.get());
243     }
244 
245 public:
DiffCanvasBench(SkString n,std::function<std::unique_ptr<SkStreamAsset> ()> f)246     DiffCanvasBench(SkString n, std::function<std::unique_ptr<SkStreamAsset>()> f)
247         : fBenchName(std::move(n)), fDataProvider(std::move(f)) {}
248 };
249 }  // namespace
250 
CreateDiffCanvasBench(SkString name,std::function<std::unique_ptr<SkStreamAsset> ()> dataSrc)251 Benchmark* CreateDiffCanvasBench(
252         SkString name, std::function<std::unique_ptr<SkStreamAsset>()> dataSrc) {
253     return new DiffCanvasBench(std::move(name), std::move(dataSrc));
254 }
255 
256 DEF_BENCH( return CreateDiffCanvasBench(
257         SkString("SkDiffBench-lorem_ipsum"),
__anon54bbae630302()258         [](){ return GetResourceAsStream("diff_canvas_traces/lorem_ipsum.trace"); }));
259