feat: Implement baseline profile generation and startup benchmarking

- Added baseline profile generator for Rosetta Messenger to optimize startup performance.
- Created startup benchmark tests to measure cold start times under different compilation modes.
- Introduced a new Gradle module for baseline profile and benchmark tests.
- Updated ChatsListViewModel to show loading skeleton while data is being fetched.
- Improved keyboard handling in MessageInputBar by using SHOW_IMPLICIT instead of SHOW_FORCED.
- Minor code cleanups and optimizations across various components.
This commit is contained in:
k1ngsterr1
2026-02-08 09:21:05 +05:00
parent 8b8c883a63
commit abe1a1a710
13 changed files with 1111 additions and 564 deletions

View File

@@ -0,0 +1,33 @@
plugins {
id("com.android.test")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.rosetta.messenger.baselineprofile"
compileSdk = 34
defaultConfig {
minSdk = 28 // Baseline Profiles require API 28+
targetSdk = 34
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
targetProjectPath = ":app"
}
dependencies {
implementation("androidx.test.ext:junit:1.1.5")
implementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.test.uiautomator:uiautomator:2.2.0")
implementation("androidx.benchmark:benchmark-macro-junit4:1.2.2")
}

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -0,0 +1,66 @@
package com.rosetta.messenger.baselineprofile
import androidx.benchmark.macro.ExperimentalBaselineProfilesApi
import androidx.benchmark.macro.junit4.BaselineProfileRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Baseline Profile Generator для Rosetta Messenger
*
* Запуск:
* ./gradlew :baselineprofile:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.rosetta.messenger.baselineprofile.BaselineProfileGenerator
*
* Результат:
* Профиль будет сгенерирован и сохранён — скопируйте его в app/src/main/baseline-prof.txt
*
* Требования:
* - Эмулятор или устройство API 28+ (лучше userdebug/rooted)
* - Приложение должно быть установлено
*/
@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {
@get:Rule
val baselineProfileRule = BaselineProfileRule()
@Test
fun generateBaselineProfile() = baselineProfileRule.collectBaselineProfile(
packageName = "com.rosetta.messenger"
) {
// 1. Cold start — запуск приложения
pressHome()
startActivityAndWait()
// 2. Ждём загрузки (Splash → Auth/Main)
device.waitForIdle()
Thread.sleep(3000) // Ждём splash + auth flow
// 3. Если попали на экран логина — пропускаем (профиль соберёт auth UI)
// Если попали на список чатов — скроллим
val chatList = device.wait(Until.hasObject(By.scrollable(true)), 5000)
if (chatList) {
// Скролл списка чатов вниз и обратно
val scrollable = device.findObject(By.scrollable(true))
scrollable?.let {
it.scroll(androidx.test.uiautomator.Direction.DOWN, 2.0f)
device.waitForIdle()
Thread.sleep(500)
it.scroll(androidx.test.uiautomator.Direction.UP, 2.0f)
device.waitForIdle()
Thread.sleep(500)
}
}
// 4. Ждём перед завершением
device.waitForIdle()
Thread.sleep(1000)
}
}

View File

@@ -0,0 +1,61 @@
package com.rosetta.messenger.baselineprofile
import androidx.benchmark.macro.CompilationMode
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 androidx.test.filters.LargeTest
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Startup Benchmark для замера холодного старта Rosetta
*
* Запуск:
* ./gradlew :baselineprofile:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.rosetta.messenger.baselineprofile.StartupBenchmark
*
* Сравнивает 3 режима компиляции:
* - None (интерпретатор) — worst case
* - BaselineProfile — с нашими профилями
* - Full (полная AOT) — best case
*/
@RunWith(AndroidJUnit4::class)
@LargeTest
class StartupBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun startupNoCompilation() = startup(CompilationMode.None())
@Test
fun startupBaselineProfile() = startup(CompilationMode.Partial())
@Test
fun startupFullCompilation() = startup(CompilationMode.Full())
private fun startup(compilationMode: CompilationMode) {
benchmarkRule.measureRepeated(
packageName = "com.rosetta.messenger",
metrics = listOf(StartupTimingMetric(), FrameTimingMetric()),
compilationMode = compilationMode,
iterations = 5,
startupMode = StartupMode.COLD,
setupBlock = {
pressHome()
}
) {
startActivityAndWait()
// Ждём появления контента (чат-лист или auth)
device.waitForIdle()
Thread.sleep(2000)
}
}
}