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

Commit 97314af5 authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Introduce perf tests for background text layout performance

Here is an example of perf score:

StaticLayout creation time
 1 Thread:  7,301,172
 2 Thread: 13,842,641
 4 Thread: 25,232,063

Bug: 37567215
Test: See above
Change-Id: I319abd5fe0861575649a1122c91f1949c6ad14d2
parent 8c04bd60
Loading
Loading
Loading
Loading
+134 −0
Original line number Diff line number Diff line
/*
 * 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 android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;

import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class StaticLayoutMultithreadPerfTest {
    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 TextPaint PAINT = new TextPaint();
    private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();

    public StaticLayoutMultithreadPerfTest() {}

    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    private CountDownLatch mStartLatch;
    private AtomicBoolean mThreadState;  // True for running, False for stopped.

    private static final long TIMEOUT_MS = 5000;

    private Thread[] startBackgroundThread(int numOfThreads) {
        mStartLatch = new CountDownLatch(numOfThreads);
        mThreadState = new AtomicBoolean(true);

        Thread[] threads = new Thread[numOfThreads];
        for (int i = 0; i < numOfThreads; ++i) {
            final int seed = i + 1;
            threads[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    final TextPerfUtils util = new TextPerfUtils();
                    util.resetRandom(seed);

                    mStartLatch.countDown();
                    while (mThreadState.get()) {
                        final CharSequence text = util.nextRandomParagraph(
                                WORD_LENGTH, NO_STYLE_TEXT);
                        StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
                                .build();
                    }
                }
            });
        }

        for (int i = 0; i < numOfThreads; ++i) {
            threads[i].start();
        }

        try {
            mStartLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return threads;
    }

    private void finishThreads(Thread[] threads) {
        mThreadState.set(false);
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        mStartLatch = null;
        mThreadState = null;
    }

    private void runRandomTest(int numOfTotalThreads) {
        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        final TextPerfUtils util = new TextPerfUtils();
        Thread[] threads = startBackgroundThread(numOfTotalThreads - 1);
        while (state.keepRunning()) {
            state.pauseTiming();
            final CharSequence text = util.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
            state.resumeTiming();

            StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
                    .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
                    .build();
        }
        finishThreads(threads);
    }

    @Test
    public void testCreate_RandomText_Thread_1() {
        runRandomTest(1);
    }

    @Test
    public void testCreate_RandomText_Thread_2() {
        runRandomTest(2);
    }

    @Test
    public void testCreate_RandomText_Thread_4() {
        runRandomTest(4);
    }
}