I am trying to perform a scroll test on a recycler view using FrameTimingMetric for 5 iterations.
My AppStartup Test using StartupTimingMetric() is working fine and generating results for all 5 iterations.
For scroll test using FrameTimingMetric, it is performing first iteration and recyclerview scrolled, but after that test failed with error (java.lang.IllegalArgumentException: Failed requirement) app exits and didn't iterate for other remaining 4 iterations.
Macrobenchmark class.
@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;
});
}
}
My AppStartup test is working fine for 5 iterations and generating results. So my initial benchmark module setup should be fine.
For scroll test, I need to wait till recyclerview loading, as data coming from API calling on Oncreate Method of MarkMainActivity and after that recyclerview is initiating and loading. So I tried to put some wait condition for recycler view ( "mark_recyclerview" is xml Id of recyclerview ) and its singleItem Layout("mark_adapter_single_view" is xml Id for singleItemView).
For this code, my markactivity is opening and recyclerview is loading, then after some seconds ,scroll was performed, and after that my tests stopped with error (java.lang.IllegalArgumentException: Failed requirement) and app closed and didn't perform remaining 4 iterations.
Also, to check with logs, logs were written till last one i.e : Log.i("MacrobenchmarkRuleTAG", "justbeforefling"). And also scroll was performed. So test should be executed through till last line.
if anyone has any inputs or suggestions, please help me on how to perform remaining four iterations for this usecase and generate outputs.
Thanks.
Error code :
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)
I am following these guidelines: macrobenchmark
First you need know ,how the FrameTimingMetric works.
FrameTimingMetric works by perfetto trace. it querys four types of slices from perfetto trace file.
relate them by FrameId in the slices, and encapsulate related four types slices in FrameData class.
so If there miss any type of slices, or no FrameId in slices, The FrameTimingMetric can't work properly.
Second, FrameTimingQuery.kt is a helper class for FrameTimingMetirc to query frame informations from perfetto trace. Exception is thrown by this class
the "java.lang.IllegalArgumentException: Failed requirement." is a exception that
requirestatement in kotlin language throws.(Macrobenchmark is written in kotlin).there're three require statemets in FrameTimingQuery.kt class.
there must be one of them which is not satisfied.
Last, you need debug your testcase by debugger.
adb shell "am instrument -w -e debug true [your instrumentation package name]"
-e debug truemakes your instrumentation test waiting for debuggerthen you use debugger in android studio to attach the instrumentation process
Cause Where does the FameId in the slice come from?
FrameId comes from the last sub string by dividing slice name with space character.
because the last substring of choreographer#doFrame is this, that cause frameId null. So that's why your testcases don't work.
you need give your feedback at this website( I have done that) or write your own metric.
--TO THE LAST-- I have rewritten the FrameTimingMetric, you can new a class named FrameMetric, copy codes to it, use it in repeat function.