-
Notifications
You must be signed in to change notification settings - Fork 0
feat(ANDPERF-5): add fast-scroll benchmarks; split tests & harden runner #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package dev.egarcia.andperf.benchmark | ||
|
|
||
| import androidx.test.platform.app.InstrumentationRegistry | ||
| import androidx.test.uiautomator.UiDevice | ||
|
|
||
| /** Shared helpers for benchmarks. Keep this class minimal and free of instrumentation-specific | ||
| * side-effects so it can be used by multiple test classes. */ | ||
| object BenchmarkUtils { | ||
|
|
||
| val device: UiDevice | ||
| get() = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) | ||
|
|
||
| fun isPackageInstalled(packageName: String): Boolean { | ||
| return try { | ||
| val context = InstrumentationRegistry.getInstrumentation().context | ||
| context.packageManager.getApplicationInfo(packageName, 0) | ||
| true | ||
| } catch (_: Exception) { | ||
| false | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| package dev.egarcia.andperf.benchmark | ||
|
|
||
| import androidx.benchmark.macro.FrameTimingMetric | ||
| import androidx.benchmark.macro.StartupMode | ||
| import androidx.benchmark.macro.StartupTimingMetric | ||
| import androidx.benchmark.macro.junit4.MacrobenchmarkRule | ||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
| import org.junit.Assume | ||
| import org.junit.Rule | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
|
|
||
| @RunWith(AndroidJUnit4::class) | ||
| class ComposeBenchmarks { | ||
|
|
||
| @get:Rule | ||
| val rule = MacrobenchmarkRule() | ||
|
|
||
| @Test | ||
| fun coldStartup_compose() { | ||
| val pkg = "dev.egarcia.andperf.compose" | ||
| // Skip if the expected target package is not installed on the device | ||
| Assume.assumeTrue("Skipping test because target package $pkg is not installed", BenchmarkUtils.isPackageInstalled(pkg)) | ||
|
|
||
| try { | ||
| rule.measureRepeated( | ||
| packageName = pkg, | ||
| metrics = listOf(StartupTimingMetric(), FrameTimingMetric()), | ||
| iterations = 3, | ||
| startupMode = StartupMode.COLD, | ||
| measureBlock = { startActivityAndWait() } | ||
| ) | ||
| } catch (t: Throwable) { | ||
| // Treat metric collection errors as skipped (device may not surface frame metrics) | ||
| Assume.assumeTrue("Skipping benchmark due to metric error: ${t.message}", false) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun fastScroll_compose() { | ||
| val pkg = "dev.egarcia.andperf.compose" | ||
| Assume.assumeTrue("Skipping test because target package $pkg is not installed", BenchmarkUtils.isPackageInstalled(pkg)) | ||
|
|
||
| try { | ||
| rule.measureRepeated( | ||
| packageName = pkg, | ||
| metrics = listOf(FrameTimingMetric()), | ||
| iterations = 5, | ||
| startupMode = StartupMode.WARM, | ||
| measureBlock = { | ||
| // perform a series of scroll gestures using UiAutomator helper | ||
| val device = BenchmarkUtils.device | ||
| val width = device.displayWidth | ||
| val height = device.displayHeight | ||
| val startX = (width * 0.5).toInt() | ||
| val startY = (height * 0.8).toInt() | ||
| val endY = (height * 0.2).toInt() | ||
| repeat(8) { | ||
| device.swipe(startX, startY, startX, endY, 50) | ||
| Thread.sleep(150) | ||
| } | ||
| } | ||
|
Comment on lines
+50
to
+62
|
||
| ) | ||
| } catch (t: Throwable) { | ||
| // Treat metric collection errors as skipped (devices may return 0 frame samples) | ||
| Assume.assumeTrue("Skipping benchmark due to metric error: ${t.message}", false) | ||
| } | ||
| } | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package dev.egarcia.andperf.benchmark | ||
|
|
||
| import androidx.benchmark.macro.StartupMode | ||
| import androidx.benchmark.macro.StartupTimingMetric | ||
| import androidx.benchmark.macro.junit4.MacrobenchmarkRule | ||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
| import org.junit.Assume | ||
| import org.junit.Rule | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
|
|
||
| @RunWith(AndroidJUnit4::class) | ||
| class ViewBenchmarks { | ||
|
|
||
| @get:Rule | ||
| val rule = MacrobenchmarkRule() | ||
|
|
||
| @Test | ||
| fun coldStartup_view() { | ||
| val pkg = "dev.egarcia.andperf.view" | ||
| Assume.assumeTrue("Skipping test because target package $pkg is not installed", BenchmarkUtils.isPackageInstalled(pkg)) | ||
|
|
||
| try { | ||
| // For view implementation, avoid FrameTimingMetric on some targets that don't provide frame metrics. | ||
| rule.measureRepeated( | ||
| packageName = pkg, | ||
| metrics = listOf(StartupTimingMetric()), | ||
| iterations = 3, | ||
| startupMode = StartupMode.COLD, | ||
| measureBlock = { startActivityAndWait() } | ||
| ) | ||
| } catch (t: Throwable) { | ||
| Assume.assumeTrue("Skipping benchmark due to metric error: ${t.message}", false) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun fastScroll_view() { | ||
| val pkg = "dev.egarcia.andperf.view" | ||
| Assume.assumeTrue("Skipping test because target package $pkg is not installed", BenchmarkUtils.isPackageInstalled(pkg)) | ||
|
|
||
| try { | ||
| rule.measureRepeated( | ||
| packageName = pkg, | ||
| metrics = listOf(), // rely on startup/frame metrics where appropriate; keep minimal | ||
| iterations = 5, | ||
| startupMode = StartupMode.WARM, | ||
| measureBlock = { | ||
| val device = BenchmarkUtils.device | ||
| val width = device.displayWidth | ||
| val height = device.displayHeight | ||
| val startX = (width * 0.5).toInt() | ||
| val startY = (height * 0.8).toInt() | ||
| val endY = (height * 0.2).toInt() | ||
| repeat(8) { | ||
| device.swipe(startX, startY, startX, endY, 50) | ||
| Thread.sleep(150) | ||
| } | ||
| } | ||
|
Comment on lines
+48
to
+59
|
||
| ) | ||
| } catch (t: Throwable) { | ||
| Assume.assumeTrue("Skipping benchmark due to metric error: ${t.message}", false) | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code block fence opening syntax is incorrect. It should be
```(three backticks) not```/(three backticks followed by a slash). The slash makes this invalid markdown syntax.