skia2/bench/TextBlobBench.cpp

112 lines
3.3 KiB
C++
Raw Normal View History

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "bench/Benchmark.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkFont.h"
#include "include/core/SkPaint.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTextBlob.h"
#include "include/core/SkTypeface.h"
#include "include/private/SkTemplates.h"
#include "include/utils/SkRandom.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
/*
* A trivial test which benchmarks the performance of a textblob with a single run.
*/
class SkTextBlobBench : public Benchmark {
public:
SkTextBlobBench() {}
Move font loading in gm tests and benches out of constructors Constructing the gm tests and benches causes many calls to font loads. This is visible as profiling samples in fontconfig and freetype on Linux for all profiling runs of nanobench. This complicates analysis of test-cases that are suspected of being slow due to font-related issues. Move the font loading to GM::onOnceBeforeDraw and Benchmark::onPreDraw. This way the code is not executed if the testcase does not match the nanobench --match filter. This way the samples in font-related code are more easy to identify as legitimate occurances caused by the testcase. This should not cause differences in timings, because: * Benchmark::preDraw / onPreDraw is defined to be run outside the timer * GM::runAsBench is not enabled for any of the modified testcases. Also nanobench untimed warmup round should run the onOnceBeforeDraw. (and there are other GM::runAsBench gms already doing loading in onOnceBeforeDraw). Changes the behavior: In TextBench: Before, the test would report two different gms with the same name if the color emoji font was not loaded successfully. After, the test always reports all tests as individual names. Generally: The errors from loading fonts now print inbetween each testcase, as opposed to printing during construction phase. Sample output: ( 143/145 MB 1872) 14.7ms 8888 gm quadclosepathResource /fonts/Funkster.ttf not a valid font. ( 160/160 MB 1831) 575µs 8888 gm surfacenewResource /fonts/Funkster.ttf not a valid font. ( 163/165 MB 1816) 12.5ms 8888 gm linepathResource /fonts/Funkster.ttf not a valid font. ( 263/411 MB 1493) 118ms 8888 gm typefacestyles_kerningResource /fonts/Funkster.ttf not a valid font. ( 374/411 MB 1231) 7.16ms 565 gm getpostextpathResource /fonts/Funkster.ttf not a valid font. ( 323/411 MB 1179) 4.92ms 565 gm stringartResource /fonts/Funkster.ttf not a valid font. ( 347/493 MB 917) 191ms 565 gm patch_gridResource /fonts/Funkster.ttf not a valid font. ( 375/493 MB 857) 23.9ms gpu gm clipdrawdrawCannot render path (0) ( 393/493 MB 706) 2.91ms unit test ParsePath------ png error IEND: CRC error ( 394/493 MB 584) 166ms gpu gm hairmodesResource /fonts/Funkster.ttf not a valid font. Resource /fonts/Funkster.ttf not a valid font. Resource /fonts/Funkster.ttf not a valid font. ... Review URL: https://codereview.chromium.org/1144023002
2015-05-21 13:15:28 +00:00
void onDelayedSetup() override {
fFont.setTypeface(ToolUtils::create_portable_typeface("serif", SkFontStyle()));
fFont.setSubpixel(true);
// This text seems representative in both length and letter frequency.
const char* text = "Keep your sentences short, but not overly so.";
fGlyphs.setCount(fFont.countText(text, strlen(text), SkTextEncoding::kUTF8));
fXPos.setCount(fGlyphs.count());
fFont.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, fGlyphs.begin(), fGlyphs.count());
fFont.getXPos(&fGlyphs[0], fGlyphs.count(), fXPos.begin());
}
sk_sp<SkTextBlob> makeBlob() {
const SkTextBlobBuilder::RunBuffer& run =
fBuilder.allocRunPosH(fFont, fGlyphs.count(), 10, nullptr);
memcpy(run.glyphs, &fGlyphs[0], fGlyphs.count() * sizeof(uint16_t));
memcpy(run.pos, &fXPos[0], fXPos.count() * sizeof(SkScalar));
return fBuilder.make();
}
private:
SkTextBlobBuilder fBuilder;
SkFont fFont;
SkTDArray<uint16_t> fGlyphs;
SkTDArray<SkScalar> fXPos;
typedef Benchmark INHERITED;
};
class TextBlobCachedBench : public SkTextBlobBench {
const char* onGetName() override {
return "TextBlobCachedBench";
}
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
auto blob = this->makeBlob();
auto bigLoops = loops * 100;
for (int i = 0; i < bigLoops; i++) {
// To ensure maximum caching, we just redraw the blob at the same place everytime
canvas->drawTextBlob(blob, 0, 0, paint);
}
}
};
DEF_BENCH( return new TextBlobCachedBench(); )
class TextBlobFirstTimeBench : public SkTextBlobBench {
const char* onGetName() override {
return "TextBlobFirstTimeBench";
}
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
auto bigLoops = loops * 100;
for (int i = 0; i < bigLoops; i++) {
canvas->drawTextBlob(this->makeBlob(), 0, 0, paint);
}
}
};
DEF_BENCH( return new TextBlobFirstTimeBench(); )
class TextBlobMakeBench : public SkTextBlobBench {
const char* onGetName() override {
return "TextBlobMakeBench";
}
bool isSuitableFor(Backend backend) override {
return backend == kNonRendering_Backend;
}
void onDraw(int loops, SkCanvas*) override {
for (int i = 0; i < loops; i++) {
for (int inner = 0; inner < 1000; ++inner) {
this->makeBlob();
}
}
}
};
DEF_BENCH( return new TextBlobMakeBench(); )