Skip to content
Snippets Groups Projects
Commit dd87ba45 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

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
parent 6a853abc
No related branches found
No related tags found
No related merge requests found
......@@ -32,6 +32,7 @@ android_test {
"apct-perftests-utils",
"collector-device-lib",
"platform-test-annotations",
"cts-wm-util",
],
test_suites: ["device-tests"],
data: [":perfetto_artifacts"],
......
......@@ -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" />
......
......@@ -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>
......
......@@ -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 @@ import java.util.concurrent.ArrayBlockingQueue;
* @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 class BufferFlinger {
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) {
}
}
......
......@@ -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.SurfaceControl;
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.Test;
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 class SurfaceFlingerPerfTest {
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 @@ public class SurfaceFlingerPerfTest {
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 @@ public class SurfaceFlingerPerfTest {
}
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;
}
......
......@@ -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 @@ public class SurfaceFlingerTestActivity extends Activity {
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 @@ public class SurfaceFlingerTestActivity extends Activity {
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 @@ public class SurfaceFlingerTestActivity extends Activity {
// 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")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment