build(benchmark): 同时复制 Baseline Profile 与 Startup Profile 到 :core

This commit is contained in:
xfy 2026-06-16 09:36:18 +08:00
parent bcc59ca7a0
commit 6f4fa68f0d

View File

@ -42,53 +42,83 @@ dependencies {
implementation(libs.androidx.test.uiautomator) implementation(libs.androidx.test.uiautomator)
} }
// ===== Baseline Profile 自动复制 ===== // ===== Baseline Profile / Startup Profile 自动复制 =====
// 运行 ./gradlew :macrobenchmark:updateBaselineProfile 即可一键生成并复制 // 运行 ./gradlew :macrobenchmark:updateBaselineProfile 即可一键生成并复制
val updateBaselineProfile by tasks.registering { val updateBaselineProfile by tasks.registering {
group = "benchmark" group = "benchmark"
description = "运行 connectedBenchmarkAndroidTest 并将生成的 startup-prof.txt 复制到 :core 模块" description = "运行 connectedBenchmarkAndroidTest 并将生成的 Baseline Profile 与 Startup Profile 复制到 :core 模块"
// 依赖基准测试 task需要先连接设备/模拟器) // 依赖基准测试 task需要先连接设备/模拟器)
dependsOn("connectedBenchmarkAndroidTest") dependsOn("connectedBenchmarkAndroidTest")
// 该 task 的输入是 benchmark 运行后的产物,因此不应被跳过
outputs.upToDateWhen { false }
// 预先计算目标路径,避免在 doLast 中引用 project 对象configuration cache 兼容) // 预先计算目标路径,避免在 doLast 中引用 project 对象configuration cache 兼容)
val targetPath = rootProject.projectDir.resolve("core/src/main/baseline-prof.txt").absolutePath val baselineTargetPath = rootProject.projectDir
.resolve("core/src/main/baseline-prof.txt")
.absolutePath
val startupTargetDirPath = rootProject.projectDir
.resolve("core/src/main/baselineProfiles")
.absolutePath
val buildDirPath = layout.buildDirectory.get().asFile.absolutePath val buildDirPath = layout.buildDirectory.get().asFile.absolutePath
doLast { doLast {
// 寻找生成的 profile 文件benchmark 1.4+ 文件名格式:{Class}_{Method}-startup-prof.txt
val sourcePaths = listOf( val sourcePaths = listOf(
"$buildDirPath/outputs/connected_android_test_additional_output/benchmark/", "$buildDirPath/outputs/connected_android_test_additional_output/benchmark/",
"$buildDirPath/outputs/connected_android_test_additional_output/", "$buildDirPath/outputs/connected_android_test_additional_output/",
) )
val targetFile = File(targetPath) // benchmark 1.4+ 文件名格式:{Class}_{Method}-baseline-prof.txt / {Class}_{Method}-startup-prof.txt
var copied = false // 排除带时间戳的历史文件(如 ...-2026-06-15-startup-prof.txt只取当前 canonical 文件
for (path in sourcePaths) { val dateStampRegex = Regex("-\\d{4}-\\d{2}-\\d{2}-")
fun findNewestProfile(suffix: String): File? {
val candidates = sourcePaths.flatMap { path ->
val dir = File(path) val dir = File(path)
if (!dir.exists()) continue if (!dir.exists()) emptyList()
else dir.walkTopDown().filter {
// 优先匹配不带时间戳的 startup-prof.txtbenchmark 1.4+ 格式) it.isFile &&
val profileFile = dir.walkTopDown() it.name.endsWith(suffix) &&
.firstOrNull { it.name.endsWith("-startup-prof.txt") && !it.name.contains(Regex("-\\d{4}-\\d{2}-\\d{2}-")) } !it.name.contains(dateStampRegex)
?: continue }.toList()
}
profileFile.copyTo(targetFile, overwrite = true) return candidates
println("✅ Baseline Profile 已自动复制到: ${targetFile.absolutePath}") .sortedWith(compareByDescending<File> { it.lastModified() }.thenBy { it.absolutePath })
println(" 来源: ${profileFile.absolutePath}") .firstOrNull()
copied = true
break
} }
if (!copied) { fun requireProfile(suffix: String, label: String): File {
throw GradleException( val sourceFile = findNewestProfile(suffix)
"未找到生成的 *-startup-prof.txt。\n" + ?: throw GradleException(
"未找到生成的 *$suffix。\n" +
"请确认:\n" + "请确认:\n" +
" 1. 设备/模拟器已连接 (adb devices)\n" + " 1. 设备/模拟器已连接 (adb devices)\n" +
" 2. 应用已安装在 benchmark 构建类型下\n" + " 2. 应用已安装在 benchmark 构建类型下\n" +
" 3. 检查 macrobenchmark/build/outputs/ 下是否有输出" " 3. 检查 macrobenchmark/build/outputs/ 下是否有输出"
) )
if (sourceFile.length() == 0L) {
throw GradleException("生成的 $label 文件为空: ${sourceFile.absolutePath}")
} }
return sourceFile
}
// 1) 先定位并校验两份源文件,确保都可用再开始复制,避免部分覆盖目标文件
val baselineSource = requireProfile("-baseline-prof.txt", "Baseline Profile")
val startupSource = requireProfile("-startup-prof.txt", "Startup Profile")
// 2) Baseline Profile → AOT 编译优化
val baselineTargetFile = File(baselineTargetPath)
baselineSource.copyTo(baselineTargetFile, overwrite = true)
logger.lifecycle("✅ Baseline Profile 已自动复制到: ${baselineTargetFile.absolutePath}")
logger.lifecycle(" 来源: ${baselineSource.absolutePath}")
// 3) Startup Profile → DEX layout 优化(必须放在 baselineProfiles/startup-prof.txt
val startupTargetDir = File(startupTargetDirPath)
startupTargetDir.mkdirs()
val startupTargetFile = File(startupTargetDir, "startup-prof.txt")
startupSource.copyTo(startupTargetFile, overwrite = true)
logger.lifecycle("✅ Startup Profile 已自动复制到: ${startupTargetFile.absolutePath}")
logger.lifecycle(" 来源: ${startupSource.absolutePath}")
} }
} }