#!/bin/bash # # YaYa 性能追踪脚本 # 使用 Perfetto 抓取应用 trace,保存到 logs/ 目录 # # 用法: # ./scripts/profile.sh # 默认抓取 8 秒 # ./scripts/profile.sh 15 # 抓取 15 秒 # ./scripts/profile.sh --no-launch # 不自动启动应用(应用已在运行) # ./scripts/profile.sh --trace # 使用 trace 构建类型(保留自定义 trace 标记) # set -euo pipefail PACKAGE="plus.rua.project" ACTIVITY="plus.rua.project.MainActivity" PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" 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] [--trace]" echo "" echo "选项:" echo " 秒数 抓取时长(默认 8 秒)" echo " --no-launch 不自动启动应用" echo " --trace 使用 trace 构建(release 优化 + 保留 trace 标记)" echo " --help 显示此帮助" exit 0 ;; [0-9]*) DURATION_SEC="$arg" ;; esac done DURATION_MS=$((DURATION_SEC * 1000)) TIMESTAMP=$(date +%Y%m%d_%H%M%S) echo "========================================" echo " YaYa 性能追踪" echo " 包名: ${PACKAGE}" echo " 时长: ${DURATION_SEC}s" echo " 构建: $([ "$USE_TRACE_BUILD" = true ] && echo "trace (release + trace)" || echo "debug")" echo " 输出: ${LOGS_DIR}/" echo "========================================" # 创建 logs 目录 mkdir -p "${LOGS_DIR}" # 检查 adb if ! command -v adb &>/dev/null; then echo "错误: adb 未找到。请确保 Android SDK 的 platform-tools 在 PATH 中。" exit 1 fi # 检查设备连接 DEVICE_COUNT=$(adb devices | grep -c "device$" || true) if [ "$DEVICE_COUNT" -eq 0 ]; then echo "错误: 没有已连接的 Android 设备。" exit 1 fi if [ "$DEVICE_COUNT" -gt 1 ]; then echo "警告: 检测到多个设备,将使用默认设备。" 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 # 启动应用(如果未禁用) if [ "$NO_LAUNCH" = false ]; then echo "" echo "[1/5] 启动应用..." adb shell am start -n "${PACKAGE}/${ACTIVITY}" >/dev/null 2>&1 || true sleep 2 else echo "" echo "[1/5] 跳过启动 (--no-launch)" fi # 抓取 Perfetto trace echo "" echo "[2/5] 抓取 Perfetto trace (${DURATION_SEC}s)..." echo " 请在设备上操作应用,trace 正在记录..." TRACE_FILE="/data/misc/perfetto-traces/yaya_${TIMESTAMP}.perfetto-trace" LOCAL_TRACE="${LOGS_DIR}/trace_${TIMESTAMP}.perfetto-trace" LOCAL_CONFIG="${LOGS_DIR}/.perfetto_config_${TIMESTAMP}.txt" DEVICE_CONFIG="/data/misc/perfetto-configs/yaya_config_${TIMESTAMP}.txt" # 生成本地配置文件,然后 push 到设备 cat > "${LOCAL_CONFIG}" < /dev/null rm -f "${LOCAL_CONFIG}" # 运行 perfetto(前台阻塞,直到 duration_ms 结束) adb shell "perfetto --txt -c ${DEVICE_CONFIG} -o ${TRACE_FILE}" # 清理设备上的临时配置文件 adb shell "rm -f ${DEVICE_CONFIG}" # 拉取 trace 文件 echo " 拉取 trace 文件..." adb pull "${TRACE_FILE}" "${LOCAL_TRACE}" adb shell "rm -f ${TRACE_FILE}" || true # 抓取帧统计 echo "" echo "[3/5] 抓取帧统计..." FRAMESTATS_FILE="${LOGS_DIR}/framestats_${TIMESTAMP}.txt" adb shell dumpsys gfxinfo "${PACKAGE}" framestats > "${FRAMESTATS_FILE}" # 抓取内存信息 echo "" echo "[4/5] 抓取内存信息..." MEMINFO_FILE="${LOGS_DIR}/meminfo_${TIMESTAMP}.txt" adb shell dumpsys meminfo "${PACKAGE}" > "${MEMINFO_FILE}" # 生成报告摘要 echo "" echo "[5/5] 生成摘要..." REPORT_FILE="${LOGS_DIR}/report_${TIMESTAMP}.md" # 计算帧率相关数据 FRAME_COUNT=$(grep -c "FrameTimeline" "${FRAMESTATS_FILE}" 2>/dev/null || echo "0") # 从 gfxinfo 提取关键指标(取第一个匹配,即整体统计而非 per-window) TOTAL_FRAMES=$(awk '/Total frames rendered:/{print $4; exit}' "${FRAMESTATS_FILE}") JANKY_FRAMES=$(awk '/Janky frames:/{print $3; exit}' "${FRAMESTATS_FILE}") JANKY_PERCENT=$(awk '/Janky frames:/{start=index($0,"(")+1; end=index($0,")"); print substr($0,start,end-start); exit}' "${FRAMESTATS_FILE}") P50=$(awk '/50th percentile:/{print $3; exit}' "${FRAMESTATS_FILE}") P90=$(awk '/90th percentile:/{print $3; exit}' "${FRAMESTATS_FILE}") P99=$(awk '/99th percentile:/{print $3; exit}' "${FRAMESTATS_FILE}") SLOW_UI=$(awk '/Number Slow UI thread:/{print $NF; exit}' "${FRAMESTATS_FILE}") SLOW_DRAW=$(awk '/Number Slow issue draw commands:/{print $NF; exit}' "${FRAMESTATS_FILE}") HIGH_INPUT=$(awk '/Number High input latency:/{print $NF; exit}' "${FRAMESTATS_FILE}") # 获取应用版本 APP_VERSION=$(adb shell dumpsys package "${PACKAGE}" | grep versionName | head -1 | awk '{print $1}' | cut -d= -f2 2>/dev/null || echo "unknown") # 获取设备信息 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') # 获取内存摘要($NF 取最后一个字段,避免中间空格导致的列错位) TOTAL_PSS=$(awk '/TOTAL PSS:/{print $3; exit}' "${MEMINFO_FILE}") JAVA_HEAP=$(awk '/^ *Java Heap:/{print $3; exit}' "${MEMINFO_FILE}") NATIVE_HEAP=$(awk '/^ *Native Heap:/{print $3; exit}' "${MEMINFO_FILE}") GRAPHICS=$(awk '/^ *Graphics:/{print $2; exit}' "${MEMINFO_FILE}") cat > "${REPORT_FILE}" <