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