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

Commit 833b2935 authored by Tony Mak's avatar Tony Mak
Browse files

Setup crystalball and add more perf tests

crystalball is the new perf system that we are migrating to.

The perf tests on platform side are repurposed to benchmark the platform
code and various overheads introduced by the system.
The model performance will be tracked elsewhere.

Bug: 161918490
Bug: 156886144

Test: atest TextClassifierPerfsTest
Change-Id: Ib9d204a930f5212a68407dbab576627a51dfb41e
parent ed575dce
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@ android_test {
        "androidx.test.rules",
        "androidx.annotation_annotation",
        "apct-perftests-utils",
        "collector-device-lib-platform",
    ],
    data: [":perfetto_artifacts"],
    platform_apis: true,
    test_suites: ["device-tests"],
}
+32 −0
Original line number Diff line number Diff line
@@ -21,8 +21,40 @@
        <option name="test-file-name" value="TextClassifierPerfTests.apk" />
    </target_preparer>

    <!-- Needed for pushing the trace config file -->
    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
        <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
    </target_preparer>

    <!-- Needed for pulling the collected trace config on to the host -->
    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
        <option name="pull-pattern-keys" value="perfetto_file_path" />
    </metrics_collector>

    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
    <option name="isolated-storage" value="false" />

    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.perftests.textclassifier" />
        <option name="hidden-api-checks" value="false"/>

         <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />

        <!-- ProcLoadListener related arguments -->
        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />

        <!-- PerfettoListener related arguments -->
        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />

        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
    </test>
</configuration>
+44 −44
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view.textclassifier;
import android.content.Context;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.service.textclassifier.TextClassifierService;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -25,86 +26,85 @@ import androidx.test.filters.LargeTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Random;

@RunWith(Parameterized.class)
@LargeTest
public class TextClassifierPerfTest {
    /** Request contains meaning text, rather than garbled text. */
    private static final int ACTUAL_REQUEST = 0;
    private static final String RANDOM_CHAR_SET = "abcdefghijklmnopqrstuvwxyz0123456789";
    private static final String TEXT = " Oh hi Mark, the number is (323) 654-6192.\n"
            + "Anyway, I'll meet you at 1600 Pennsylvania Avenue NW.\n"
            + "My flight is LX 38 and I'll arrive at 8:00pm.\n"
            + "Also, check out www.google.com.\n";

    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    @Parameterized.Parameters(name = "size{0}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][]{{ACTUAL_REQUEST}, {10}, {100}, {1000}});
    }

    private TextClassifier mTextClassifier;
    private final int mSize;

    public TextClassifierPerfTest(int size) {
        mSize = size;
    }

    @Before
    public void setUp() {
        Context context = InstrumentationRegistry.getTargetContext();
        TextClassificationManager textClassificationManager =
                context.getSystemService(TextClassificationManager.class);
        mTextClassifier = textClassificationManager.getTextClassifier(TextClassifier.LOCAL);
        mTextClassifier = TextClassifierService.getDefaultTextClassifierImplementation(context);
    }

    @Test
    public void testSuggestConversationActions() {
        String text = mSize == ACTUAL_REQUEST ? "Where are you?" : generateRandomString(mSize);
        ConversationActions.Request request = createConversationActionsRequest(text);
    public void testClassifyText() {
        TextClassification.Request request =
                new TextClassification.Request.Builder(TEXT, 0, TEXT.length()).build();
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            mTextClassifier.suggestConversationActions(request);
            mTextClassifier.classifyText(request);
        }
    }

    @Test
    public void testDetectLanguage() {
        String text = mSize == ACTUAL_REQUEST
                ? "これは日本語のテキストです" : generateRandomString(mSize);
        TextLanguage.Request request = createTextLanguageRequest(text);
    public void testSuggestSelection() {
        // Trying to select the phone number.
        TextSelection.Request request =
                new TextSelection.Request.Builder(
                        TEXT,
                        /* startIndex= */ 28,
                        /* endIndex= */29)
                        .build();
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            mTextClassifier.detectLanguage(request);
            mTextClassifier.suggestSelection(request);
        }
    }

    private static ConversationActions.Request createConversationActionsRequest(CharSequence text) {
    @Test
    public void testGenerateLinks() {
        TextLinks.Request request =
                new TextLinks.Request.Builder(TEXT).build();
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            mTextClassifier.generateLinks(request);
        }
    }

    @Test
    public void testSuggestConversationActions() {
        ConversationActions.Message message =
                new ConversationActions.Message.Builder(
                        ConversationActions.Message.PERSON_USER_OTHERS)
                        .setText(text)
                        .setText(TEXT)
                        .build();
        return new ConversationActions.Request.Builder(Collections.singletonList(message))
        ConversationActions.Request request = new ConversationActions.Request.Builder(
                Collections.singletonList(message))
                .build();
    }

    private static TextLanguage.Request createTextLanguageRequest(CharSequence text) {
        return new TextLanguage.Request.Builder(text).build();
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            mTextClassifier.suggestConversationActions(request);
        }
    }

    private static String generateRandomString(int length) {
        Random random = new Random();
        StringBuilder stringBuilder = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(RANDOM_CHAR_SET.length());
            stringBuilder.append(RANDOM_CHAR_SET.charAt(index));
    @Test
    public void testDetectLanguage() {
        TextLanguage.Request request = new TextLanguage.Request.Builder(TEXT).build();
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            mTextClassifier.detectLanguage(request);
        }
        return stringBuilder.toString();
    }
}