Source added

This commit is contained in:
Fr4nz D13trich 2025-11-20 09:26:33 +01:00
parent b2864b500e
commit ba28ca859e
8352 changed files with 1487182 additions and 1 deletions

1
benchmark/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,83 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.api.dsl.ManagedVirtualDevice
import org.gradle.api.JavaVersion
import org.gradle.kotlin.dsl.extra
val benchmarkLibs = the<org.gradle.accessors.dm.LibrariesForBenchmarkLibs>()
val signalBuildToolsVersion: String by rootProject.extra
val signalCompileSdkVersion: String by rootProject.extra
val signalTargetSdkVersion: Int by rootProject.extra
val signalMinSdkVersion: Int by rootProject.extra
val signalJavaVersion: JavaVersion by rootProject.extra
val signalKotlinJvmTarget: String by rootProject.extra
plugins {
id("com.android.test")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "org.signal.benchmark"
compileSdkVersion = signalCompileSdkVersion
compileOptions {
sourceCompatibility = signalJavaVersion
targetCompatibility = signalJavaVersion
}
kotlinOptions {
jvmTarget = signalKotlinJvmTarget
}
defaultConfig {
minSdk = 23
targetSdk = signalTargetSdkVersion
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
missingDimensionStrategy("environment", "prod")
missingDimensionStrategy("distribution", "play")
}
buildTypes {
create("benchmark") {
isDebuggable = true
signingConfig = getByName("debug").signingConfig
matchingFallbacks += listOf("perf", "debug")
}
}
targetProjectPath = ":Signal-Android"
experimentalProperties["android.experimental.self-instrumenting"] = true
testOptions {
managedDevices {
devices {
create("api31", ManagedVirtualDevice::class) {
device = "Pixel 6"
apiLevel = 31
systemImageSource = "aosp"
require64Bit = false
}
}
}
}
}
dependencies {
implementation(benchmarkLibs.androidx.test.ext.junit)
implementation(benchmarkLibs.espresso.core)
implementation(benchmarkLibs.uiautomator)
implementation(benchmarkLibs.androidx.benchmark.macro)
}
androidComponents {
beforeVariants(selector().all()) {
if (it.buildType != "benchmark") {
it.enable = false
}
}
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<package android:name="org.thoughtcrime.securesms" />
</queries>
</manifest>

View file

@ -0,0 +1,41 @@
@file:OptIn(ExperimentalBaselineProfilesApi::class)
package org.thoughtcrime.benchmark
import androidx.benchmark.macro.ExperimentalBaselineProfilesApi
import androidx.benchmark.macro.junit4.BaselineProfileRule
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Rule
import org.junit.Test
/**
* WARNING! THIS WILL WIPE YOUR SIGNAL INSTALL
*
* Test that generates a Baseline profile from a user journey. Our journey is:
* - start the app
* - open a conversation
*/
@OptIn(ExperimentalBaselineProfilesApi::class)
class BaselineProfileGenerator {
@get:Rule
val baselineProfileRule = BaselineProfileRule()
@Test
fun startup() {
var setup = false
baselineProfileRule.collectBaselineProfile(
packageName = "org.thoughtcrime.securesms",
profileBlock = {
if (!setup) {
BenchmarkSetup.setup("cold-start", device)
setup = true
}
startActivityAndWait()
device.findObject(By.textContains("Buddy")).click();
device.wait(Until.hasObject(By.textContains("Signal message")), 10_000L)
device.wait(Until.hasObject(By.textContains("Test")), 5_000L)
}
)
}
}

View file

@ -0,0 +1,12 @@
package org.thoughtcrime.benchmark
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
object BenchmarkSetup {
fun setup(type: String, device: UiDevice) {
device.executeShellCommand("am start -W -n org.thoughtcrime.securesms/org.signal.benchmark.BenchmarkSetupActivity --es setup-type $type")
device.wait(Until.hasObject(By.textContains("done")), 25_000L)
}
}

View file

@ -0,0 +1,54 @@
package org.thoughtcrime.benchmark
import android.Manifest
import android.os.Build
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.ExperimentalMetricApi
import androidx.benchmark.macro.TraceSectionMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ConversationBenchmarks {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@OptIn(ExperimentalMetricApi::class)
@Test
fun simpleConversationOpen() {
var setup = false
benchmarkRule.measureRepeated(
packageName = "org.thoughtcrime.securesms",
metrics = listOf(
TraceSectionMetric("6-ConversationOpen"),
TraceSectionMetric("1-ConversationOpen-ViewModel-Init"),
TraceSectionMetric("2-ConversationOpen-Metadata-Loaded"),
TraceSectionMetric("3-ConversationOpen-Data-Loaded"),
TraceSectionMetric("4-ConversationOpen-Data-Posted"),
TraceSectionMetric("5-ConversationOpen-Render"),
),
iterations = 10,
compilationMode = CompilationMode.Partial(),
setupBlock = {
if (!setup) {
BenchmarkSetup.setup("conversation-open", device)
setup = true
}
killProcess()
if (Build.VERSION.SDK_INT >= 33) {
device.executeShellCommand("pm grant $packageName ${Manifest.permission.POST_NOTIFICATIONS}")
}
startActivityAndWait()
device.waitForIdle()
}) {
device.findObject(By.textContains("Buddy")).click()
device.wait(Until.hasObject(By.textContains("Signal message")), 10_000L)
device.wait(Until.hasObject(By.textContains("Test")), 5_000L)
}
}
}

View file

@ -0,0 +1,57 @@
package org.thoughtcrime.benchmark
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.ExperimentalMetricApi
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.TraceSectionMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Macrobenchmark benchmarks for app startup performance.
*
* WARNING! THIS WILL WIPE YOUR SIGNAL INSTALL
*/
@RunWith(AndroidJUnit4::class)
class StartupBenchmarks {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun coldStartNone() {
measureStartup(5, CompilationMode.None())
}
@Test
fun coldStartBaselineProfile() {
measureStartup(5, CompilationMode.Partial())
}
@OptIn(ExperimentalMetricApi::class)
private fun measureStartup(iterations: Int, compilationMode: CompilationMode) {
var setup = false
benchmarkRule.measureRepeated(
packageName = "org.thoughtcrime.securesms",
metrics = listOf(StartupTimingMetric(), TraceSectionMetric("ConversationListDataSource#load")),
iterations = iterations,
startupMode = StartupMode.COLD,
compilationMode = compilationMode,
setupBlock = {
if (!setup) {
BenchmarkSetup.setup("cold-start", device)
killProcess()
dropKernelPageCache()
setup = true
}
}
) {
pressHome()
startActivityAndWait()
}
}
}