diff options
7 files changed, 464 insertions, 69 deletions
diff --git a/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java b/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java new file mode 100644 index 000000000000..fc6302ea9394 --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/MeasuredTextMemoryUsageTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 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.TextDirectionHeuristics.LTR; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; + +import android.app.Activity; +import android.os.Bundle; +import android.support.test.InstrumentationRegistry; +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.text.Layout; +import android.text.style.TextAppearanceSpan; +import android.view.DisplayListCanvas; +import android.view.RenderNode; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.CharBuffer; +import java.util.Random; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class MeasuredTextMemoryUsageTest { + private static final int WORD_LENGTH = 9; // Random word has 9 characters. + private static final boolean NO_STYLE_TEXT = false; + + private static TextPaint PAINT = new TextPaint(); + + private static int TRIAL_COUNT = 100; + + public MeasuredTextMemoryUsageTest() {} + + private TextPerfUtils mTextUtil = new TextPerfUtils(); + + @Before + public void setUp() { + mTextUtil.resetRandom(0 /* seed */); + } + + private void reportMemoryUsage(int memoryUsage, String key) { + Bundle status = new Bundle(); + status.putInt(key + "_median", memoryUsage); + InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status); + } + + private int median(int[] values) { + return values.length % 2 == 0 ? + (values[values.length / 2] + values[values.length / 2 - 1]) / 2: + values[values.length / 2]; + } + + @Test + public void testMemoryUsage_NoHyphenation() { + int[] memories = new int[TRIAL_COUNT]; + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build().getMemoryUsage(); + } + reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation"); + } + + @Test + public void testMemoryUsage_Hyphenation() { + int[] memories = new int[TRIAL_COUNT]; + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build().getMemoryUsage(); + } + reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation"); + } + + @Test + public void testMemoryUsage_NoHyphenation_WidthOnly() { + int[] memories = new int[TRIAL_COUNT]; + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(false /* width only */).getMemoryUsage(); + } + reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly"); + } + + @Test + public void testMemoryUsage_Hyphenatation_WidthOnly() { + int[] memories = new int[TRIAL_COUNT]; + // Report median of randomly generated MeasuredText. + for (int i = 0; i < TRIAL_COUNT; ++i) { + memories[i] = new MeasuredText.Builder( + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(false /* width only */).getMemoryUsage(); + } + reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly"); + } +} diff --git a/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java b/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java new file mode 100644 index 000000000000..98f2bd5e5736 --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/MeasuredTextPerfTest.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2018 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.TextDirectionHeuristics.LTR; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; + +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.text.Layout; +import android.text.style.TextAppearanceSpan; +import android.view.DisplayListCanvas; +import android.view.RenderNode; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.CharBuffer; +import java.util.Random; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class MeasuredTextPerfTest { + private static final int WORD_LENGTH = 9; // Random word has 9 characters. + private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line. + private static final boolean NO_STYLE_TEXT = false; + private static final boolean STYLE_TEXT = true; + + private static TextPaint PAINT = new TextPaint(); + private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize(); + + public MeasuredTextPerfTest() {} + + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + private TextPerfUtils mTextUtil = new TextPerfUtils(); + + @Before + public void setUp() { + mTextUtil.resetRandom(0 /* seed */); + } + + @Test + public void testCreate_NoStyled_Hyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(true /* do full layout */); + } + } + + @Test + public void testCreate_NoStyled_NoHyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(true /* do full layout */); + } + } + + @Test + public void testCreate_NoStyled_Hyphenation_WidthOnly() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(false /* width only */); + } + } + + @Test + public void testCreate_NoStyled_NoHyphenation_WidthOnly() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(false /* width only */); + } + } + + @Test + public void testCreate_Styled_Hyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(true /* do full layout */); + } + } + + @Test + public void testCreate_Styled_NoHyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(true /* do full layout */); + } + } + + @Test + public void testCreate_Styled_Hyphenation_WidthOnly() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .build(false /* width only */); + } + } + + @Test + public void testCreate_Styled_NoHyphenation_WidthOnly() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); + state.resumeTiming(); + + new MeasuredText.Builder(text, PAINT) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .build(false /* width only */); + } + } +} diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java index 682885b3120d..bab2a859698c 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java @@ -43,74 +43,30 @@ import java.util.Random; @LargeTest @RunWith(AndroidJUnit4.class) public class StaticLayoutPerfTest { - - public StaticLayoutPerfTest() {} - - @Rule - public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - private static final int WORD_LENGTH = 9; // Random word has 9 characters. private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line. - private static final int PARA_LENGTH = 500; // Number of characters in a paragraph. - private static final boolean NO_STYLE_TEXT = false; private static final boolean STYLE_TEXT = true; - private Random mRandom; - - private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - private static final int ALPHABET_LENGTH = ALPHABET.length(); - - private static final ColorStateList TEXT_COLOR = ColorStateList.valueOf(0x00000000); - private static final String[] FAMILIES = { "sans-serif", "serif", "monospace" }; - private static final int[] STYLES = { - Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC - }; - - private final char[] mBuffer = new char[PARA_LENGTH]; - private static TextPaint PAINT = new TextPaint(); private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize(); - private CharSequence generateRandomParagraph(int wordLen, boolean applyRandomStyle) { - for (int i = 0; i < PARA_LENGTH; i++) { - if (i % (wordLen + 1) == wordLen) { - mBuffer[i] = ' '; - } else { - mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH)); - } - } - - CharSequence cs = CharBuffer.wrap(mBuffer); - if (!applyRandomStyle) { - return cs; - } - - SpannableStringBuilder ssb = new SpannableStringBuilder(cs); - for (int i = 0; i < ssb.length(); i += WORD_LENGTH) { - final int spanStart = i; - final int spanEnd = (i + WORD_LENGTH) > ssb.length() ? ssb.length() : i + WORD_LENGTH; + public StaticLayoutPerfTest() {} - final TextAppearanceSpan span = new TextAppearanceSpan( - FAMILIES[mRandom.nextInt(FAMILIES.length)], - STYLES[mRandom.nextInt(STYLES.length)], - 24 + mRandom.nextInt(32), // text size. min 24 max 56 - TEXT_COLOR, TEXT_COLOR); + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - ssb.setSpan(span, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - } - return ssb; - } + private TextPerfUtils mTextUtil = new TextPerfUtils(); @Before public void setUp() { - mRandom = new Random(0); + mTextUtil.resetRandom(0 /* seed */); } @Test public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); while (state.keepRunning()) { StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) @@ -124,7 +80,7 @@ public class StaticLayoutPerfTest { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) @@ -139,7 +95,7 @@ public class StaticLayoutPerfTest { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) @@ -154,7 +110,7 @@ public class StaticLayoutPerfTest { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) @@ -169,7 +125,7 @@ public class StaticLayoutPerfTest { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); state.resumeTiming(); StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) @@ -184,7 +140,7 @@ public class StaticLayoutPerfTest { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); state.resumeTiming(); StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) @@ -200,7 +156,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .build(); @@ -219,7 +175,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) .build(); @@ -238,7 +194,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .build(); @@ -257,7 +213,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) .build(); @@ -276,7 +232,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT) .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .build(); @@ -292,7 +248,7 @@ public class StaticLayoutPerfTest { @Test public void testDraw_FixedText_NoStyled() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); @@ -311,7 +267,7 @@ public class StaticLayoutPerfTest { final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -327,7 +283,7 @@ public class StaticLayoutPerfTest { final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -343,7 +299,7 @@ public class StaticLayoutPerfTest { final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -360,7 +316,7 @@ public class StaticLayoutPerfTest { final RenderNode node = RenderNode.create("benchmark", null); while (state.keepRunning()) { state.pauseTiming(); - final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -378,7 +334,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build(); + mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build(); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -395,7 +351,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build(); + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build(); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -412,7 +368,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build(); + mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT).build(); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); @@ -430,7 +386,7 @@ public class StaticLayoutPerfTest { while (state.keepRunning()) { state.pauseTiming(); final MeasuredText text = new MeasuredText.Builder( - generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build(); + mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT).build(); final StaticLayout layout = StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build(); final DisplayListCanvas c = node.start(1200, 200); diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java new file mode 100644 index 000000000000..dccb34be9d07 --- /dev/null +++ b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 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.TextDirectionHeuristics.LTR; + +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; + +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.text.Layout; +import android.text.style.TextAppearanceSpan; +import android.view.DisplayListCanvas; +import android.view.RenderNode; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.CharBuffer; +import java.util.Random; + +public class TextPerfUtils { + + private static final int PARA_LENGTH = 500; // Number of characters in a paragraph. + + private Random mRandom = new Random(0); + + private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + private static final int ALPHABET_LENGTH = ALPHABET.length(); + + private static final ColorStateList TEXT_COLOR = ColorStateList.valueOf(0x00000000); + private static final String[] FAMILIES = { "sans-serif", "serif", "monospace" }; + private static final int[] STYLES = { + Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC + }; + + private final char[] mBuffer = new char[PARA_LENGTH]; + + public void resetRandom(long seed) { + mRandom = new Random(seed); + } + + public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle) { + for (int i = 0; i < PARA_LENGTH; i++) { + if (i % (wordLen + 1) == wordLen) { + mBuffer[i] = ' '; + } else { + mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH)); + } + } + + CharSequence cs = CharBuffer.wrap(mBuffer); + if (!applyRandomStyle) { + return cs; + } + + SpannableStringBuilder ssb = new SpannableStringBuilder(cs); + for (int i = 0; i < ssb.length(); i += wordLen) { + final int spanStart = i; + final int spanEnd = (i + wordLen) > ssb.length() ? ssb.length() : i + wordLen; + + final TextAppearanceSpan span = new TextAppearanceSpan( + FAMILIES[mRandom.nextInt(FAMILIES.length)], + STYLES[mRandom.nextInt(STYLES.length)], + 24 + mRandom.nextInt(32), // text size. min 24 max 56 + TEXT_COLOR, TEXT_COLOR); + + ssb.setSpan(span, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return ssb; + } +} diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java index 45fbf6f58209..aafcf44a73fc 100644 --- a/core/java/android/text/MeasuredParagraph.java +++ b/core/java/android/text/MeasuredParagraph.java @@ -672,6 +672,13 @@ public class MeasuredParagraph { return width; } + /** + * This only works if the MeasuredParagraph is computed with buildForStaticLayout. + */ + @IntRange(from = 0) int getMemoryUsage() { + return nGetMemoryUsage(mNativePtr); + } + private static native /* Non Zero */ long nInitBuilder(); /** @@ -718,4 +725,7 @@ public class MeasuredParagraph { @CriticalNative private static native /* Non Zero */ long nGetReleaseFunc(); + + @CriticalNative + private static native int nGetMemoryUsage(/* Non Zero */ long nativePtr); } diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java index ff23395d92a5..bb7a9e0b7906 100644 --- a/core/java/android/text/MeasuredText.java +++ b/core/java/android/text/MeasuredText.java @@ -333,6 +333,20 @@ public class MeasuredText implements Spanned { return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart); } + /** + * Returns the size of native MeasuredText memory usage + * + * Note that this may not be aculate. Must be used only for testing purposes. + * @hide + */ + public int getMemoryUsage() { + int r = 0; + for (int i = 0; i < getParagraphCount(); ++i) { + r += getMeasuredParagraph(i).getMemoryUsage(); + } + return r; + } + /////////////////////////////////////////////////////////////////////////////////////////////// // Spanned overrides // diff --git a/core/jni/android_text_MeasuredParagraph.cpp b/core/jni/android_text_MeasuredParagraph.cpp index f0e449d52998..dddddbbb3796 100644 --- a/core/jni/android_text_MeasuredParagraph.cpp +++ b/core/jni/android_text_MeasuredParagraph.cpp @@ -115,6 +115,10 @@ static jlong nGetReleaseFunc() { return toJLong(&releaseMeasuredParagraph); } +static jint nGetMemoryUsage(jlong ptr) { + return static_cast<jint>(toMeasuredParagraph(ptr)->getMemoryUsage()); +} + static const JNINativeMethod gMethods[] = { // MeasuredParagraphBuilder native functions. {"nInitBuilder", "()J", (void*) nInitBuilder}, @@ -126,6 +130,7 @@ static const JNINativeMethod gMethods[] = { // MeasuredParagraph native functions. {"nGetWidth", "(JII)F", (void*) nGetWidth}, // Critical Natives {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc}, // Critical Natives + {"nGetMemoryUsage", "(J)I", (void*) nGetMemoryUsage}, // Critical Native }; int register_android_text_MeasuredParagraph(JNIEnv* env) { |