Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5fe9674 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Add memory usage tests for various scripts

Here is an example of test result:

android.text.PrecomputedTextMemoryUsageTest:
  MemoryUsage
    Arabic Hyphenation  : 26,087
    Arabic NoHyphenation: 26,087
    CJK Hyphenation     : 58,515
    CJK NoHyphenation   : 58,515
    Latin Hyphenation   : 38,333
    Latin NoHyphenation : 16,077

Bug: 72461923
Test: manually
Change-Id: If3df2243cf9901178b3fd34882fb20f499fef5ab
parent aac73522
Loading
Loading
Loading
Loading
+79 −29
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import org.junit.runner.RunWith;

import java.nio.CharBuffer;
import java.util.Random;
import java.util.Locale;

@LargeTest
@RunWith(AndroidJUnit4.class)
@@ -49,9 +50,7 @@ public class PrecomputedTextMemoryUsageTest {
    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;
    private static int TRIAL_COUNT = 10;

    public PrecomputedTextMemoryUsageTest() {}

@@ -75,9 +74,10 @@ public class PrecomputedTextMemoryUsageTest {
    }

    @Test
    public void testMemoryUsage_NoHyphenation() {
    public void testMemoryUsage_Latin_NoHyphenation() {
        TextPaint paint = new TextPaint();
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
                .build();
@@ -88,13 +88,14 @@ public class PrecomputedTextMemoryUsageTest {
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param)
                .getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation");
        reportMemoryUsage(median(memories), "MemoryUsage_Latin_NoHyphenation");
    }

    @Test
    public void testMemoryUsage_Hyphenation() {
    public void testMemoryUsage_Latin_Hyphenation() {
        TextPaint paint = new TextPaint();
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
                .build();
@@ -105,48 +106,97 @@ public class PrecomputedTextMemoryUsageTest {
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param)
                .getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation");
        reportMemoryUsage(median(memories), "MemoryUsage_Latin_Hyphenation");
    }

    @Test
    public void testMemoryUsage_NoHyphenation_WidthOnly() {
    public void testMemoryUsage_CJK_NoHyphenation() {
        TextPaint paint = new TextPaint();
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
                .build();

        // Report median of randomly generated PrecomputedText.
        for (int i = 0; i < TRIAL_COUNT; ++i) {
            CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
            PrecomputedText.ParagraphInfo[] paragraphInfo =
                    PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false);
            memories[i] = 0;
            for (PrecomputedText.ParagraphInfo info : paragraphInfo) {
                memories[i] += info.measured.getMemoryUsage();
            memories[i] = PrecomputedText.create(
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT, "[\\u4E00-\\u9FA0]"),
                    param).getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_CJK_NoHyphenation");
    }

    @Test
    public void testMemoryUsage_CJK_Hyphenation() {
        TextPaint paint = new TextPaint();
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
                .build();

        // Report median of randomly generated PrecomputedText.
        for (int i = 0; i < TRIAL_COUNT; ++i) {
            memories[i] = PrecomputedText.create(
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT, "[\\u4E00-\\u9FA0]"),
                    param).getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_CJK_Hyphenation");
    }

    @Test
    public void testMemoryUsage_Arabic_NoHyphenation() {
        TextPaint paint = new TextPaint();
        paint.setTextLocale(Locale.forLanguageTag("ar"));
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
                .build();

        // Report median of randomly generated PrecomputedText.
        for (int i = 0; i < TRIAL_COUNT; ++i) {
            memories[i] = PrecomputedText.create(
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT, "[\\u0600-\\u06FF]"),
                    param).getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly");
        reportMemoryUsage(median(memories), "MemoryUsage_Arabic_NoHyphenation");
    }

    @Test
    public void testMemoryUsage_Hyphenatation_WidthOnly() {
    public void testMemoryUsage_Arabic_Hyphenation() {
        TextPaint paint = new TextPaint();
        paint.setTextLocale(Locale.forLanguageTag("ar"));
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
                .build();

        // Report median of randomly generated PrecomputedText.
        for (int i = 0; i < TRIAL_COUNT; ++i) {
            CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
            PrecomputedText.ParagraphInfo[] paragraphInfo =
                    PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false);
            memories[i] = 0;
            for (PrecomputedText.ParagraphInfo info : paragraphInfo) {
                memories[i] += info.measured.getMemoryUsage();
            memories[i] = PrecomputedText.create(
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT, "[\\u0600-\\u06FF]"),
                    param).getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_Arabic_Hyphenation");
    }
    @Test
    public void testMemoryUsage_Emoji() {
        TextPaint paint = new TextPaint();
        int[] memories = new int[TRIAL_COUNT];
        final PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
                .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
                .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
                .build();

        // Report median of randomly generated PrecomputedText.
        for (int i = 0; i < TRIAL_COUNT; ++i) {
            memories[i] = PrecomputedText.create(
                    mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT, "[:emoji:]"),
                    param).getMemoryUsage();
        }
        reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly");
        reportMemoryUsage(median(memories), "MemoryUsage_Emoji_NoHyphenation");
    }
}
+52 −10
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.support.test.runner.AndroidJUnit4;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.icu.text.UnicodeSet;
import android.icu.text.UnicodeSetIterator;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
import android.view.DisplayListCanvas;
@@ -39,6 +41,7 @@ import org.junit.runner.RunWith;

import java.nio.CharBuffer;
import java.util.Random;
import java.util.ArrayList;

public class TextPerfUtils {

@@ -46,8 +49,17 @@ public class TextPerfUtils {

    private Random mRandom = new Random(0);

    private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    private static final int ALPHABET_LENGTH = ALPHABET.length();
    private static final String[] ALPHABET;
    private static final int ALPHABET_LENGTH;
    static {
        String alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        ALPHABET_LENGTH = alphabets.length();
        ALPHABET = new String[ALPHABET_LENGTH];
        for (int i = 0; i < ALPHABET_LENGTH; ++i) {
            ALPHABET[i] = Character.toString(alphabets.charAt(i));
        }
    }


    private static final ColorStateList TEXT_COLOR = ColorStateList.valueOf(0x00000000);
    private static final String[] FAMILIES = { "sans-serif", "serif", "monospace" };
@@ -55,30 +67,59 @@ public class TextPerfUtils {
            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);
    }

    private static String[] UnicodeSetToArray(String setStr) {
        final UnicodeSet set = new UnicodeSet(setStr);
        final UnicodeSetIterator iterator = new UnicodeSetIterator(set);
        final ArrayList<String> out = new ArrayList<>(set.size());
        while (iterator.next()) {
          out.add(iterator.getString());
        }
        return out.toArray(new String[out.size()]);
    }

    public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle, String setStr) {
        return nextRandomParagraph(wordLen, applyRandomStyle, UnicodeSetToArray(setStr));
    }

    public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle) {
        return nextRandomParagraph(wordLen, applyRandomStyle, ALPHABET);
    }

    public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle,
            String[] charSet) {
        ArrayList<Character> chars = new ArrayList<>();
        ArrayList<Integer> wordOffsets = new ArrayList<>();
        for (int i = 0; i < PARA_LENGTH; i++) {
            if (i % (wordLen + 1) == wordLen) {
                mBuffer[i] = ' ';
                chars.add(' ');
                wordOffsets.add(chars.size());
            } else {
                mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH));
                final String str = charSet[mRandom.nextInt(charSet.length)];
                for (int j = 0; j < str.length(); ++j) {
                    chars.add(str.charAt(j));
                }
            }
        }
        wordOffsets.add(chars.size());

        CharSequence cs = CharBuffer.wrap(mBuffer);
        char[] buffer = new char[chars.size()];
        for (int i = 0; i < buffer.length; ++i) {
            buffer[i] = chars.get(i);
        }
        CharSequence cs = CharBuffer.wrap(buffer);
        if (!applyRandomStyle) {
            return cs;
        }

        SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
        for (int i = 0; i < ssb.length(); i += wordLen + 1) {
            final int spanStart = i;
            final int spanEnd = (i + wordLen) > ssb.length() ? ssb.length() : i + wordLen;
        int prevWordStart = 0;
        for (int i = 0; i < wordOffsets.size(); i++) {
            final int spanStart = prevWordStart;
            final int spanEnd = wordOffsets.get(i);

            final TextAppearanceSpan span = new TextAppearanceSpan(
                  FAMILIES[mRandom.nextInt(FAMILIES.length)],
@@ -87,6 +128,7 @@ public class TextPerfUtils {
                  TEXT_COLOR, TEXT_COLOR);

            ssb.setSpan(span, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            prevWordStart = spanEnd;
        }
        return ssb;
    }