我正在尝试使用 FrameTimingMetric 在回收器视图上执行 5 次迭代的滚动测试。
我使用 StartupTimingMetric() 的 AppStartup 测试工作正常,并为所有 5 次迭代生成结果。
对于使用 FrameTimingMetric 的滚动测试,它正在执行第一次迭代并且 recyclerview 滚动,但在该测试失败并出现错误(java.lang.IllegalArgumentException:失败的要求)后,应用程序退出并且没有迭代其他剩余的 4 次迭代。
Macrobenchmark 类。
@RunWith(AndroidJUnit4.class)
public class ExampleStartupBenchmark {
@Rule
public MacrobenchmarkRule mBenchmarkRule = new MacrobenchmarkRule();
@Test
public void startup() {
mBenchmarkRule.measureRepeated(
"my-app-package-name",
Collections.singletonList(new StartupTimingMetric()),
CompilationMode.DEFAULT,
StartupMode.COLD,
5,
scope -> {
scope.startActivityAndWait();
return Unit.INSTANCE;
});
}
@Test
public void scroll() {
mBenchmarkRule.measureRepeated(
"my-app-package-name",
Collections.singletonList(new FrameTimingMetric()),
CompilationMode.DEFAULT,
StartupMode.COLD,
5,
macrobenchmarkScope -> {
Log.i("MacrobenchmarkRuleTAG", "justBeforeIntent");
Intent intent = new Intent("MarkMainActivity-intentlaunch-string");
macrobenchmarkScope.startActivityAndWait(intent);
// Wait until activity is shown.
Log.i("MacrobenchmarkRuleTAG", "justBeforeMarkMainActivityWait");
macrobenchmarkScope.getDevice().wait(
Until.hasObject(By.clazz("MarkMainActivity")),
10_000L
);
Log.i("MacrobenchmarkRuleTAG", "justAfterMarkMainActivityWait");
return Unit.INSTANCE;
}, scope ->{
UiDevice device = scope.getDevice();
UiObject2 recycler = device.findObject(By.res(scope.getPackageName(), "mark_recyclerview"));
SearchCondition<Boolean> searchCond2 = Until.hasObject(By.res("mark_adapter_single_view"));
recycler.wait(searchCond2, 10_000L); // wait until recyclerview object loads a singleitemview
Log.i("MacrobenchmarkRuleTAG", recycler.getClassName());
recycler.setGestureMargin(device.getDisplayWidth() / 5);
Log.i("MacrobenchmarkRuleTAG", "justbeforefling");
recycler.scroll(Direction.DOWN, 55);
return Unit.INSTANCE;
});
}
}
我的 AppStartup 测试运行良好,进行了 5 次迭代并生成结果。所以我最初的基准测试模块设置应该没问题。
对于滚动测试,我需要等到recyclerview加载,因为数据来自MarkMainActivity的Oncreate方法上的API调用,然后recyclerview启动并加载。 所以我尝试为回收器视图设置一些等待条件(“mark_recyclerview”是recyclerview的xml Id)及其singleItem布局(“mark_adapter_single_view”是singleItemView的xml Id)。
对于这段代码,我的markactivity正在打开并且recyclerview正在加载,然后几秒钟后,执行滚动,之后我的测试因错误而停止(java.lang.IllegalArgumentException:失败的要求)并且应用程序关闭并且没有执行剩余的操作4 次迭代。
此外,为了检查日志,日志被写入到最后一个,即:Log.i(“MacrobenchmarkRuleTAG”,“justbeforefling”)。并且还执行了滚动。 所以测试应该执行到最后一行。
如果有人有任何意见或建议,请帮助我了解如何为此用例执行剩余的四次迭代并生成输出。
谢谢。
错误代码:
java.lang.IllegalArgumentException: Failed requirement.
at androidx.benchmark.macro.perfetto.FrameTimingQuery.getFrameSubMetrics(FrameTimingQuery.kt:182)
at androidx.benchmark.macro.FrameTimingMetric.getMetrics$benchmark_macro_release(Metric.kt:231)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmark(Macrobenchmark.kt:209)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmarkWithStartupMode(Macrobenchmark.kt:301)
at androidx.benchmark.macro.junit4.MacrobenchmarkRule.measureRepeated(MacrobenchmarkRule.kt:106)
at com.tc.macrobenchmark.ExampleStartupBenchmark.scroll(ExampleStartupBenchmark.java:51)
我遵循以下准则: 宏观基准
FrameTimingQuery.kt 是一个辅助类,用于从 perfetto 跟踪查询帧信息。
“java.lang.IllegalArgumentException:未满足要求。”是 kotlin 中的
require
语句抛出的异常。
FrameTimingQuery.kt 类中有 3 个 require 语句。
require(actualSlices.isEmpty() == newSlicesShouldBeEmpty)
require(expectedSlices.isEmpty() == newSlicesShouldBeEmpty)
require(slices.none { it.frameId == null })
一定有一个不满意的地方。
Slice 表示带有开始/结束时间戳和名称的跟踪事件。 实际切片是指应用程序生成帧切片 Expexted Slice 表示应用程序期望生成帧切片 FrameId 是 Expected/Actual Slice 中的 id,Choreographer#doFrame 中 UiThread 中的 slice,drawFrames 中 RenderThread 中的 id,这有助于将它们关联起来。
您需要通过macrobenchmark测试检查perfetto跟踪记录,使用https://ui.perfetto.dev/打开它,手动检查。