blob: a43d2aa38e8a4bc047f2578391d8c1393ac17581 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.benchmark.junit4
import androidx.annotation.CallSuper
import androidx.benchmark.IsolationActivity
import androidx.test.runner.AndroidJUnitRunner
/**
* Instrumentation runner for benchmarks, used to increase stability of measurements and minimize
* interference.
*
* To use this runner, put the following in your module level `build.gradle`:
*
* ```
* android {
* defaultConfig {
* testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
* }
* }
* ```
*
* ## Minimizing Interference
*
* This runner launches a simple opaque activity used to reduce benchmark interference from other
* windows. Launching other activities is supported e.g. via ActivityTestRule and ActivityScenario -
* the opaque activity will be relaunched if not actively running before each test, and after each
* test's cleanup is complete.
*
* For example, sources of potential interference:
* - live wallpaper rendering
* - homescreen widget updates
* - hotword detection
* - status bar repaints
* - running in background (some cores may be foreground-app only)
*
* ## Clock Stability
*
* While it is better for performance stability to lock clocks with the `./gradlew lockClocks` task
* provided by the gradle plugin, this is not possible on most devices. The runner provides a
* fallback mode for preventing thermal throttling.
*
* On devices that support [android.view.Window.setSustainedPerformanceMode], the runner will set
* this mode on the window of every Activity launched (including the opaque Activity mentioned
* above). The runner will also launch a continuously spinning Thread. Together, these ensure that
* the app runs in the multithreaded stable performance mode, which locks the maximum clock
* frequency to prevent thermal throttling. This ensures stable clock levels across all benchmarks,
* even if a continuous suite of benchmarks runs for many minutes on end.
*/
@Suppress("unused") // Note: not referenced by code
public open class AndroidBenchmarkRunner : AndroidJUnitRunner() {
@CallSuper
override fun waitForActivitiesToComplete() {
// We don't call the super method here, since we have
// an activity we intend to persist between tests
// TODO: somehow wait for every activity but IsolationActivity
// Before/After each test, from the test thread, synchronously launch
// our IsolationActivity if it's not already resumed
var isResumed = false
runOnMainSync {
isResumed = IsolationActivity.resumed
}
if (!isResumed) {
IsolationActivity.launchSingleton()
}
}
@CallSuper
override fun onDestroy() {
IsolationActivity.finishSingleton()
super.waitForActivitiesToComplete()
super.onDestroy()
}
}