From ee8282b80de41079b9b05dcd2707087bad2ce03d Mon Sep 17 00:00:00 2001 From: James Rich Date: Wed, 3 Jun 2026 14:56:37 -0500 Subject: [PATCH 1/2] perf: add Baseline Profile generation for :androidApp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a :baselineProfile macrobenchmark module that produces a Baseline Profile for the app's cold-start path, plus a StartupBenchmark to quantify the win. Wire the androidx.baselineprofile plugin and profileinstaller into :androidApp so release builds ship and honor the profile. Generation needs a device/emulator, so it is automated in the existing scheduled-updates workflow (raised to a 6h cadence to absorb the ~10 min emulator step) and folded into the PR that workflow already opens. Notes for reviewers: - Profile output (androidApp/src/google/generated/baselineProfiles/) is not committed yet — the scheduled workflow produces it on first run. - Pinned to the google flavor; f-droid inherits only library-bundled profiles. - benchmark/baselineprofile kept on the 1.5.0-alpha track for AGP 9.x compatibility (stable 1.4.x predates AGP 9 support). - AGP 9 required dropping the catalog version on com.android.test and not applying kotlin.android in the test module (Kotlin is now bundled). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/scheduled-updates.yml | 57 ++++++++++++++- androidApp/build.gradle.kts | 8 +++ baselineProfile/README.md | 32 +++++++++ baselineProfile/build.gradle.kts | 64 +++++++++++++++++ .../BaselineProfileGenerator.kt | 66 +++++++++++++++++ .../baselineprofile/StartupBenchmark.kt | 70 +++++++++++++++++++ gradle/libs.versions.toml | 15 ++++ settings.gradle.kts | 1 + 8 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 baselineProfile/README.md create mode 100644 baselineProfile/build.gradle.kts create mode 100644 baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt create mode 100644 baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt diff --git a/.github/workflows/scheduled-updates.yml b/.github/workflows/scheduled-updates.yml index 63e1b9f5b5..7588cf886c 100644 --- a/.github/workflows/scheduled-updates.yml +++ b/.github/workflows/scheduled-updates.yml @@ -2,7 +2,7 @@ name: Scheduled Updates (Firmware, Hardware, Translations) on: schedule: - - cron: '0 */4 * * *' # Run every 4 hours (was hourly — reduced to cut cascade CI cost) + - cron: '0 */6 * * *' # Run every 6 hours (raised from 4h to absorb the added baseline-profile step) workflow_dispatch: # Allow manual triggering jobs: @@ -111,6 +111,45 @@ jobs: run: ./gradlew graphUpdate continue-on-error: true + # ── Baseline Profile regeneration ─────────────────────────────────── + # Runs on every scheduled tick (and manual dispatch). Generation needs a booted emulator + # (~10 min); continue-on-error keeps flakiness from blocking the firmware/translation PR. + - name: Enable KVM (for the emulator) + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \ + | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Generate Baseline Profile + id: generate_baseline + continue-on-error: true # Emulator flakiness must not block the firmware/translation PR. + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 34 + target: google_apis # google flavor needs GMS (Maps) on the device image + arch: x86_64 + profile: pixel_6 + disable-animations: true + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + # Writes androidApp/src/google/generated/baselineProfiles/ via the androidx.baselineprofile plugin. + script: ./gradlew :androidApp:generateGoogleReleaseBaselineProfile -Pci=true + + - name: Detect baseline profile changes + id: baseline + run: | + profile_dir="androidApp/src/google/generated/baselineProfiles" + outcome="${{ steps.generate_baseline.outcome }}" + if [ "$outcome" = "skipped" ]; then + echo "status=skipped" >> "$GITHUB_OUTPUT" + elif [ "$outcome" != "success" ]; then + echo "::warning::Baseline profile generation failed (outcome: $outcome). Skipping." + echo "status=error" >> "$GITHUB_OUTPUT" + elif [ -n "$(git status --porcelain "$profile_dir" 2>/dev/null)" ]; then + echo "status=updated" >> "$GITHUB_OUTPUT" + else + echo "status=unchanged" >> "$GITHUB_OUTPUT" + fi - name: Build PR body id: pr_body @@ -119,6 +158,7 @@ jobs: firmware_detail="${{ steps.firmware.outputs.detail }}" hardware_status="${{ steps.hardware.outputs.status }}" hardware_detail="${{ steps.hardware.outputs.detail }}" + baseline_status="${{ steps.baseline.outputs.status }}" body="This PR includes automated updates from the scheduled workflow:" body+=$'\n' @@ -139,6 +179,15 @@ jobs: *) body+=$'\n'"- ❓ \`device_hardware.json\` — unknown status." ;; esac + # Baseline profile (daily / manual only) + case "$baseline_status" in + updated) body+=$'\n'"- ✅ \`androidApp\` baseline profile regenerated on an emulator." ;; + unchanged) body+=$'\n'"- ✔️ \`androidApp\` baseline profile regenerated — no changes detected." ;; + error) body+=$'\n'"- ⚠️ \`androidApp\` baseline profile generation failed — skipped (see workflow logs)." ;; + skipped) ;; # Not a daily/manual run — omit the line entirely. + *) ;; + esac + # Crowdin & graphs (always attempted) body+=$'\n'"- Source strings were uploaded to Crowdin." body+=$'\n'"- Latest translations were downloaded from Crowdin (if available)." @@ -158,7 +207,7 @@ jobs: with: token: ${{ secrets.CROWDIN_GITHUB_TOKEN }} commit-message: | - chore: Scheduled updates (Firmware, Hardware, Translations, Graphs) + chore: Scheduled updates (Firmware, Hardware, Translations, Graphs, Baseline) Automated updates for: - Firmware releases list @@ -166,7 +215,8 @@ jobs: - Crowdin source string uploads - Crowdin translation downloads - Module dependency graphs - title: 'chore: Scheduled updates (Firmware, Hardware, Translations, Graphs)' + - androidApp baseline profile + title: 'chore: Scheduled updates (Firmware, Hardware, Translations, Graphs, Baseline)' body: ${{ steps.pr_body.outputs.content }} branch: 'scheduled-updates' base: 'main' @@ -174,6 +224,7 @@ jobs: add-paths: | androidApp/src/main/assets/firmware_releases.json androidApp/src/main/assets/device_hardware.json + androidApp/src/google/generated/baselineProfiles/** fastlane/metadata/android/** **/strings.xml **/README.md diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index bc3697bf8e..a101f628dc 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -30,6 +30,7 @@ plugins { id("meshtastic.koin") alias(libs.plugins.kotlin.parcelize) alias(libs.plugins.secrets) + alias(libs.plugins.androidx.baselineprofile) id("meshtastic.aboutlibraries") id("dev.mokkery") } @@ -250,6 +251,9 @@ dependencies { implementation(libs.coil.network.ktor3) implementation(libs.coil.svg) implementation(libs.androidx.core.splashscreen) + // Installs the baseline profile produced by :baselineProfile at app startup (API < 31) + // and lets ART honor it on first launch. On API 31+ the platform installs it automatically. + implementation(libs.androidx.profileinstaller) implementation(libs.kotlinx.serialization.json) implementation(libs.usb.serial.android) implementation(libs.androidx.work.runtime.ktx) @@ -297,4 +301,8 @@ dependencies { testImplementation(libs.compose.multiplatform.ui.test) testImplementation(libs.androidx.test.ext.junit) testImplementation(libs.androidx.glance.appwidget) + + // Producer of the baseline profile consumed by the release build. The androidx.baselineprofile + // plugin merges the generated rules into src//generated/baselineProfiles at build time. + baselineProfile(projects.baselineProfile) } diff --git a/baselineProfile/README.md b/baselineProfile/README.md new file mode 100644 index 0000000000..bd87b405b3 --- /dev/null +++ b/baselineProfile/README.md @@ -0,0 +1,32 @@ +# `:baselineProfile` + +Generates a [Baseline Profile](https://developer.android.com/topic/performance/baselineprofiles/overview) +for `:androidApp` — AOT-compiling the cold-start and first-frame code paths so ART doesn't pay the +JIT cost on first launch. Targets the **google** flavor (the variant most users run). + +## Generate the profile (run on a device/emulator) + +```bash +./gradlew :androidApp:generateGoogleReleaseBaselineProfile +``` + +Output is merged into `androidApp/src/google/generated/baselineProfiles/baseline-prof.txt`. +**Commit that file** — release builds package it via `androidx.profileinstaller`. + +## Quantify the win + +```bash +./gradlew :androidApp:benchmarkGoogleReleaseBaselineProfile +``` + +Compare `startupCompilationNone` vs `startupCompilationBaselineProfiles` in the output. + +## Scope / TODO + +- The journey (`BaselineProfileGenerator`) is cold-start only, since CI has no paired radio. + Extend it with post-connection screens (node list, map, message thread) once a fake transport or + connected device is wired into the harness — a more representative journey yields a better profile. +- For hermetic CI generation, swap `useConnectedDevices = true` in `build.gradle.kts` for a + [Gradle Managed Device](https://developer.android.com/topic/performance/baselineprofiles/measure-baselineprofile#gradle-managed). +- f-droid currently inherits no profile (only `google` is produced). Add a second flavor here if + the f-droid startup path ever diverges enough to matter. diff --git a/baselineProfile/build.gradle.kts b/baselineProfile/build.gradle.kts new file mode 100644 index 0000000000..c2cb86d866 --- /dev/null +++ b/baselineProfile/build.gradle.kts @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.android.test) + alias(libs.plugins.androidx.baselineprofile) +} + +android { + namespace = "org.meshtastic.baselineprofile" + compileSdk = 37 + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + + defaultConfig { + // Macrobenchmark / BaselineProfileRule require API 28+ on the test (device) side. + // The generated profile is still installed on the app's real minSdk (26) via profileinstaller. + minSdk = 28 + targetSdk = 37 + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + // App module whose startup we profile/benchmark. + targetProjectPath = ":androidApp" + + // The app declares a `marketplace` flavor dimension (google / fdroid). A test module must + // match it. We pin to `google` — the variant the vast majority of users run (and the one with + // Maps). f-droid can reuse the same profile; wire a second flavor here if it ever diverges. + flavorDimensions += "marketplace" + productFlavors { create("google") { dimension = "marketplace" } } +} + +kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_21) } } + +baselineProfile { + // Generate on an attached device/emulator. For hermetic CI, replace with a Gradle Managed + // Device (see README.md) and set managedDevices + useConnectedDevices = false. + useConnectedDevices = true +} + +dependencies { + implementation(libs.androidx.test.ext.junit) + implementation(libs.androidx.test.espresso.core) + implementation(libs.androidx.uiautomator) + implementation(libs.androidx.benchmark.macro.junit4) +} diff --git a/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt b/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt new file mode 100644 index 0000000000..7928374083 --- /dev/null +++ b/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2026 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.meshtastic.baselineprofile + +import androidx.benchmark.macro.junit4.BaselineProfileRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Generates a Baseline Profile for the app's critical user journey. + * + * Run it with: + * ``` + * ./gradlew :androidApp:generateGoogleReleaseBaselineProfile + * ``` + * + * The [androidx.baselineprofile] plugin on `:androidApp` drives this against the auto-created + * `nonMinifiedRelease` variant and merges the result into + * `androidApp/src/google/generated/baselineProfiles/`. Commit that output so release builds ship it. + * + * The journey is intentionally minimal (cold start → first frame) because CI has no paired radio. + * Extend it with post-connection screens (node list, map, message thread) once a fake transport or + * connected device is available in the harness — the more representative the journey, the better the + * profile. + */ +@LargeTest +@RunWith(AndroidJUnit4::class) +class BaselineProfileGenerator { + + @get:Rule val baselineProfileRule = BaselineProfileRule() + + @Test + fun generate() = + baselineProfileRule.collect( + // The plugin injects the target applicationId (handles the google debug/release suffix). + packageName = InstrumentationRegistry.getArguments().getString("targetAppId") ?: DEFAULT_APP_ID, + // Also produce a startup profile (dexlayout hints) for faster cold start, not just AOT rules. + includeInStartupProfile = true, + ) { + pressHome() + startActivityAndWait() + device.waitForIdle() + } + + private companion object { + const val DEFAULT_APP_ID = "com.geeksville.mesh" + } +} diff --git a/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt b/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt new file mode 100644 index 0000000000..b2f3bf43bb --- /dev/null +++ b/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2026 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.meshtastic.baselineprofile + +import androidx.benchmark.macro.BaselineProfileMode +import androidx.benchmark.macro.CompilationMode +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.platform.app.InstrumentationRegistry +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Measures cold-start time with and without the Baseline Profile so the win is quantifiable. + * + * Run it with: + * ``` + * ./gradlew :androidApp:benchmarkGoogleReleaseBaselineProfile + * ``` + * + * Compare `startupCompilationNone` vs `startupCompilationBaselineProfiles` in the output: the delta + * is the startup improvement the shipped profile buys. `Partial(Require)` fails loudly if the + * profile is missing, so this also guards against a release that silently dropped it. + */ +@LargeTest +@RunWith(AndroidJUnit4::class) +class StartupBenchmark { + + @get:Rule val benchmarkRule = MacrobenchmarkRule() + + @Test fun startupCompilationNone() = startup(CompilationMode.None()) + + @Test + fun startupCompilationBaselineProfiles() = + startup(CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require)) + + private fun startup(compilationMode: CompilationMode) = + benchmarkRule.measureRepeated( + packageName = InstrumentationRegistry.getArguments().getString("targetAppId") ?: DEFAULT_APP_ID, + metrics = listOf(StartupTimingMetric()), + compilationMode = compilationMode, + startupMode = StartupMode.COLD, + iterations = 10, + ) { + pressHome() + startActivityAndWait() + } + + private companion object { + const val DEFAULT_APP_ID = "com.geeksville.mesh" + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c60763e45d..3824833b5e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,6 +35,14 @@ turbine = "1.2.1" # Compose Screenshot Testing compose-screenshot = "0.0.1-alpha15" +# Baseline Profiles / Macrobenchmark +# `benchmark` drives both the androidx.benchmark macro lib AND the androidx.baselineprofile +# Gradle plugin (same coordinates/version). Kept on the alpha track to stay compatible with +# AGP 9.x (the stable 1.4.x line predates AGP 9 support). +benchmark = "1.5.0-alpha06" +profileinstaller = "1.4.1" +androidx-uiautomator = "2.3.0" + # Compose Multiplatform compose-multiplatform = "1.11.1" compose-multiplatform-material3 = "1.11.0-alpha07" @@ -138,6 +146,11 @@ androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version = androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version = "2.11.2" } androidx-work-testing = { module = "androidx.work:work-testing", version = "2.11.2" } +# Baseline Profiles / Macrobenchmark +androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "profileinstaller" } +androidx-benchmark-macro-junit4 = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" } +androidx-uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "androidx-uiautomator" } + # AndroidX Compose (explicit versions — BOM removed; CMP is the sole version authority) androidx-compose-runtime-tracing = { module = "androidx.compose.runtime:runtime-tracing", version.ref = "androidx-compose-bom-aligned" } androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "androidx-compose-bom-aligned" } # Required by Robolectric Compose tests (registers ComponentActivity) @@ -291,6 +304,8 @@ takpacket-sdk-jvm = { module = "org.meshtastic:takpacket-sdk-jvm", version.ref = # Android android-application = { id = "com.android.application", version.ref = "agp" } android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } +android-test = { id = "com.android.test" } +androidx-baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" } compose-screenshot = { id = "com.android.compose.screenshot", version.ref = "compose-screenshot" } # Jetbrains diff --git a/settings.gradle.kts b/settings.gradle.kts index 1f6629f922..2dcce0c970 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -133,4 +133,5 @@ include( ":core:barcode", ":feature:widget", ":screenshot-tests", + ":baselineProfile", ) From 5f4448cfff42eadcc9886a49b6be98d96aa57a2c Mon Sep 17 00:00:00 2001 From: James Rich Date: Wed, 3 Jun 2026 15:37:01 -0500 Subject: [PATCH 2/2] fix: rename :baselineProfile module to lowercase :baselineprofile The check-changes path filter and the verify-check-changes-filter drift guard in pull-request.yml were pre-wired for a lowercase `baselineprofile` root. Match that convention so the filter-drift check passes. Co-Authored-By: Claude Opus 4.8 (1M context) --- androidApp/build.gradle.kts | 4 ++-- {baselineProfile => baselineprofile}/README.md | 2 +- {baselineProfile => baselineprofile}/build.gradle.kts | 0 .../meshtastic/baselineprofile/BaselineProfileGenerator.kt | 0 .../kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt | 0 settings.gradle.kts | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) rename {baselineProfile => baselineprofile}/README.md (98%) rename {baselineProfile => baselineprofile}/build.gradle.kts (100%) rename {baselineProfile => baselineprofile}/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt (100%) rename {baselineProfile => baselineprofile}/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt (100%) diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index a101f628dc..d1a693cef3 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -251,7 +251,7 @@ dependencies { implementation(libs.coil.network.ktor3) implementation(libs.coil.svg) implementation(libs.androidx.core.splashscreen) - // Installs the baseline profile produced by :baselineProfile at app startup (API < 31) + // Installs the baseline profile produced by :baselineprofile at app startup (API < 31) // and lets ART honor it on first launch. On API 31+ the platform installs it automatically. implementation(libs.androidx.profileinstaller) implementation(libs.kotlinx.serialization.json) @@ -304,5 +304,5 @@ dependencies { // Producer of the baseline profile consumed by the release build. The androidx.baselineprofile // plugin merges the generated rules into src//generated/baselineProfiles at build time. - baselineProfile(projects.baselineProfile) + baselineProfile(projects.baselineprofile) } diff --git a/baselineProfile/README.md b/baselineprofile/README.md similarity index 98% rename from baselineProfile/README.md rename to baselineprofile/README.md index bd87b405b3..ca3ec581eb 100644 --- a/baselineProfile/README.md +++ b/baselineprofile/README.md @@ -1,4 +1,4 @@ -# `:baselineProfile` +# `:baselineprofile` Generates a [Baseline Profile](https://developer.android.com/topic/performance/baselineprofiles/overview) for `:androidApp` — AOT-compiling the cold-start and first-frame code paths so ART doesn't pay the diff --git a/baselineProfile/build.gradle.kts b/baselineprofile/build.gradle.kts similarity index 100% rename from baselineProfile/build.gradle.kts rename to baselineprofile/build.gradle.kts diff --git a/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt b/baselineprofile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt similarity index 100% rename from baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt rename to baselineprofile/src/main/kotlin/org/meshtastic/baselineprofile/BaselineProfileGenerator.kt diff --git a/baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt b/baselineprofile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt similarity index 100% rename from baselineProfile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt rename to baselineprofile/src/main/kotlin/org/meshtastic/baselineprofile/StartupBenchmark.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 2dcce0c970..f42b5bf673 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -133,5 +133,5 @@ include( ":core:barcode", ":feature:widget", ":screenshot-tests", - ":baselineProfile", + ":baselineprofile", )