[go: nahoru, domu]

blob: 2c0bc9c07361258e9b62d36be87a467f9796ee47 [file] [log] [blame]
/*
* Copyright 2020 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.macro
import android.content.Intent
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
/**
* Provides access to common operations in app automation, such as killing the app,
* or navigating home.
*/
public class MacrobenchmarkScope(
private val packageName: String
) {
private val instrumentation = InstrumentationRegistry.getInstrumentation()
private val context = instrumentation.context
private val device = UiDevice.getInstance(instrumentation)
fun launchPackageAndWait(block: (Intent) -> Unit) {
val intent = context.packageManager.getLaunchIntentForPackage(packageName)!!
block(intent)
context.startActivity(intent)
device.wait(
Until.hasObject(By.pkg(packageName).depth(0)),
5000 /* ms */
)
}
fun pressHome(delayDurationMs: Long = 300) {
device.pressHome()
Thread.sleep(delayDurationMs)
}
fun killProcess() {
device.executeShellCommand("am force-stop $packageName")
}
}
data class MacrobenchmarkConfig(
val packageName: String,
val metrics: List<Metric>,
val compilationMode: CompilationMode = CompilationMode.SpeedProfile(),
val killProcessEachIteration: Boolean = false,
val iterations: Int
)
/**
* Primary macrobenchmark test entrypoint.
*
* TODO: wrap in a JUnit4 rule, which defines [benchmarkName] based on test name
*/
fun macrobenchmark(
benchmarkName: String,
config: MacrobenchmarkConfig,
block: MacrobenchmarkScope.() -> Unit
) = withPermissiveSeLinuxPolicy {
val scope = MacrobenchmarkScope(config.packageName)
// always kill the process at beginning of test
scope.killProcess()
config.compilationMode.compile(config.packageName) {
block(scope)
}
// Perfetto collector is separate from metrics, so we can control file
// output, and give it different (test-wide) lifecycle
val perfettoCollector = PerfettoCaptureWrapper()
try {
perfettoCollector.start()
config.metrics.forEach {
it.start()
}
repeat(config.iterations) {
if (config.killProcessEachIteration) {
scope.killProcess()
}
block(scope)
}
config.metrics.forEach {
it.stop()
}
config.metrics.map {
it.collector
}.report()
} finally {
perfettoCollector.stop("$benchmarkName.trace")
scope.killProcess()
}
}
internal fun CompilationMode.compile(packageName: String, block: () -> Unit) {
if (this == CompilationMode.None) {
return // nothing to do
}
if (this is CompilationMode.SpeedProfile) {
// TODO: clear existing profiling state
repeat(this.warmupIterations) {
block()
}
}
// TODO: merge in below method
compilationFilter(
InstrumentationRegistry.getInstrumentation(),
packageName,
compileArgument()
)
}