1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package android.text;
18
19import android.perftests.utils.BenchmarkState;
20import android.perftests.utils.PerfStatusReporter;
21
22import android.support.test.filters.LargeTest;
23import android.support.test.runner.AndroidJUnit4;
24
25import org.junit.Rule;
26import org.junit.Test;
27import org.junit.runner.RunWith;
28
29import java.util.Random;
30import java.util.concurrent.CountDownLatch;
31import java.util.concurrent.atomic.AtomicBoolean;
32import java.util.concurrent.TimeUnit;
33
34@LargeTest
35@RunWith(AndroidJUnit4.class)
36public class StaticLayoutMultithreadPerfTest {
37    private static final int WORD_LENGTH = 9;  // Random word has 9 characters.
38    private static final int WORDS_IN_LINE = 8;  // Roughly, 8 words in a line.
39    private static final boolean NO_STYLE_TEXT = false;
40
41    private static TextPaint PAINT = new TextPaint();
42    private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
43
44    public StaticLayoutMultithreadPerfTest() {}
45
46    @Rule
47    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
48
49    private CountDownLatch mStartLatch;
50    private AtomicBoolean mThreadState;  // True for running, False for stopped.
51
52    private static final long TIMEOUT_MS = 5000;
53
54    private Thread[] startBackgroundThread(int numOfThreads) {
55        mStartLatch = new CountDownLatch(numOfThreads);
56        mThreadState = new AtomicBoolean(true);
57
58        Thread[] threads = new Thread[numOfThreads];
59        for (int i = 0; i < numOfThreads; ++i) {
60            final int seed = i + 1;
61            threads[i] = new Thread(new Runnable() {
62                @Override
63                public void run() {
64                    final TextPerfUtils util = new TextPerfUtils();
65                    util.resetRandom(seed);
66
67                    mStartLatch.countDown();
68                    while (mThreadState.get()) {
69                        final CharSequence text = util.nextRandomParagraph(
70                                WORD_LENGTH, NO_STYLE_TEXT);
71                        StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
72                                .build();
73                    }
74                }
75            });
76        }
77
78        for (int i = 0; i < numOfThreads; ++i) {
79            threads[i].start();
80        }
81
82        try {
83            mStartLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
84        } catch (InterruptedException e) {
85            throw new RuntimeException(e);
86        }
87        return threads;
88    }
89
90    private void finishThreads(Thread[] threads) {
91        mThreadState.set(false);
92        for (Thread thread : threads) {
93            try {
94                thread.join();
95            } catch (InterruptedException e) {
96                throw new RuntimeException(e);
97            }
98        }
99        mStartLatch = null;
100        mThreadState = null;
101    }
102
103    private void runRandomTest(int numOfTotalThreads) {
104        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
105        final TextPerfUtils util = new TextPerfUtils();
106        Thread[] threads = startBackgroundThread(numOfTotalThreads - 1);
107        while (state.keepRunning()) {
108            state.pauseTiming();
109            final CharSequence text = util.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
110            state.resumeTiming();
111
112            StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
113                    .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
114                    .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
115                    .build();
116        }
117        finishThreads(threads);
118    }
119
120    @Test
121    public void testCreate_RandomText_Thread_1() {
122        runRandomTest(1);
123    }
124
125    @Test
126    public void testCreate_RandomText_Thread_2() {
127        runRandomTest(2);
128    }
129
130    @Test
131    public void testCreate_RandomText_Thread_4() {
132        runRandomTest(4);
133    }
134}
135