Flutter Engine
paragraph_benchmarks.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <minikin/Layout.h>
18 
19 #include <cstring>
20 
21 #include "flutter/fml/command_line.h"
22 #include "flutter/fml/logging.h"
23 #include "flutter/third_party/txt/tests/txt_test_utils.h"
24 #include "minikin/LayoutUtils.h"
25 #include "third_party/benchmark/include/benchmark/benchmark_api.h"
26 #include "third_party/icu/source/common/unicode/unistr.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "third_party/skia/include/core/SkCanvas.h"
29 #include "third_party/skia/include/core/SkColor.h"
30 #include "txt/font_collection.h"
31 #include "txt/font_skia.h"
32 #include "txt/font_style.h"
33 #include "txt/font_weight.h"
34 #include "txt/paragraph.h"
36 
37 namespace txt {
38 
39 class ParagraphFixture : public benchmark::Fixture {
40  public:
41  void SetUp(const benchmark::State& state) {
43 
44  bitmap_ = std::make_unique<SkBitmap>();
45  bitmap_->allocN32Pixels(1000, 1000);
46  canvas_ = std::make_unique<SkCanvas>(*bitmap_);
47  canvas_->clear(SK_ColorWHITE);
48  }
49 
50  void TearDown(const benchmark::State& state) { font_collection_.reset(); }
51 
52  protected:
53  std::shared_ptr<FontCollection> font_collection_;
54  std::unique_ptr<SkCanvas> canvas_;
55  std::unique_ptr<SkBitmap> bitmap_;
56 };
57 
58 BENCHMARK_F(ParagraphFixture, ShortLayout)(benchmark::State& state) {
59  const char* text = "Hello World";
60  auto icu_text = icu::UnicodeString::fromUTF8(text);
61  std::u16string u16_text(icu_text.getBuffer(),
62  icu_text.getBuffer() + icu_text.length());
63 
64  txt::ParagraphStyle paragraph_style;
65 
66  txt::TextStyle text_style;
67  text_style.font_families = std::vector<std::string>(1, "Roboto");
68  text_style.color = SK_ColorBLACK;
69  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
70 
71  builder.PushStyle(text_style);
72  builder.AddText(u16_text);
73  builder.Pop();
74  auto paragraph = BuildParagraph(builder);
75  while (state.KeepRunning()) {
76  paragraph->SetDirty();
77  paragraph->Layout(300);
78  }
79 }
80 
81 BENCHMARK_F(ParagraphFixture, LongLayout)(benchmark::State& state) {
82  const char* text =
83  "This is a very long sentence to test if the text will properly wrap "
84  "around and go to the next line. Sometimes, short sentence. Longer "
85  "sentences are okay too because they are necessary. Very short. "
86  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
87  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
88  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
89  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
90  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
91  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
92  "mollit anim id est laborum. "
93  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
94  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
95  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
96  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
97  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
98  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
99  "mollit anim id est laborum.";
100  auto icu_text = icu::UnicodeString::fromUTF8(text);
101  std::u16string u16_text(icu_text.getBuffer(),
102  icu_text.getBuffer() + icu_text.length());
103 
104  txt::ParagraphStyle paragraph_style;
105 
106  txt::TextStyle text_style;
107  text_style.font_families = std::vector<std::string>(1, "Roboto");
108  text_style.color = SK_ColorBLACK;
109 
110  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
111 
112  builder.PushStyle(text_style);
113  builder.AddText(u16_text);
114  builder.Pop();
115  auto paragraph = BuildParagraph(builder);
116  while (state.KeepRunning()) {
117  paragraph->SetDirty();
118  paragraph->Layout(300);
119  }
120 }
121 
122 BENCHMARK_F(ParagraphFixture, JustifyLayout)(benchmark::State& state) {
123  const char* text =
124  "This is a very long sentence to test if the text will properly wrap "
125  "around and go to the next line. Sometimes, short sentence. Longer "
126  "sentences are okay too because they are necessary. Very short. "
127  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
128  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
129  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
130  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
131  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
132  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
133  "mollit anim id est laborum. "
134  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
135  "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
136  "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
137  "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
138  "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
139  "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
140  "mollit anim id est laborum.";
141  auto icu_text = icu::UnicodeString::fromUTF8(text);
142  std::u16string u16_text(icu_text.getBuffer(),
143  icu_text.getBuffer() + icu_text.length());
144 
145  txt::ParagraphStyle paragraph_style;
146  paragraph_style.text_align = TextAlign::justify;
147 
148  txt::TextStyle text_style;
149  text_style.font_families = std::vector<std::string>(1, "Roboto");
150  text_style.color = SK_ColorBLACK;
151 
152  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
153 
154  builder.PushStyle(text_style);
155  builder.AddText(u16_text);
156  builder.Pop();
157  auto paragraph = BuildParagraph(builder);
158  while (state.KeepRunning()) {
159  paragraph->SetDirty();
160  paragraph->Layout(300);
161  }
162 }
163 
164 BENCHMARK_F(ParagraphFixture, ManyStylesLayout)(benchmark::State& state) {
165  const char* text = "-";
166  auto icu_text = icu::UnicodeString::fromUTF8(text);
167  std::u16string u16_text(icu_text.getBuffer(),
168  icu_text.getBuffer() + icu_text.length());
169 
170  txt::ParagraphStyle paragraph_style;
171 
172  txt::TextStyle text_style;
173  text_style.font_families = std::vector<std::string>(1, "Roboto");
174  text_style.color = SK_ColorBLACK;
175  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
176  for (int i = 0; i < 1000; ++i) {
177  builder.PushStyle(text_style);
178  builder.AddText(u16_text);
179  }
180  auto paragraph = BuildParagraph(builder);
181  while (state.KeepRunning()) {
182  paragraph->SetDirty();
183  paragraph->Layout(300);
184  }
185 }
186 
187 BENCHMARK_DEFINE_F(ParagraphFixture, TextBigO)(benchmark::State& state) {
188  std::vector<uint16_t> text;
189  for (uint16_t i = 0; i < state.range(0); ++i) {
190  text.push_back(i % 5 == 0 ? ' ' : i);
191  }
192  std::u16string u16_text(text.data(), text.data() + text.size());
193 
194  txt::ParagraphStyle paragraph_style;
195  paragraph_style.font_family = "Roboto";
196 
197  txt::TextStyle text_style;
198  text_style.font_families = std::vector<std::string>(1, "Roboto");
199  text_style.color = SK_ColorBLACK;
200 
201  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
202 
203  builder.PushStyle(text_style);
204  builder.AddText(u16_text);
205  builder.Pop();
206  auto paragraph = BuildParagraph(builder);
207  while (state.KeepRunning()) {
208  paragraph->SetDirty();
209  paragraph->Layout(300);
210  }
211  state.SetComplexityN(state.range(0));
212 }
213 BENCHMARK_REGISTER_F(ParagraphFixture, TextBigO)
214  ->RangeMultiplier(4)
215  ->Range(1 << 6, 1 << 14)
216  ->Complexity(benchmark::oN);
217 
218 BENCHMARK_DEFINE_F(ParagraphFixture, StylesBigO)(benchmark::State& state) {
219  const char* text = "vry shrt ";
220  auto icu_text = icu::UnicodeString::fromUTF8(text);
221  std::u16string u16_text(icu_text.getBuffer(),
222  icu_text.getBuffer() + icu_text.length());
223 
224  txt::ParagraphStyle paragraph_style;
225 
226  txt::TextStyle text_style;
227  text_style.font_families = std::vector<std::string>(1, "Roboto");
228  text_style.color = SK_ColorBLACK;
229 
230  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
231 
232  for (int i = 0; i < state.range(0); ++i) {
233  builder.PushStyle(text_style);
234  builder.AddText(u16_text);
235  }
236  auto paragraph = BuildParagraph(builder);
237  while (state.KeepRunning()) {
238  paragraph->SetDirty();
239  paragraph->Layout(300);
240  }
241  state.SetComplexityN(state.range(0));
242 }
243 BENCHMARK_REGISTER_F(ParagraphFixture, StylesBigO)
244  ->RangeMultiplier(4)
245  ->Range(1 << 3, 1 << 12)
246  ->Complexity(benchmark::oN);
247 
248 BENCHMARK_F(ParagraphFixture, PaintSimple)(benchmark::State& state) {
249  const char* text = "Hello world! This is a simple sentence to test drawing.";
250  auto icu_text = icu::UnicodeString::fromUTF8(text);
251  std::u16string u16_text(icu_text.getBuffer(),
252  icu_text.getBuffer() + icu_text.length());
253 
254  txt::ParagraphStyle paragraph_style;
255 
256  txt::TextStyle text_style;
257  text_style.font_families = std::vector<std::string>(1, "Roboto");
258  text_style.color = SK_ColorBLACK;
259  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
260  builder.PushStyle(text_style);
261  builder.AddText(u16_text);
262  auto paragraph = BuildParagraph(builder);
263  paragraph->Layout(300);
264 
265  int offset = 0;
266  while (state.KeepRunning()) {
267  paragraph->Paint(canvas_.get(), offset % 700, 10);
268  offset++;
269  }
270 }
271 
272 BENCHMARK_F(ParagraphFixture, PaintLarge)(benchmark::State& state) {
273  const char* text =
274  "Hello world! This is a simple sentence to test drawing. Hello world! "
275  "This is a simple sentence to test drawing. Hello world! This is a "
276  "simple sentence to test drawing.Hello world! This is a simple sentence "
277  "to test drawing. Hello world! "
278  "This is a simple sentence to test drawing. Hello world! This is a "
279  "simple sentence to test drawing.Hello world! This is a simple sentence "
280  "to test drawing. Hello world! "
281  "This is a simple sentence to test drawing. Hello world! This is a "
282  "simple sentence to test drawing.Hello world! This is a simple sentence "
283  "to test drawing. Hello world! "
284  "This is a simple sentence to test drawing. Hello world! This is a "
285  "simple sentence to test drawing.Hello world! This is a simple sentence "
286  "to test drawing. Hello world! "
287  "This is a simple sentence to test drawing. Hello world! This is a "
288  "simple sentence to test drawing.Hello world! This is a simple sentence "
289  "to test drawing. Hello world! "
290  "This is a simple sentence to test drawing. Hello world! This is a "
291  "simple sentence to test drawing.";
292  auto icu_text = icu::UnicodeString::fromUTF8(text);
293  std::u16string u16_text(icu_text.getBuffer(),
294  icu_text.getBuffer() + icu_text.length());
295 
296  txt::ParagraphStyle paragraph_style;
297 
298  txt::TextStyle text_style;
299  text_style.font_families = std::vector<std::string>(1, "Roboto");
300  text_style.color = SK_ColorBLACK;
301  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
302  builder.PushStyle(text_style);
303  builder.AddText(u16_text);
304  auto paragraph = BuildParagraph(builder);
305  paragraph->Layout(300);
306 
307  int offset = 0;
308  while (state.KeepRunning()) {
309  paragraph->Paint(canvas_.get(), offset % 700, 10);
310  offset++;
311  }
312 }
313 
314 BENCHMARK_F(ParagraphFixture, PaintDecoration)(benchmark::State& state) {
315  const char* text =
316  "Hello world! This is a simple sentence to test drawing. Hello world! "
317  "This is a simple sentence to test drawing.";
318  auto icu_text = icu::UnicodeString::fromUTF8(text);
319  std::u16string u16_text(icu_text.getBuffer(),
320  icu_text.getBuffer() + icu_text.length());
321 
322  txt::ParagraphStyle paragraph_style;
323 
324  txt::TextStyle text_style;
325  text_style.font_families = std::vector<std::string>(1, "Roboto");
330  text_style.color = SK_ColorBLACK;
331 
332  txt::ParagraphBuilderTxt builder(paragraph_style, font_collection_);
333 
334  builder.PushStyle(text_style);
335  builder.AddText(u16_text);
336 
338  builder.PushStyle(text_style);
339  builder.AddText(u16_text);
340 
342  builder.PushStyle(text_style);
343  builder.AddText(u16_text);
344 
345  auto paragraph = BuildParagraph(builder);
346  paragraph->Layout(300);
347 
348  int offset = 0;
349  while (state.KeepRunning()) {
350  paragraph->Paint(canvas_.get(), offset % 700, 10);
351  offset++;
352  }
353 }
354 
355 // -----------------------------------------------------------------------------
356 //
357 // The following benchmarks break down the layout function and attempts to time
358 // each of the components to more finely attribute latency.
359 //
360 // -----------------------------------------------------------------------------
361 
362 BENCHMARK_DEFINE_F(ParagraphFixture, MinikinDoLayout)(benchmark::State& state) {
363  std::vector<uint16_t> text;
364  for (uint16_t i = 0; i < 16000 * 2; ++i) {
365  text.push_back(i % 5 == 0 ? ' ' : i);
366  }
367  minikin::FontStyle font;
368  txt::TextStyle text_style;
369  text_style.font_families = std::vector<std::string>(1, "Roboto");
370  minikin::MinikinPaint paint;
371 
372  font = minikin::FontStyle(4, false);
373  paint.size = text_style.font_size;
374  paint.letterSpacing = text_style.letter_spacing;
375  paint.wordSpacing = text_style.word_spacing;
376 
377  auto collection = font_collection_->GetMinikinFontCollectionForFamilies(
378  text_style.font_families, "en-US");
379 
380  while (state.KeepRunning()) {
381  minikin::Layout layout;
382  layout.doLayout(text.data(), 0, state.range(0), state.range(0), 0, font,
383  paint, collection);
384  }
385  state.SetComplexityN(state.range(0));
386 }
387 BENCHMARK_REGISTER_F(ParagraphFixture, MinikinDoLayout)
388  ->RangeMultiplier(4)
389  ->Range(1 << 7, 1 << 14)
390  ->Complexity(benchmark::oN);
391 
392 BENCHMARK_DEFINE_F(ParagraphFixture, AddStyleRun)(benchmark::State& state) {
393  std::vector<uint16_t> text;
394  for (uint16_t i = 0; i < 16000 * 2; ++i) {
395  text.push_back(i % 5 == 0 ? ' ' : i);
396  }
397  minikin::FontStyle font;
398  txt::TextStyle text_style;
399  text_style.font_families = std::vector<std::string>(1, "Roboto");
400  minikin::MinikinPaint paint;
401 
402  font = minikin::FontStyle(4, false);
403  paint.size = text_style.font_size;
404  paint.letterSpacing = text_style.letter_spacing;
405  paint.wordSpacing = text_style.word_spacing;
406 
407  minikin::LineBreaker breaker;
408  breaker.setLocale(icu::Locale(), nullptr);
409  breaker.resize(text.size());
410  memcpy(breaker.buffer(), text.data(), text.size() * sizeof(text[0]));
411  breaker.setText();
412 
413  while (state.KeepRunning()) {
414  for (int i = 0; i < 20; ++i) {
415  breaker.addStyleRun(&paint,
416  font_collection_->GetMinikinFontCollectionForFamilies(
417  std::vector<std::string>(1, "Roboto"), "en-US"),
418  font, state.range(0) / 20 * i,
419  state.range(0) / 20 * (i + 1), false);
420  }
421  }
422  state.SetComplexityN(state.range(0));
423 }
424 BENCHMARK_REGISTER_F(ParagraphFixture, AddStyleRun)
425  ->RangeMultiplier(4)
426  ->Range(1 << 7, 1 << 14)
427  ->Complexity(benchmark::oN);
428 
429 BENCHMARK_DEFINE_F(ParagraphFixture, SkTextBlobAlloc)(benchmark::State& state) {
430  SkFont font;
431  font.setEdging(SkFont::Edging::kAntiAlias);
432  font.setSize(14);
433  font.setEmbolden(false);
434 
435  while (state.KeepRunning()) {
436  SkTextBlobBuilder builder;
437  builder.allocRunPos(font, state.range(0));
438  }
439  state.SetComplexityN(state.range(0));
440 }
441 BENCHMARK_REGISTER_F(ParagraphFixture, SkTextBlobAlloc)
442  ->RangeMultiplier(4)
443  ->Range(1 << 7, 1 << 14)
444  ->Complexity(benchmark::oN);
445 
446 } // namespace txt
FontStyle
Definition: font_style.h:22
TextDecorationStyle
std::shared_ptr< FontCollection > GetTestFontCollection()
void SetUp(const benchmark::State &state)
virtual void Pop() override
double letter_spacing
Definition: text_style.h:51
void resize(size_t size)
Definition: LineBreaker.h:102
uint16_t * buffer()
Definition: LineBreaker.h:109
double font_size
Definition: text_style.h:50
std::string font_family
std::unique_ptr< SkCanvas > canvas_
double word_spacing
Definition: text_style.h:52
std::unique_ptr< SkBitmap > bitmap_
float addStyleRun(MinikinPaint *paint, const std::shared_ptr< FontCollection > &typeface, FontStyle style, size_t start, size_t end, bool isRtl)
void TearDown(const benchmark::State &state)
TextDecorationStyle decoration_style
Definition: text_style.h:41
std::vector< std::string > font_families
Definition: text_style.h:49
SkColor color
Definition: text_style.h:36
void setLocale(const icu::Locale &locale, Hyphenator *hyphenator)
void doLayout(const uint16_t *buf, size_t start, size_t count, size_t bufSize, bool isRtl, const FontStyle &style, const MinikinPaint &paint, const std::shared_ptr< FontCollection > &collection)
virtual void AddText(const std::u16string &text) override
BENCHMARK_F(ParagraphFixture, ShortLayout)(benchmark
std::unique_ptr< ParagraphTxt > BuildParagraph(txt::ParagraphBuilderTxt &builder)
virtual void PushStyle(const TextStyle &style) override
std::shared_ptr< FontCollection > font_collection_
BENCHMARK_DEFINE_F(ParagraphFixture, TextBigO)(benchmark