Denoise hermetric surfaceflinger perf tests
Remove overheard by disabling features during the test including:
- perfetto tracing
- region sampling by hiding navbar
- transaction tracing
Reduce variations between each frame by
- forcing max frame rate (avoids any frame misses)
- consuming transform hint (avoids gpu comp)
- starting simpleperf after test setup to move test activity
launch outside of measurement window
Test: atest android.surfaceflinger.SurfaceFlingerPerfTest
Bug: 298240242
Change-Id: Ida7422c37b9afa323147949c9776c042ca97cd08
diff --git a/apct-tests/perftests/surfaceflinger/Android.bp b/apct-tests/perftests/surfaceflinger/Android.bp
index 0c28bce..21d0d44 100644
--- a/apct-tests/perftests/surfaceflinger/Android.bp
+++ b/apct-tests/perftests/surfaceflinger/Android.bp
@@ -32,6 +32,7 @@
"apct-perftests-utils",
"collector-device-lib",
"platform-test-annotations",
+ "cts-wm-util",
],
test_suites: ["device-tests"],
data: [":perfetto_artifacts"],
diff --git a/apct-tests/perftests/surfaceflinger/AndroidManifest.xml b/apct-tests/perftests/surfaceflinger/AndroidManifest.xml
index 26f2586..aa55b01 100644
--- a/apct-tests/perftests/surfaceflinger/AndroidManifest.xml
+++ b/apct-tests/perftests/surfaceflinger/AndroidManifest.xml
@@ -16,9 +16,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.perftests.surfaceflinger">
- <!-- permission needed to write perfetto trace and read/write simpleperf report -->
+ <!-- permission needed to read/write simpleperf report -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- permission needed to disable tracing -->
+ <uses-permission android:name="android.permission.HARDWARE_TEST" />
<application android:label="SurfaceFlingerPerfTests">
<uses-library android:name="android.test.runner" />
diff --git a/apct-tests/perftests/surfaceflinger/AndroidTest.xml b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
index 58cf58b..6dcd86e 100644
--- a/apct-tests/perftests/surfaceflinger/AndroidTest.xml
+++ b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
@@ -44,17 +44,12 @@
<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,android.device.collectors.SimpleperfListener" />
-
- <!-- 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" />
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.SimpleperfListener" />
<option name="instrumentation-arg" key="profiling-iterations" value="525" />
- <!-- 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" />
<!-- SimpleperfListener related arguments -->
+ <option name="instrumentation-arg" key="record" value="false"/>
<option name="instrumentation-arg" key="report" value="true" />
<option name="instrumentation-arg" key="arguments" value="-g" />
<option name="instrumentation-arg" key="events_to_record" value="instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking" />
@@ -70,13 +65,11 @@
<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" />
-
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="directory-keys" value="/data/local/tmp/SurfaceFlingerPerfTests" />
<!-- Needed for pulling the collected trace config on to the host -->
- <option name="pull-pattern-keys" value="perfetto_file_path" />
<option name="pull-pattern-keys" value="simpleperf_file_path" />
</metrics_collector>
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
index 8a447bb..8d6dd12 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
@@ -16,6 +16,10 @@
package android.surfaceflinger;
+import static android.view.SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
+import static android.view.SurfaceControl.BUFFER_TRANSFORM_ROTATE_270;
+import static android.view.SurfaceControl.BUFFER_TRANSFORM_ROTATE_90;
+
import android.annotation.ColorInt;
import android.graphics.Canvas;
import android.graphics.GraphicBuffer;
@@ -33,9 +37,11 @@
* @hide
*/
public class BufferFlinger {
+ private final int mTransformHint;
ArrayBlockingQueue<GraphicBuffer> mBufferQ;
- public BufferFlinger(int numOfBuffers, @ColorInt int color) {
+ public BufferFlinger(int numOfBuffers, @ColorInt int color, int bufferTransformHint) {
+ mTransformHint = bufferTransformHint;
mBufferQ = new ArrayBlockingQueue<>(numOfBuffers);
while (numOfBuffers > 0) {
@@ -56,12 +62,18 @@
public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl) {
try {
final GraphicBuffer buffer = mBufferQ.take();
- t.setBuffer(surfaceControl,
+ int transform = BUFFER_TRANSFORM_IDENTITY;
+ if (mTransformHint == BUFFER_TRANSFORM_ROTATE_90) {
+ transform = BUFFER_TRANSFORM_ROTATE_270;
+ } else if (mTransformHint == BUFFER_TRANSFORM_ROTATE_270) {
+ transform = BUFFER_TRANSFORM_ROTATE_90;
+ }
+ t.setBufferTransform(surfaceControl, transform);
+ t.setBuffer(
+ surfaceControl,
HardwareBuffer.createFromGraphicBuffer(buffer),
null,
- (SyncFence fence) -> {
- releaseCallback(fence, buffer);
- });
+ (SyncFence fence) -> releaseCallback(fence, buffer));
} catch (InterruptedException ignore) {
}
}
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
index dca818e..fd9d991 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -16,6 +16,9 @@
package android.surfaceflinger;
+import static android.server.wm.CtsWindowInfoUtils.waitForWindowOnTop;
+
+import android.app.Instrumentation;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -25,12 +28,13 @@
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.helpers.SimpleperfHelper;
+
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -39,6 +43,8 @@
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Random;
@@ -63,12 +69,33 @@
public final RuleChain mAllRules = RuleChain
.outerRule(mActivityRule);
+ private int mTransformHint;
+ private SimpleperfHelper mSimpleperfHelper = new SimpleperfHelper();
+
+ /** Start simpleperf sampling. */
+ public void startSimpleperf(String subcommand, String arguments) {
+ if (!mSimpleperfHelper.startCollecting(subcommand, arguments)) {
+ Log.e(TAG, "Simpleperf did not start successfully.");
+ }
+ }
+
+ /** Stop simpleperf sampling and dump the collected file into the given path. */
+ private void stopSimpleperf(Path path) {
+ if (!mSimpleperfHelper.stopCollecting(path.toString())) {
+ Log.e(TAG, "Failed to collect the simpleperf output.");
+ }
+ }
+
@BeforeClass
public static void suiteSetup() {
final Bundle arguments = InstrumentationRegistry.getArguments();
sProfilingIterations = Integer.parseInt(
arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
Log.d(TAG, "suiteSetup: mProfilingIterations = " + sProfilingIterations);
+ // disable transaction tracing
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .executeShellCommand("service call SurfaceFlinger 1041 i32 -1");
}
@Before
@@ -77,17 +104,45 @@
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
for (int i = 0; i < MAX_BUFFERS; i++) {
SurfaceControl sc = createSurfaceControl();
- BufferFlinger bufferTracker = createBufferTracker(Color.argb(getRandomColorComponent(),
- getRandomColorComponent(), getRandomColorComponent(),
- getRandomColorComponent()));
+ BufferFlinger bufferTracker =
+ createBufferTracker(
+ Color.argb(
+ getRandomColorComponent(),
+ getRandomColorComponent(),
+ getRandomColorComponent(),
+ getRandomColorComponent()),
+ mActivity.getBufferTransformHint());
bufferTracker.addBuffer(t, sc);
t.setPosition(sc, i * 10, i * 10);
}
t.apply(true);
+ mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
+ mTransaction.show(mSurfaceControls.get(0)).apply(true);
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+
+ instrumentation.waitForIdleSync();
+ // Wait for device animation that shows above the activity to leave.
+ try {
+ waitForWindowOnTop(mActivity.getWindow());
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Failed to wait for window", e);
+ }
+ String args =
+ "-o /data/local/tmp/perf.data -g -e"
+ + " instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking -p "
+ + mSimpleperfHelper.getPID("surfaceflinger")
+ + ","
+ + mSimpleperfHelper.getPID("android.perftests.surfaceflinger");
+ startSimpleperf("record", args);
}
@After
public void teardown() {
+ try {
+ mSimpleperfHelper.stopSimpleperf();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to stop simpleperf", e);
+ }
mSurfaceControls.forEach(SurfaceControl::release);
mBufferTrackers.forEach(BufferFlinger::freeBuffers);
}
@@ -97,8 +152,9 @@
}
private final ArrayList<BufferFlinger> mBufferTrackers = new ArrayList<>();
- private BufferFlinger createBufferTracker(int color) {
- BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
+
+ private BufferFlinger createBufferTracker(int color, int bufferTransformHint) {
+ BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color, bufferTransformHint);
mBufferTrackers.add(bufferTracker);
return bufferTracker;
}
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
index bb95659..5f1f44d 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
@@ -16,12 +16,15 @@
package android.surfaceflinger;
+import static android.view.Surface.FRAME_RATE_COMPATIBILITY_DEFAULT;
+
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@@ -42,6 +45,11 @@
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ View decorView = getWindow().getDecorView();
+ // Hide both the navigation bar and the status bar.
+ int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ decorView.setSystemUiVisibility(uiOptions);
+
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mTestSurfaceView = new TestSurfaceView(this);
setContentView(mTestSurfaceView);
@@ -51,6 +59,10 @@
return mTestSurfaceView.getChildSurfaceControlHelper();
}
+ public int getBufferTransformHint() {
+ return mTestSurfaceView.getRootSurfaceControl().getBufferTransformHint();
+ }
+
public class TestSurfaceView extends SurfaceView {
public TestSurfaceView(Context context) {
super(context);
@@ -79,6 +91,9 @@
// check to see if surface is valid
if (holder.getSurface().isValid()) {
mSurfaceControl = getSurfaceControl();
+ new SurfaceControl.Transaction()
+ .setFrameRate(mSurfaceControl, 1000, FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .apply(true);
}
return new SurfaceControl.Builder()
.setName("ChildSurfaceControl")