Loading apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java 0 → 100644 +150 −0 Original line number Diff line number Diff line /* * 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*/); } } apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * 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(); } } apct-tests/perftests/core/src/android/text/NonEditableTextGenerator.java 0 → 100644 +138 −0 Original line number Diff line number Diff line 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(); } } } apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * 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(); } } apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * 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(); } } Loading
apct-tests/perftests/core/src/android/text/BoringLayoutCreateDrawPerfTest.java 0 → 100644 +150 −0 Original line number Diff line number Diff line /* * 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*/); } }
apct-tests/perftests/core/src/android/text/BoringLayoutIsBoringPerfTest.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * 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(); } }
apct-tests/perftests/core/src/android/text/NonEditableTextGenerator.java 0 → 100644 +138 −0 Original line number Diff line number Diff line 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(); } } }
apct-tests/perftests/core/src/android/text/PaintMeasureDrawPerfTest.java 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * 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(); } }
apct-tests/perftests/core/src/android/text/StaticLayoutCreateDrawPerfTest.java 0 → 100644 +151 −0 Original line number Diff line number Diff line /* * 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(); } }