From a431dcdfbf4d44cb432007a7889b7ee01818709d Mon Sep 17 00:00:00 2001 From: xfy Date: Mon, 25 May 2026 16:19:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20trace=20=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E7=B1=BB=E5=9E=8B=20+=20=E5=A2=9E=E5=BC=BA=E6=80=A7?= =?UTF-8?q?=E8=83=BD=E8=BF=BD=E8=B8=AA=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ComposeTrace 改用 BuildConfig.ENABLE_TRACE 控制,release 关闭,debug/trace 开启 - core/app 添加 trace buildType:release 优化(R8 + shrink resources)+ 保留 trace 标记 - CalendarMonthView/WeekPager 添加更多自定义 trace marker,覆盖年月视图切换路径 - profile.sh 增强: - 添加 --trace 参数支持 trace 构建 - Perfetto 配置增加 gpu.memory 和 surfaceflinger.frametimeline 数据源 - 报告自动提取帧率百分位、jank 比例、内存摘要 - 添加年月视图切换专项分析指南和基线对比方法 Co-Authored-By: Claude Opus 4.7 (1M context) --- app/build.gradle.kts | 6 + core/build.gradle.kts | 15 ++ .../kotlin/plus/rua/project/ComposeTrace.kt | 6 +- .../plus/rua/project/ui/CalendarMonthView.kt | 2 + .../kotlin/plus/rua/project/ui/WeekPager.kt | 4 + scripts/profile.sh | 131 ++++++++++++++++-- 6 files changed, 146 insertions(+), 18 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b6bbfa1..f876a95 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -42,6 +42,12 @@ android { ) signingConfig = signingConfigs.getByName("debug") } + // trace 构建类型:release 优化 + trace 标记保留,用于性能分析 + create("trace") { + initWith(buildTypes.getByName("release")) + signingConfig = signingConfigs.getByName("debug") + matchingFallbacks += listOf("release") + } // benchmark 构建类型供 macrobenchmark 模块使用 create("benchmark") { initWith(buildTypes.getByName("release")) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2387cc1..3dd7307 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -14,6 +14,21 @@ android { consumerProguardFiles("proguard-rules.pro") } + buildTypes { + debug { + buildConfigField("boolean", "ENABLE_TRACE", "true") + } + release { + isMinifyEnabled = false + consumerProguardFiles("proguard-rules.pro") + buildConfigField("boolean", "ENABLE_TRACE", "false") + } + create("trace") { + initWith(buildTypes.getByName("release")) + buildConfigField("boolean", "ENABLE_TRACE", "true") + } + } + buildFeatures { compose = true buildConfig = true diff --git a/core/src/main/kotlin/plus/rua/project/ComposeTrace.kt b/core/src/main/kotlin/plus/rua/project/ComposeTrace.kt index c9bbfd0..42c21f5 100644 --- a/core/src/main/kotlin/plus/rua/project/ComposeTrace.kt +++ b/core/src/main/kotlin/plus/rua/project/ComposeTrace.kt @@ -5,10 +5,10 @@ import plus.rua.project.shared.BuildConfig /** * Systrace 包装,用于录制 Compose 性能 trace。 - * 仅在 debug 构建中启用,release 构建中为空操作。 + * 由 [BuildConfig.ENABLE_TRACE] 控制开关,release 构建默认关闭,trace 构建开启。 */ fun composeTraceBeginSection(name: String) { - if (!BuildConfig.DEBUG) return + if (!BuildConfig.ENABLE_TRACE) return try { Trace.beginSection(name) } catch (_: RuntimeException) { @@ -17,7 +17,7 @@ fun composeTraceBeginSection(name: String) { } fun composeTraceEndSection() { - if (!BuildConfig.DEBUG) return + if (!BuildConfig.ENABLE_TRACE) return try { Trace.endSection() } catch (_: RuntimeException) { diff --git a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt index 656e815..2c6bbc2 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt @@ -187,6 +187,7 @@ fun CalendarMonthView( ) { yearViewActive -> if (!yearViewActive) { composeTraceBeginSection("MonthView:Compose") + composeTraceBeginSection("CalendarPagerArea") val layoutReady = rowHeightPx > 0 Box( modifier = Modifier @@ -255,6 +256,7 @@ fun CalendarMonthView( } } composeTraceEndSection() + composeTraceEndSection() } else { composeTraceBeginSection("YearView:Compose") Column( diff --git a/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt b/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt index 23eeab3..602e402 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/WeekPager.kt @@ -21,6 +21,8 @@ import kotlinx.datetime.LocalDate import kotlinx.datetime.daysUntil import kotlinx.datetime.plus import plus.rua.project.ShiftKind +import plus.rua.project.composeTraceBeginSection +import plus.rua.project.composeTraceEndSection import kotlin.math.abs @@ -74,6 +76,7 @@ fun WeekPager( flingBehavior = PagerDefaults.flingBehavior(state = pagerState), modifier = modifier ) { page -> + composeTraceBeginSection("WeekPager:Page") val pageOffset = abs(pagerState.currentPageOffsetFraction) val isCurrentPage = page == pagerState.currentPage val alpha = if (isCurrentPage) { @@ -104,5 +107,6 @@ fun WeekPager( ) } } + composeTraceEndSection() } } \ No newline at end of file diff --git a/scripts/profile.sh b/scripts/profile.sh index 13451e5..ecd3b4d 100755 --- a/scripts/profile.sh +++ b/scripts/profile.sh @@ -7,6 +7,7 @@ # ./scripts/profile.sh # 默认抓取 8 秒 # ./scripts/profile.sh 15 # 抓取 15 秒 # ./scripts/profile.sh --no-launch # 不自动启动应用(应用已在运行) +# ./scripts/profile.sh --trace # 使用 trace 构建类型(保留自定义 trace 标记) # set -euo pipefail @@ -19,18 +20,23 @@ LOGS_DIR="${PROJECT_ROOT}/logs" # 解析参数 DURATION_SEC=8 NO_LAUNCH=false +USE_TRACE_BUILD=false for arg in "$@"; do case "$arg" in --no-launch) NO_LAUNCH=true ;; + --trace) + USE_TRACE_BUILD=true + ;; --help|-h) - echo "用法: $0 [秒数] [--no-launch]" + echo "用法: $0 [秒数] [--no-launch] [--trace]" echo "" echo "选项:" echo " 秒数 抓取时长(默认 8 秒)" echo " --no-launch 不自动启动应用" + echo " --trace 使用 trace 构建(release 优化 + 保留 trace 标记)" echo " --help 显示此帮助" exit 0 ;; @@ -47,6 +53,7 @@ echo "========================================" echo " YaYa 性能追踪" echo " 包名: ${PACKAGE}" echo " 时长: ${DURATION_SEC}s" +echo " 构建: $([ "$USE_TRACE_BUILD" = true ] && echo "trace (release + trace)" || echo "debug")" echo " 输出: ${LOGS_DIR}/" echo "========================================" @@ -72,6 +79,9 @@ fi # 检查应用是否已安装 if ! adb shell pm list packages | grep -q "${PACKAGE}"; then echo "错误: 应用 ${PACKAGE} 未安装。请先运行 ./gradlew :app:installDebug" + if [ "$USE_TRACE_BUILD" = true ]; then + echo " 或使用 ./gradlew :app:installTrace 安装 trace 构建" + fi exit 1 fi @@ -126,6 +136,16 @@ data_sources { } } } +data_sources { + config { + name: "android.gpu.memory" + } +} +data_sources { + config { + name: "android.surfaceflinger.frametimeline" + } +} data_sources { config { name: "linux.process_stats" @@ -171,7 +191,17 @@ REPORT_FILE="${LOGS_DIR}/report_${TIMESTAMP}.md" # 计算帧率相关数据 FRAME_COUNT=$(grep -c "FrameTimeline" "${FRAMESTATS_FILE}" 2>/dev/null || echo "0") -JANK_COUNT=$(grep -c "jank" "${FRAMESTATS_FILE}" 2>/dev/null || echo "0") + +# 从 gfxinfo 提取关键指标 +TOTAL_FRAMES=$(grep "Total frames rendered:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $4}' || echo "N/A") +JANKY_FRAMES=$(grep "Janky frames:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $3}' || echo "N/A") +JANKY_PERCENT=$(grep "Janky frames:" "${FRAMESTATS_FILE}" | tail -1 | grep -oP '\(\K[^)]+' || echo "N/A") +P50=$(grep "50th percentile:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $3}' || echo "N/A") +P90=$(grep "90th percentile:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $3}' || echo "N/A") +P99=$(grep "99th percentile:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $3}' || echo "N/A") +SLOW_UI=$(grep "Number Slow UI thread:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $4}' || echo "N/A") +SLOW_DRAW=$(grep "Number Slow issue draw commands:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $5}' || echo "N/A") +HIGH_INPUT=$(grep "Number High input latency:" "${FRAMESTATS_FILE}" | tail -1 | awk '{print $4}' || echo "N/A") # 获取应用版本 APP_VERSION=$(adb shell dumpsys package "${PACKAGE}" | grep versionName | head -1 | awk '{print $1}' | cut -d= -f2 2>/dev/null || echo "unknown") @@ -180,12 +210,19 @@ APP_VERSION=$(adb shell dumpsys package "${PACKAGE}" | grep versionName | head - DEVICE_MODEL=$(adb shell getprop ro.product.model 2>/dev/null | tr -d '\r') ANDROID_VERSION=$(adb shell getprop ro.build.version.release 2>/dev/null | tr -d '\r') +# 获取内存摘要 +TOTAL_PSS=$(grep "TOTAL PSS:" "${MEMINFO_FILE}" | awk '{print $3}' || echo "N/A") +JAVA_HEAP=$(grep "Java Heap:" "${MEMINFO_FILE}" | head -1 | awk '{print $2}' || echo "N/A") +NATIVE_HEAP=$(grep "Native Heap:" "${MEMINFO_FILE}" | head -1 | awk '{print $2}' || echo "N/A") +GRAPHICS=$(grep "Graphics:" "${MEMINFO_FILE}" | head -1 | awk '{print $2}' || echo "N/A") + cat > "${REPORT_FILE}" < "${REPORT_FILE}" < "${REPORT_FILE}" <