Add androidx.benchmark.iterations argument for controlling measurement iters
Test: ./gradlew benchmark:benchmark-common:cC -P android.testInstrumentationRunnerArguments.androidx.benchmark.iterations=100 -P android.testInstrumentationRunnerArguments.class=androidx.benchmark.BenchmarkStateTest
Fixes: 194137879
Note: this doesn't modify warmup, which is still an arbitrary number
of iterations. The initial intent is to support profiling use cases
(which should use androidx.benchmark.profiling.*), or experimenting
locally when providing feedback on automatic iteration determination.
Change-Id: I1682ccff011f430da564cedf9113fb628b8d87b4
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ArgumentInjectingApplication.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ArgumentInjectingApplication.kt
index 6f2d759..3a06fab 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ArgumentInjectingApplication.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/ArgumentInjectingApplication.kt
@@ -39,6 +39,9 @@
super.onCreate()
argumentSource = Bundle().apply {
+ // allow cli args to pass through
+ putAll(InstrumentationRegistry.getArguments())
+
// Since these benchmark correctness tests run as part of the regular
// (non-performance-test) suite, they will have debuggable=true, won't be clock-locked,
// can run with low-battery or on an emulator, and code coverage enabled.
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
index 0deb870..f05047f 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
@@ -17,7 +17,6 @@
package androidx.benchmark
import android.Manifest
-import android.util.Log
import androidx.benchmark.BenchmarkState.Companion.ExperimentalExternalReport
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
@@ -29,6 +28,7 @@
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
+import org.junit.Assume.assumeTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -166,6 +166,10 @@
val expectedCount = report.warmupIterations + report.repeatIterations * expectedRepeatCount
assertEquals(expectedCount, total)
+ if (Arguments.iterations != null) {
+ assertEquals(Arguments.iterations, report.repeatIterations)
+ }
+
// verify we're not in warmup mode
assertTrue(report.warmupIterations > 0)
assertTrue(report.repeatIterations > 1)
@@ -180,16 +184,14 @@
@Test
public fun iterationCheck_withAllocations() {
- if (CpuInfo.locked ||
- IsolationActivity.sustainedPerformanceModeInUse ||
- Errors.isEmulator
- ) {
- // In any of these conditions, it's known that throttling won't happen, so it's safe
- // to check for allocation count, by setting checkingForThermalThrottling = false
- iterationCheck(checkingForThermalThrottling = false)
- } else {
- Log.d(BenchmarkState.TAG, "Warning - bypassing iterationCheck_withAllocations")
- }
+ // In any of these conditions, it's known that throttling won't happen, so it's safe
+ // to check for allocation count, by setting checkingForThermalThrottling = false
+ assumeTrue(
+ CpuInfo.locked ||
+ IsolationActivity.sustainedPerformanceModeInUse ||
+ Errors.isEmulator
+ )
+ iterationCheck(checkingForThermalThrottling = false)
}
@Test
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
index c14a978..04d0004 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
@@ -42,6 +42,7 @@
internal val outputEnable: Boolean
internal val startupMode: Boolean
internal val dryRunMode: Boolean
+ internal val iterations: Int?
internal val profiler: Profiler?
internal val profilerSampleFrequency: Int
internal val profilerSampleDurationSeconds: Long
@@ -81,6 +82,9 @@
outputEnable = !dryRunMode &&
(arguments.getBenchmarkArgument("output.enable")?.toBoolean() ?: true)
+ iterations =
+ arguments.getBenchmarkArgument("iterations")?.toInt()
+
// Transform comma-delimited list into set of suppressed errors
// E.g. "DEBUGGABLE, UNLOCKED" -> setOf("DEBUGGABLE", "UNLOCKED")
suppressedErrors = arguments.getBenchmarkArgument("suppressErrors", "")
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
index b7d6f56..518fbc7 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
@@ -440,11 +440,9 @@
}
private fun computeMaxIterations(): Int {
- var idealIterations =
- (REPEAT_DURATION_TARGET_NS / warmupManager.estimatedIterationTimeNs).toInt()
- idealIterations = idealIterations.coerceIn(MIN_TEST_ITERATIONS, MAX_TEST_ITERATIONS)
- OVERRIDE_ITERATIONS?.let { idealIterations = OVERRIDE_ITERATIONS }
- return idealIterations
+ return OVERRIDE_ITERATIONS
+ ?: (REPEAT_DURATION_TARGET_NS / warmupManager.estimatedIterationTimeNs).toInt()
+ .coerceIn(MIN_TEST_ITERATIONS, MAX_TEST_ITERATIONS)
}
private fun throwIfPaused() = check(!paused) {
@@ -547,11 +545,13 @@
internal const val REPEAT_COUNT_ALLOCATION = 5
- private val OVERRIDE_ITERATIONS = if (
+ private val OVERRIDE_ITERATIONS = when {
Arguments.dryRunMode ||
- Arguments.startupMode ||
- Arguments.profiler?.requiresSingleMeasurementIteration == true
- ) 1 else null
+ Arguments.startupMode ||
+ Arguments.profiler?.requiresSingleMeasurementIteration == true -> 1
+ Arguments.iterations != null -> Arguments.iterations
+ else -> null
+ }
internal val REPEAT_DURATION_TARGET_NS = when (Arguments.profiler?.requiresExtraRuntime) {
// longer measurements while profiling to ensure we have enough data
diff --git a/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/ArgumentInjectingApplication.kt b/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/ArgumentInjectingApplication.kt
index c8085ea..202b117 100644
--- a/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/ArgumentInjectingApplication.kt
+++ b/benchmark/benchmark-junit4/src/androidTest/java/androidx/benchmark/junit4/ArgumentInjectingApplication.kt
@@ -19,6 +19,7 @@
import android.app.Application
import android.os.Bundle
import androidx.benchmark.argumentSource
+import androidx.test.platform.app.InstrumentationRegistry
/**
* Hack to enable overriding benchmark arguments (since we can't easily do this in CI, per apk)
@@ -39,7 +40,8 @@
super.onCreate()
argumentSource = Bundle().apply {
- putString("androidx.benchmark.output.enable", "true")
+ // allow cli args to pass through
+ putAll(InstrumentationRegistry.getArguments())
// Since these benchmark correctness tests run as part of the regular
// (non-performance-test) suite, they will have debuggable=true, won't be clock-locked,