diff options
| author | 2022-09-01 16:56:52 +0800 | |
|---|---|---|
| committer | 2022-09-22 12:42:26 +0800 | |
| commit | a07f4f5532d8386c1824ec0029f422dae3cf4015 (patch) | |
| tree | 684bc66d0eabc52b47b994522035572dedacc81d | |
| parent | fc2de301f00c240f07ed541ef2f49687de26a4f6 (diff) | |
Add the benchmark of XmlBlock for CriticalNative
In order to make sure that CriticalNative is better than "FastNaive",
this patch adds android.content.res.XmlBlockBenchmark to measure the
current performance of FastNaive.
Bug: 173709508
Test: atest \
CorePerfTests:android.content.res.XmlBlockBenchmark
Change-Id: Iafa1e043425353bf430832ee5edd38947e667404
3 files changed, 436 insertions, 0 deletions
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml index 4f8ee2927d51..86f41e1f496c 100644 --- a/apct-tests/perftests/core/AndroidTest.xml +++ b/apct-tests/perftests/core/AndroidTest.xml @@ -27,6 +27,11 @@ <option name="test-file-name" value="CorePerfTests.apk" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" value="input keyevent KEYCODE_WAKEUP" /> + <option name="run-command" value="wm dismiss-keyguard" /> + </target_preparer> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> <option name="pull-pattern-keys" value="perfetto_file_path" /> </metrics_collector> diff --git a/apct-tests/perftests/core/res/layout/linear_layout_for_xmlblock_benchmark.xml b/apct-tests/perftests/core/res/layout/linear_layout_for_xmlblock_benchmark.xml new file mode 100644 index 000000000000..9005d6fa9e76 --- /dev/null +++ b/apct-tests/perftests/core/res/layout/linear_layout_for_xmlblock_benchmark.xml @@ -0,0 +1,110 @@ +<!-- + Copyright (C) 2022 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/linear_layout_root" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="10dp" > + + <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText" + android:id="@+id/remote_input_text" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_weight="1" + android:paddingTop="14dp" + android:paddingStart="4dp" + android:paddingBottom="16dp" + android:paddingEnd="12dp" + android:layout_gravity="start|center_vertical" + android:textAppearance="?android:attr/textAppearance" + android:textSize="16sp" + android:background="@null" + android:maxLines="4" + android:ellipsize="start" + android:inputType="textShortMessage|textMultiLine|textAutoCorrect|textCapSentences" + android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" /> + + <ImageButton + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + style="@android:style/MediaButton.Previous" + id="@+id/my_image_button_previous" + /> + + <ImageButton + id="@+id/my_image_button_next" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + style="@android:style/MediaButton.Next" + /> + + <LinearLayout + id="@+id/my_linear_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="10dp" > + + <ImageButton + android:id="@+id/button3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_centerVertical="true" /> + + <LinearLayout + id="@+id/my_inner_linear_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="10dp" > + + <ImageButton + android:id="@+id/button5" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_alignParentBottom="true" /> + </LinearLayout> + + <ImageButton + android:id="@+id/button4" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/button2" + android:layout_centerHorizontal="true" /> + + <ImageButton + android:id="@+id/button6" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_above="@+id/button4" + android:layout_centerHorizontal="true" /> + + <ImageButton + android:id="@+id/button7" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignBottom="@+id/button" + android:layout_toEndOf="@+id/button" + android:layout_toRightOf="@+id/button" /> + </LinearLayout> +</LinearLayout> diff --git a/apct-tests/perftests/core/src/android/content/res/XmlBlockBenchmark.java b/apct-tests/perftests/core/src/android/content/res/XmlBlockBenchmark.java new file mode 100644 index 000000000000..bdce902e4aef --- /dev/null +++ b/apct-tests/perftests/core/src/android/content/res/XmlBlockBenchmark.java @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2022 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.content.res; + +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.START_TAG; + +import android.content.Context; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.text.TextUtils; +import android.util.Log; + +import androidx.test.filters.LargeTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.perftests.core.R; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.function.Function; +import java.util.function.Supplier; + +@LargeTest +public class XmlBlockBenchmark { + private static final String TAG = "XmlBlockBenchmark"; + private static final String NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android"; + + @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + private XmlBlock.Parser mParser; + + private void cleanCache() { + if (mParser != null) { + mParser.close(); + } + + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + final Resources resources = context.getResources(); + resources.getImpl().clearAllCaches(); + Log.d(TAG, "cleanCache"); + } + + private XmlBlock.Parser getNewParser() { + cleanCache(); + + final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + final Resources resources = context.getResources(); + return (XmlBlock.Parser) resources.getXml(R.layout.linear_layout_for_xmlblock_benchmark); + } + + @Before + public void setUp() { + mParser = getNewParser(); + } + + @After + public void tearDown() { + cleanCache(); + } + + int safeNext() throws XmlPullParserException, IOException { + while (true) { + int parseState = mParser.next(); + if (parseState == START_TAG) { + return parseState; + } else if (parseState == END_DOCUMENT) { + mParser = getNewParser(); + } + } + } + + @Test + public void throwNpeCausedByNullDocument() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + mParser.close(); + while (state.keepRunning()) { + try { + mParser.getClassAttribute(); + } catch (NullPointerException e) { + continue; + } + Assert.fail("It shouldn't be here!"); + } + } + + @Test + public void getNext() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + int parseState = mParser.next(); + state.pauseTiming(); + if (parseState == END_DOCUMENT) { + mParser = getNewParser(); + } + state.resumeTiming(); + } + } + + private <T> void benchmarkTagFunction(BenchmarkState state, String name, + Supplier<T> measureTarget) + throws XmlPullParserException, IOException { + while (state.keepRunning()) { + state.pauseTiming(); + int parseState = safeNext(); + + if (parseState != END_DOCUMENT) { + final String tagName = mParser.getName(); + state.resumeTiming(); + final T value = measureTarget.get(); + state.pauseTiming(); + Log.d(TAG, + TextUtils.formatSimple("%s() in tag %s is %s", name, tagName, value)); + } + state.resumeTiming(); + } + } + + @Test + public void getNamespace() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getNamespace", () -> mParser.getNamespace()); + } + + @Test + public void getName() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getName", () -> mParser.getName()); + } + + @Test + public void getText() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getText", () -> mParser.getText()); + } + + @Test + public void getLineNumber() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getLineNumber", () -> mParser.getLineNumber()); + } + + @Test + public void getAttributeCount() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getAttributeCount", () -> mParser.getAttributeCount()); + } + + private <T> void benchmarkAttributeFunction(BenchmarkState state, String name, + Function<Integer, T> measureTarget) + throws XmlPullParserException, IOException { + boolean needNext = true; + boolean needGetCount = false; + int attributeCount = 0; + int i = 0; + while (state.keepRunning()) { + state.pauseTiming(); + if (needNext) { + int parseState = safeNext(); + if (parseState == START_TAG) { + needNext = false; + needGetCount = true; + } + } + + if (needGetCount) { + attributeCount = mParser.getAttributeCount(); + needGetCount = false; + i = 0; + } + + if (i < attributeCount) { + final String tagName = mParser.getName(); + final String attributeName = mParser.getAttributeName(i); + state.resumeTiming(); + final T value = measureTarget.apply(i); + state.pauseTiming(); + Log.d(TAG, + TextUtils.formatSimple("%s(%d:%s) in tag %s is %s", name, i, attributeName, + tagName, value)); + i++; + } + + if (i >= attributeCount) { + needNext = true; + } + state.resumeTiming(); + } + } + + @Test + public void getAttributeNamespace() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkAttributeFunction(state, "getAttributeNamespace", + attributeIndex -> mParser.getAttributeNamespace(attributeIndex)); + } + + @Test + public void getAttributeName() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkAttributeFunction(state, "getAttributeName", + attributeIndex -> mParser.getAttributeName(attributeIndex)); + } + + @Test + public void getAttributeNameResource() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkAttributeFunction(state, "getAttributeNameResource", + attributeIndex -> mParser.getAttributeNameResource(attributeIndex)); + } + + /** + * benchmark {@link android.content.res.XmlBlock#nativeGetAttributeDataType(long, int)} and + * {@link android.content.res.XmlBlock#nativeGetAttributeData(long, int)} + */ + @Test + public void getAttributeDataXXX() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkAttributeFunction(state, "getAttributeDataXXX", + attributeIndex -> mParser.getAttributeValue(attributeIndex)); + } + + @Test + public void getSourceResId() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getSourceResId", () -> mParser.getSourceResId()); + } + + @Test + public void getIdAttribute() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getIdAttribute", () -> mParser.getIdAttribute()); + } + + @Test + public void getClassAttribute() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getClassAttribute", () -> mParser.getClassAttribute()); + } + + @Test + public void getStyleAttribute() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getStyleAttribute", () -> mParser.getStyleAttribute()); + } + + @Test + public void getAttributeIndex() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + benchmarkTagFunction(state, "getAttributeValue", + () -> mParser.getAttributeValue(NAMESPACE_ANDROID, "layout_width")); + } + + @Test + public void parseOneXmlDocument() throws XmlPullParserException, IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + mParser = getNewParser(); + state.resumeTiming(); + + int parseState; + while ((parseState = mParser.next()) != END_DOCUMENT) { + if (parseState == START_DOCUMENT) { + state.pauseTiming(); + Log.d(TAG, "parseOneXmlDocument: start document"); + state.resumeTiming(); + } else if (parseState == START_TAG) { + final String tagName = mParser.getName(); + state.pauseTiming(); + Log.d(TAG, TextUtils.formatSimple("parseOneXmlDocument: tag %s {[", tagName)); + state.resumeTiming(); + for (int i = 0, count = mParser.getAttributeCount(); i < count; i++) { + final String attributeName = mParser.getAttributeName(i); + final String attributeValue = mParser.getAttributeValue(i); + + state.pauseTiming(); + Log.d(TAG, TextUtils.formatSimple( + "parseOneXmlDocument: attribute %d {%s = %s},", i, attributeName, + attributeValue)); + state.resumeTiming(); + } + state.pauseTiming(); + Log.d(TAG, "parseOneXmlDocument: ]"); + state.resumeTiming(); + } else if (parseState == END_TAG) { + state.pauseTiming(); + Log.d(TAG, "parseOneXmlDocument: }"); + state.resumeTiming(); + } else { + final String text = mParser.getText(); + state.pauseTiming(); + Log.d(TAG, TextUtils.formatSimple( + "parseOneXmlDocument: parseState = %d, text = %s", parseState, text)); + state.resumeTiming(); + } + } + } + } +} |