Merge changes from topic "text_perf_sep_2017"
* changes: Reduce Text layout performance test combinations Performance test for text layout/draw
This commit is contained in:
committed by
Android (Google) Code Review
commit
f8ef7ac694
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.text;
|
||||
|
||||
import static android.text.Layout.Alignment.ALIGN_NORMAL;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.text.NonEditableTextGenerator.TextType;
|
||||
import android.view.DisplayListCanvas;
|
||||
import android.view.RenderNode;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Performance test for {@link BoringLayout} create and draw.
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(Parameterized.class)
|
||||
public class BoringLayoutCreateDrawPerfTest {
|
||||
|
||||
private static final boolean[] BOOLEANS = new boolean[]{false, true};
|
||||
private static final float SPACING_ADD = 10f;
|
||||
private static final float SPACING_MULT = 1.5f;
|
||||
|
||||
@Parameterized.Parameters(name = "cached={3},{1} chars,{0}")
|
||||
public static Collection cases() {
|
||||
final List<Object[]> params = new ArrayList<>();
|
||||
for (int length : new int[]{128}) {
|
||||
for (boolean cached : BOOLEANS) {
|
||||
for (TextType textType : new TextType[]{TextType.STRING,
|
||||
TextType.SPANNABLE_BUILDER}) {
|
||||
params.add(new Object[]{textType.name(), length, textType, cached});
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
private final int mLength;
|
||||
private final TextType mTextType;
|
||||
private final boolean mCached;
|
||||
private final TextPaint mTextPaint;
|
||||
|
||||
public BoringLayoutCreateDrawPerfTest(String label, int length, TextType textType,
|
||||
boolean cached) {
|
||||
mLength = length;
|
||||
mCached = cached;
|
||||
mTextType = textType;
|
||||
mTextPaint = new TextPaint();
|
||||
mTextPaint.setTextSize(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the creation time for {@link BoringLayout}.
|
||||
*/
|
||||
@Test
|
||||
public void timeCreate() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final CharSequence text = createRandomText();
|
||||
// isBoring result is calculated in another test, we want to measure only the
|
||||
// create time for Boring without isBoring check. Therefore it is calculated here.
|
||||
final BoringLayout.Metrics metrics = BoringLayout.isBoring(text, mTextPaint);
|
||||
if (mCached) createLayout(text, metrics);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
state.pauseTiming();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
createLayout(text, metrics);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the draw time for {@link BoringLayout} or {@link StaticLayout}.
|
||||
*/
|
||||
@Test
|
||||
public void timeDraw() throws Throwable {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final RenderNode node = RenderNode.create("benchmark", null);
|
||||
final CharSequence text = createRandomText();
|
||||
final BoringLayout.Metrics metrics = BoringLayout.isBoring(text, mTextPaint);
|
||||
final Layout layout = createLayout(text, metrics);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
|
||||
state.pauseTiming();
|
||||
final DisplayListCanvas canvas = node.start(1200, 200);
|
||||
final int save = canvas.save();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
layout.draw(canvas);
|
||||
|
||||
state.pauseTiming();
|
||||
canvas.restoreToCount(save);
|
||||
node.end(canvas);
|
||||
state.resumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence createRandomText() {
|
||||
return new NonEditableTextGenerator(new Random(0))
|
||||
.setSequenceLength(mLength)
|
||||
.setCreateBoring(true)
|
||||
.setTextType(mTextType)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Layout createLayout(CharSequence text,
|
||||
BoringLayout.Metrics metrics) {
|
||||
return BoringLayout.make(text, mTextPaint, Integer.MAX_VALUE /*width*/,
|
||||
ALIGN_NORMAL, SPACING_MULT, SPACING_ADD, metrics, true /*includePad*/);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.text;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.text.NonEditableTextGenerator.TextType;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Performance test for {@link BoringLayout#isBoring(CharSequence, TextPaint)}.
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(Parameterized.class)
|
||||
public class BoringLayoutIsBoringPerfTest {
|
||||
|
||||
private static final boolean[] BOOLEANS = new boolean[]{false, true};
|
||||
|
||||
@Parameterized.Parameters(name = "cached={4},{1} chars,{0}")
|
||||
public static Collection cases() {
|
||||
final List<Object[]> params = new ArrayList<>();
|
||||
for (int length : new int[]{128}) {
|
||||
for (boolean boring : BOOLEANS) {
|
||||
for (boolean cached : BOOLEANS) {
|
||||
for (TextType textType : new TextType[]{TextType.STRING,
|
||||
TextType.SPANNABLE_BUILDER}) {
|
||||
params.add(new Object[]{
|
||||
(boring ? "Boring" : "NotBoring") + "," + textType.name(),
|
||||
length, boring, textType, cached});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
private final int mLength;
|
||||
private final TextType mTextType;
|
||||
private final boolean mCreateBoring;
|
||||
private final boolean mCached;
|
||||
private final TextPaint mTextPaint;
|
||||
|
||||
public BoringLayoutIsBoringPerfTest(String label, int length, boolean boring, TextType textType,
|
||||
boolean cached) {
|
||||
mLength = length;
|
||||
mCreateBoring = boring;
|
||||
mCached = cached;
|
||||
mTextType = textType;
|
||||
mTextPaint = new TextPaint();
|
||||
mTextPaint.setTextSize(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure the time for the {@link BoringLayout#isBoring(CharSequence, TextPaint)}.
|
||||
*/
|
||||
@Test
|
||||
public void timeIsBoring() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final CharSequence text = createRandomText();
|
||||
if (mCached) BoringLayout.isBoring(text, mTextPaint);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
state.pauseTiming();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
BoringLayout.isBoring(text, mTextPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence createRandomText() {
|
||||
return new NonEditableTextGenerator(new Random(0))
|
||||
.setSequenceLength(mLength)
|
||||
.setCreateBoring(mCreateBoring)
|
||||
.setTextType(mTextType)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package android.text;
|
||||
|
||||
import static android.text.Spanned.SPAN_INCLUSIVE_INCLUSIVE;
|
||||
|
||||
import android.text.style.BulletSpan;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class NonEditableTextGenerator {
|
||||
|
||||
enum TextType {
|
||||
STRING,
|
||||
SPANNED,
|
||||
SPANNABLE_BUILDER
|
||||
}
|
||||
|
||||
private boolean mCreateBoring;
|
||||
private TextType mTextType;
|
||||
private int mSequenceLength;
|
||||
private final Random mRandom;
|
||||
|
||||
public NonEditableTextGenerator(Random random) {
|
||||
mRandom = random;
|
||||
}
|
||||
|
||||
public NonEditableTextGenerator setCreateBoring(boolean createBoring) {
|
||||
mCreateBoring = createBoring;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NonEditableTextGenerator setTextType(TextType textType) {
|
||||
mTextType = textType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NonEditableTextGenerator setSequenceLength(int sequenceLength) {
|
||||
mSequenceLength = sequenceLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample charSequence generated:
|
||||
* NRjPzjvUadHmH ExoEoTqfx pCLw qtndsqfpk AqajVCbgjGZ igIeC dfnXRgA
|
||||
*/
|
||||
public CharSequence build() {
|
||||
final RandomCharSequenceGenerator sequenceGenerator = new RandomCharSequenceGenerator(
|
||||
mRandom);
|
||||
if (mSequenceLength > 0) {
|
||||
sequenceGenerator.setSequenceLength(mSequenceLength);
|
||||
}
|
||||
|
||||
final CharSequence charSequence = sequenceGenerator.buildLatinSequence();
|
||||
|
||||
switch (mTextType) {
|
||||
case SPANNED:
|
||||
case SPANNABLE_BUILDER:
|
||||
return createSpannable(charSequence);
|
||||
case STRING:
|
||||
default:
|
||||
return createString(charSequence);
|
||||
}
|
||||
}
|
||||
|
||||
private Spannable createSpannable(CharSequence charSequence) {
|
||||
final Spannable spannable = (mTextType == TextType.SPANNABLE_BUILDER) ?
|
||||
new SpannableStringBuilder(charSequence) : new SpannableString(charSequence);
|
||||
|
||||
if (!mCreateBoring) {
|
||||
// add a paragraph style to make it non boring
|
||||
spannable.setSpan(new BulletSpan(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE);
|
||||
}
|
||||
|
||||
spannable.setSpan(new Object(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE);
|
||||
spannable.setSpan(new Object(), 0, 1, SPAN_INCLUSIVE_INCLUSIVE);
|
||||
|
||||
return spannable;
|
||||
}
|
||||
|
||||
private String createString(CharSequence charSequence) {
|
||||
if (mCreateBoring) {
|
||||
return charSequence.toString();
|
||||
} else {
|
||||
// BoringLayout checks to see if there is a surrogate pair and if so tells that
|
||||
// the charSequence is not suitable for boring. Add an emoji to make it non boring.
|
||||
// Emoji is added instead of RTL, since emoji stays in the same run and is a more
|
||||
// common case.
|
||||
return charSequence.toString() + "\uD83D\uDC68\uD83C\uDFFF";
|
||||
}
|
||||
}
|
||||
|
||||
public static class RandomCharSequenceGenerator {
|
||||
|
||||
private static final int DEFAULT_MIN_WORD_LENGTH = 3;
|
||||
private static final int DEFAULT_MAX_WORD_LENGTH = 15;
|
||||
private static final int DEFAULT_SEQUENCE_LENGTH = 256;
|
||||
|
||||
private int mMinWordLength = DEFAULT_MIN_WORD_LENGTH;
|
||||
private int mMaxWordLength = DEFAULT_MAX_WORD_LENGTH;
|
||||
private int mSequenceLength = DEFAULT_SEQUENCE_LENGTH;
|
||||
private final Random mRandom;
|
||||
|
||||
public RandomCharSequenceGenerator(Random random) {
|
||||
mRandom = random;
|
||||
}
|
||||
|
||||
public RandomCharSequenceGenerator setSequenceLength(int sequenceLength) {
|
||||
mSequenceLength = sequenceLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CharSequence buildLatinSequence() {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
while (result.length() < mSequenceLength) {
|
||||
// add random word
|
||||
result.append(buildLatinWord());
|
||||
result.append(' ');
|
||||
}
|
||||
return result.substring(0, mSequenceLength);
|
||||
}
|
||||
|
||||
public CharSequence buildLatinWord() {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
// create a random length that is (mMinWordLength + random amount of chars) where
|
||||
// total size is less than mMaxWordLength
|
||||
final int length = mRandom.nextInt(mMaxWordLength - mMinWordLength) + mMinWordLength;
|
||||
while (result.length() < length) {
|
||||
// add random letter
|
||||
int base = mRandom.nextInt(2) == 0 ? 'A' : 'a';
|
||||
result.append(Character.toChars(mRandom.nextInt(26) + base));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.text;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.view.DisplayListCanvas;
|
||||
import android.view.RenderNode;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Performance test for single line measure and draw using {@link Paint} and {@link Canvas}.
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(Parameterized.class)
|
||||
public class PaintMeasureDrawPerfTest {
|
||||
|
||||
private static final boolean[] BOOLEANS = new boolean[]{false, true};
|
||||
|
||||
@Parameterized.Parameters(name = "cached={1},{0} chars")
|
||||
public static Collection cases() {
|
||||
final List<Object[]> params = new ArrayList<>();
|
||||
for (int length : new int[]{128}) {
|
||||
for (boolean cached : BOOLEANS) {
|
||||
params.add(new Object[]{length, cached});
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
private final int mLength;
|
||||
private final boolean mCached;
|
||||
private final TextPaint mTextPaint;
|
||||
|
||||
|
||||
public PaintMeasureDrawPerfTest(int length, boolean cached) {
|
||||
mLength = length;
|
||||
mCached = cached;
|
||||
mTextPaint = new TextPaint();
|
||||
mTextPaint.setTextSize(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure the time for {@link Paint#measureText(String)}
|
||||
*/
|
||||
@Test
|
||||
public void timeMeasure() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final String text = createRandomText();
|
||||
if (mCached) mTextPaint.measureText(text);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
state.pauseTiming();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
mTextPaint.measureText(text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the time for {@link Canvas#drawText(String, float, float, Paint)}
|
||||
*/
|
||||
@Test
|
||||
public void timeDraw() throws Throwable {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final RenderNode node = RenderNode.create("benchmark", null);
|
||||
final String text = createRandomText();
|
||||
if (mCached) mTextPaint.measureText(text);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
|
||||
state.pauseTiming();
|
||||
final DisplayListCanvas canvas = node.start(1200, 200);
|
||||
final int save = canvas.save();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
canvas.drawText(text, 0 /*x*/, 100 /*y*/, mTextPaint);
|
||||
|
||||
state.pauseTiming();
|
||||
canvas.restoreToCount(save);
|
||||
node.end(canvas);
|
||||
state.resumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
private String createRandomText() {
|
||||
return (String) new NonEditableTextGenerator(new Random(0))
|
||||
.setSequenceLength(mLength)
|
||||
.setCreateBoring(true)
|
||||
.setTextType(NonEditableTextGenerator.TextType.STRING)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.text;
|
||||
|
||||
import static android.text.Layout.Alignment.ALIGN_NORMAL;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.text.NonEditableTextGenerator.TextType;
|
||||
import android.view.DisplayListCanvas;
|
||||
import android.view.RenderNode;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Performance test for multi line, single style {@link StaticLayout} creation/draw.
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(Parameterized.class)
|
||||
public class StaticLayoutCreateDrawPerfTest {
|
||||
|
||||
private static final boolean[] BOOLEANS = new boolean[]{false, true};
|
||||
|
||||
private static final float SPACING_ADD = 10f;
|
||||
private static final float SPACING_MULT = 1.5f;
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
@Parameterized.Parameters(name = "cached={3},{1} chars,{0}")
|
||||
public static Collection cases() {
|
||||
final List<Object[]> params = new ArrayList<>();
|
||||
for (int length : new int[]{128}) {
|
||||
for (boolean cached : BOOLEANS) {
|
||||
for (TextType textType : new TextType[]{TextType.STRING,
|
||||
TextType.SPANNABLE_BUILDER}) {
|
||||
params.add(new Object[]{textType.name(), length, textType, cached});
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private final int mLineWidth;
|
||||
private final int mLength;
|
||||
private final TextType mTextType;
|
||||
private final boolean mCached;
|
||||
private final TextPaint mTextPaint;
|
||||
|
||||
public StaticLayoutCreateDrawPerfTest(String label, int length, TextType textType,
|
||||
boolean cached) {
|
||||
mLength = length;
|
||||
mTextType = textType;
|
||||
mCached = cached;
|
||||
mTextPaint = new TextPaint();
|
||||
mTextPaint.setTextSize(10);
|
||||
mLineWidth = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the creation time for a multi line {@link StaticLayout}.
|
||||
*/
|
||||
@Test
|
||||
public void timeCreate() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final CharSequence text = createRandomText(mLength);
|
||||
createLayout(text);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
state.pauseTiming();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
createLayout(text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the draw time for a multi line {@link StaticLayout}.
|
||||
*/
|
||||
@Test
|
||||
public void timeDraw() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final RenderNode node = RenderNode.create("benchmark", null);
|
||||
final CharSequence text = createRandomText(mLength);
|
||||
final Layout layout = createLayout(text);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
|
||||
state.pauseTiming();
|
||||
final DisplayListCanvas canvas = node.start(1200, 200);
|
||||
int save = canvas.save();
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
layout.draw(canvas);
|
||||
|
||||
state.pauseTiming();
|
||||
canvas.restoreToCount(save);
|
||||
node.end(canvas);
|
||||
state.resumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
private Layout createLayout(CharSequence text) {
|
||||
return StaticLayout.Builder.obtain(text, 0 /*start*/, text.length() /*end*/, mTextPaint,
|
||||
mLineWidth)
|
||||
.setAlignment(ALIGN_NORMAL)
|
||||
.setIncludePad(true)
|
||||
.setLineSpacing(SPACING_ADD, SPACING_MULT)
|
||||
.build();
|
||||
}
|
||||
|
||||
private CharSequence createRandomText(int length) {
|
||||
return new NonEditableTextGenerator(new Random(0))
|
||||
.setSequenceLength(length)
|
||||
.setTextType(mTextType)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package android.text;
|
||||
|
||||
import static android.view.View.MeasureSpec.AT_MOST;
|
||||
import static android.view.View.MeasureSpec.UNSPECIFIED;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.text.NonEditableTextGenerator.TextType;
|
||||
import android.view.DisplayListCanvas;
|
||||
import android.view.RenderNode;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Performance test for multi line, single style {@link StaticLayout} creation/draw.
|
||||
*/
|
||||
@LargeTest
|
||||
@RunWith(Parameterized.class)
|
||||
public class TextViewSetTextMeasurePerfTest {
|
||||
|
||||
private static final boolean[] BOOLEANS = new boolean[]{false, true};
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
@Parameterized.Parameters(name = "cached={3},{1} chars,{0}")
|
||||
public static Collection cases() {
|
||||
final List<Object[]> params = new ArrayList<>();
|
||||
for (int length : new int[]{128}) {
|
||||
for (boolean cached : BOOLEANS) {
|
||||
for (TextType textType : new TextType[]{TextType.STRING,
|
||||
TextType.SPANNABLE_BUILDER}) {
|
||||
params.add(new Object[]{textType.name(), length, textType, cached});
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private final int mLineWidth;
|
||||
private final int mLength;
|
||||
private final TextType mTextType;
|
||||
private final boolean mCached;
|
||||
private final TextPaint mTextPaint;
|
||||
|
||||
public TextViewSetTextMeasurePerfTest(String label, int length, TextType textType,
|
||||
boolean cached) {
|
||||
mLength = length;
|
||||
mTextType = textType;
|
||||
mCached = cached;
|
||||
mTextPaint = new TextPaint();
|
||||
mTextPaint.setTextSize(10);
|
||||
mLineWidth = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the time to setText and measure for a {@link TextView}.
|
||||
*/
|
||||
@Test
|
||||
public void timeCreate() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final CharSequence text = createRandomText(mLength);
|
||||
final TextView textView = new TextView(InstrumentationRegistry.getTargetContext());
|
||||
textView.setText(text);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
state.pauseTiming();
|
||||
textView.setTextLocale(Locale.UK);
|
||||
textView.setTextLocale(Locale.US);
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
textView.setText(text);
|
||||
textView.measure(AT_MOST | mLineWidth, UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the time to draw for a {@link TextView}.
|
||||
*/
|
||||
@Test
|
||||
public void timeDraw() throws Exception {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
|
||||
state.pauseTiming();
|
||||
Canvas.freeTextLayoutCaches();
|
||||
final RenderNode node = RenderNode.create("benchmark", null);
|
||||
final CharSequence text = createRandomText(mLength);
|
||||
final TextView textView = new TextView(InstrumentationRegistry.getTargetContext());
|
||||
textView.setText(text);
|
||||
state.resumeTiming();
|
||||
|
||||
while (state.keepRunning()) {
|
||||
|
||||
state.pauseTiming();
|
||||
final DisplayListCanvas canvas = node.start(1200, 200);
|
||||
int save = canvas.save();
|
||||
textView.setTextLocale(Locale.UK);
|
||||
textView.setTextLocale(Locale.US);
|
||||
if (!mCached) Canvas.freeTextLayoutCaches();
|
||||
state.resumeTiming();
|
||||
|
||||
textView.draw(canvas);
|
||||
|
||||
state.pauseTiming();
|
||||
canvas.restoreToCount(save);
|
||||
node.end(canvas);
|
||||
state.resumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence createRandomText(int length) {
|
||||
return new NonEditableTextGenerator(new Random(0))
|
||||
.setSequenceLength(length)
|
||||
.setCreateBoring(false)
|
||||
.setTextType(mTextType)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user