# Perfetto分析Trace提效方案 ## 一、提效概述 ### 1. 提效目标 - **减少分析时间**:从数小时缩短到数十分钟 - **提高分析准确性**:减少人为错误 - **标准化流程**:建立可复用的分析流程 - **自动化分析**:减少重复性工作 - **知识积累**:建立分析模板和案例库 ### 2. 提效策略 1. **工具自动化**:使用脚本和工具自动化重复操作 2. **流程标准化**:建立标准化的分析流程 3. **模板复用**:使用配置模板和分析模板 4. **批量处理**:批量录制和分析Trace 5. **智能分析**:使用SQL和工具进行智能分析 ## 二、工具和脚本自动化 ### 1. 快速录制脚本 #### 1.1 通用录制脚本 **quick_trace.sh:** ```bash #!/bin/bash # 快速录制Trace脚本 # 用法: ./quick_trace.sh [时长] [输出文件] [应用包名] DURATION=${1:-10} OUTPUT=${2:-trace.pb} PACKAGE=${3:-""} echo "开始录制 ${DURATION} 秒的Trace..." if [ -z "$PACKAGE" ]; then adb shell perfetto -c - --out /data/misc/perfetto-traces/trace -t ${DURATION}s else adb shell perfetto -c - --out /data/misc/perfetto-traces/trace \ -a ${PACKAGE} -t ${DURATION}s fi echo "拉取Trace文件..." adb pull /data/misc/perfetto-traces/trace ${OUTPUT} echo "Trace文件已保存为: ${OUTPUT}" echo "可以在 https://ui.perfetto.dev/ 打开分析" ``` **使用方法:** ```bash chmod +x quick_trace.sh # 录制10秒 ./quick_trace.sh 10 trace.pb # 录制指定应用 ./quick_trace.sh 10 startup.pb com.example.app ``` #### 1.2 启动分析脚本 **startup_trace.sh:** ```bash #!/bin/bash # 应用启动分析脚本 # 用法: ./startup_trace.sh [应用包名] [输出文件] PACKAGE=${1:-com.example.app} OUTPUT=${2:-startup_trace.pb} echo "准备录制 ${PACKAGE} 的启动Trace..." echo "请在3秒内启动应用..." sleep 3 echo "开始录制..." adb shell perfetto -c - --out /data/misc/perfetto-traces/trace \ -a ${PACKAGE} -t 10s echo "拉取Trace文件..." adb pull /data/misc/perfetto-traces/trace ${OUTPUT} echo "启动Trace已保存为: ${OUTPUT}" ``` #### 1.3 卡顿分析脚本 **jank_trace.sh:** ```bash #!/bin/bash # 卡顿分析脚本 # 用法: ./jank_trace.sh [时长] [输出文件] [应用包名] DURATION=${1:-30} OUTPUT=${2:-jank_trace.pb} PACKAGE=${3:-""} echo "准备录制卡顿Trace..." echo "请在3秒内复现卡顿问题..." sleep 3 echo "开始录制 ${DURATION} 秒..." if [ -z "$PACKAGE" ]; then adb shell perfetto -c - --out /data/misc/perfetto-traces/trace -t ${DURATION}s else adb shell perfetto -c - --out /data/misc/perfetto-traces/trace \ -a ${PACKAGE} -t ${DURATION}s fi echo "拉取Trace文件..." adb pull /data/misc/perfetto-traces/trace ${OUTPUT} echo "卡顿Trace已保存为: ${OUTPUT}" ``` ### 2. 批量分析脚本 #### 2.1 批量录制脚本 **batch_record.sh:** ```bash #!/bin/bash # 批量录制Trace脚本 # 用法: ./batch_record.sh [次数] [时长] [应用包名] COUNT=${1:-5} DURATION=${2:-10} PACKAGE=${3:-""} echo "批量录制 ${COUNT} 次Trace,每次 ${DURATION} 秒..." for i in $(seq 1 $COUNT); do echo "录制第 ${i} 次Trace..." if [ -z "$PACKAGE" ]; then adb shell perfetto -c - --out /data/misc/perfetto-traces/trace_${i} -t ${DURATION}s else adb shell perfetto -c - --out /data/misc/perfetto-traces/trace_${i} \ -a ${PACKAGE} -t ${DURATION}s fi adb pull /data/misc/perfetto-traces/trace_${i} trace_${i}.pb echo "第 ${i} 次Trace已保存为 trace_${i}.pb" sleep 2 done echo "所有Trace录制完成" ``` #### 2.2 批量拉取脚本 **batch_pull.sh:** ```bash #!/bin/bash # 批量拉取Trace文件 # 用法: ./batch_pull.sh [文件数量] COUNT=${1:-5} OUTPUT_DIR=${2:-traces} mkdir -p ${OUTPUT_DIR} echo "批量拉取 ${COUNT} 个Trace文件..." for i in $(seq 1 $COUNT); do echo "拉取 trace_${i}..." adb pull /data/misc/perfetto-traces/trace_${i} ${OUTPUT_DIR}/trace_${i}.pb 2>/dev/null done echo "所有Trace文件已保存到 ${OUTPUT_DIR}/" ``` ### 3. 自动化分析脚本 #### 3.1 SQL查询脚本 **analyze_trace.py:** ```python #!/usr/bin/env python3 """ Perfetto Trace自动化分析脚本 用法: python analyze_trace.py trace.pb """ import sys import subprocess import json def run_sql_query(trace_file, sql_query): """执行SQL查询""" # 使用perfetto命令行工具执行SQL查询 # 注意:这需要perfetto命令行工具支持SQL查询 cmd = ['perfetto', '--query', sql_query, trace_file] result = subprocess.run(cmd, capture_output=True, text=True) return result.stdout def analyze_startup(trace_file): """分析启动性能""" queries = { 'process_creation': """ SELECT ts, dur / 1000000.0 AS duration_ms FROM slice WHERE name LIKE '%startProcess%' LIMIT 1 """, 'application_init': """ SELECT ts, dur / 1000000.0 AS duration_ms FROM slice WHERE name LIKE '%handleBindApplication%' LIMIT 1 """, 'activity_creation': """ SELECT ts, dur / 1000000.0 AS duration_ms FROM slice WHERE name LIKE '%performLaunchActivity%' LIMIT 1 """, 'first_frame': """ SELECT ts, dur / 1000000.0 AS duration_ms FROM slice WHERE name = 'Choreographer#doFrame' ORDER BY ts LIMIT 1 """ } results = {} for key, query in queries.items(): output = run_sql_query(trace_file, query) results[key] = output return results def analyze_jank(trace_file): """分析卡顿""" query = """ SELECT COUNT(*) AS jank_count, AVG(dur) / 1000000.0 AS avg_duration_ms, MAX(dur) / 1000000.0 AS max_duration_ms FROM slice WHERE name = 'Choreographer#doFrame' AND dur > 16666667 """ return run_sql_query(trace_file, query) def analyze_fps(trace_file): """分析帧率""" query = """ SELECT COUNT(*) * 1000000000.0 / (MAX(ts) - MIN(ts)) AS fps FROM slice WHERE name = 'Choreographer#doFrame' """ return run_sql_query(trace_file, query) if __name__ == '__main__': if len(sys.argv) < 2: print("用法: python analyze_trace.py trace.pb") sys.exit(1) trace_file = sys.argv[1] print("分析启动性能...") startup_results = analyze_startup(trace_file) print(json.dumps(startup_results, indent=2)) print("\n分析卡顿...") jank_results = analyze_jank(trace_file) print(jank_results) print("\n分析帧率...") fps_results = analyze_fps(trace_file) print(fps_results) ``` #### 3.2 报告生成脚本 **generate_report.py:** ```python #!/usr/bin/env python3 """ 生成性能分析报告 用法: python generate_report.py trace.pb report.html """ import sys import json from datetime import datetime def generate_html_report(trace_file, output_file): """生成HTML报告""" html_template = """ Perfetto Trace分析报告

Perfetto Trace分析报告

生成时间: {timestamp}

Trace文件: {trace_file}

性能指标

启动性能

进程创建: {process_creation} ms

Application初始化: {app_init} ms

Activity创建: {activity_creation} ms

首帧渲染: {first_frame} ms

帧率

平均帧率: {fps} FPS

掉帧次数: {jank_count}

平均掉帧时长: {avg_jank_duration} ms

分析建议

""" # 这里应该调用实际的SQL查询获取数据 # 为了示例,使用占位符 report = html_template.format( timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), trace_file=trace_file, process_creation="N/A", app_init="N/A", activity_creation="N/A", first_frame="N/A", fps="N/A", jank_count="N/A", avg_jank_duration="N/A" ) with open(output_file, 'w', encoding='utf-8') as f: f.write(report) print(f"报告已生成: {output_file}") if __name__ == '__main__': if len(sys.argv) < 3: print("用法: python generate_report.py trace.pb report.html") sys.exit(1) trace_file = sys.argv[1] output_file = sys.argv[2] generate_html_report(trace_file, output_file) ``` ## 三、配置模板复用 ### 1. 配置文件模板库 #### 1.1 启动分析配置模板 **templates/startup_config.txt:** ```protobuf buffers: { size_kb: 63488 fill_policy: DISCARD } data_sources: { config { name: "linux.ftrace" ftrace_config { ftrace_events: "sched/sched_switch" ftrace_events: "sched/sched_waking" ftrace_events: "sched/sched_process_exit" ftrace_events: "sched/sched_process_free" ftrace_events: "task/task_newtask" ftrace_events: "task/task_rename" ftrace_events: "power/cpu_frequency" ftrace_events: "power/cpu_idle" ftrace_events: "power/suspend_resume" atrace_categories: "am" atrace_categories: "wm" atrace_categories: "gfx" atrace_categories: "view" atrace_categories: "binder_driver" atrace_categories: "binder_lock" atrace_categories: "input" atrace_categories: "res" atrace_categories: "dalvik" buffer_size_kb: 4096 drain_period_ms: 250 } } } data_sources: { config { name: "android.surfaceflinger.frame" } } duration_ms: 10000 ``` #### 1.2 卡顿分析配置模板 **templates/jank_config.txt:** ```protobuf buffers: { size_kb: 63488 fill_policy: DISCARD } data_sources: { config { name: "linux.ftrace" ftrace_config { ftrace_events: "sched/sched_switch" ftrace_events: "sched/sched_waking" ftrace_events: "power/cpu_frequency" ftrace_events: "power/cpu_idle" ftrace_events: "gfx/mali_gpu_total" ftrace_events: "gpu_mem_total/gpu_mem_total" atrace_categories: "gfx" atrace_categories: "view" atrace_categories: "sched" atrace_categories: "freq" atrace_categories: "idle" buffer_size_kb: 8192 drain_period_ms: 250 } } } data_sources: { config { name: "android.surfaceflinger.frame" } } duration_ms: 30000 ``` ### 2. 模板管理脚本 **use_template.sh:** ```bash #!/bin/bash # 使用配置模板 # 用法: ./use_template.sh [模板名] [输出文件] [时长] TEMPLATE=${1:-startup} OUTPUT=${2:-config.txt} DURATION=${3:-10000} TEMPLATE_DIR="templates" TEMPLATE_FILE="${TEMPLATE_DIR}/${TEMPLATE}_config.txt" if [ ! -f "$TEMPLATE_FILE" ]; then echo "模板文件不存在: $TEMPLATE_FILE" exit 1 fi # 复制模板并替换时长 sed "s/duration_ms: [0-9]*/duration_ms: ${DURATION}/" \ "$TEMPLATE_FILE" > "$OUTPUT" echo "配置已生成: $OUTPUT" ``` ## 四、工作流程优化 ### 1. 标准化分析流程 #### 1.1 启动分析流程 ``` 1. 准备阶段 - 明确分析目标 - 准备测试环境 - 选择配置模板 2. 录制阶段 - 使用启动分析脚本 - 启动应用 - 等待录制完成 3. 分析阶段 - 打开Trace文件 - 定位关键节点 - 分析各阶段耗时 - 识别性能瓶颈 4. 报告阶段 - 记录分析结果 - 生成分析报告 - 提供优化建议 ``` #### 1.2 卡顿分析流程 ``` 1. 准备阶段 - 明确卡顿场景 - 准备复现步骤 - 选择配置模板 2. 录制阶段 - 使用卡顿分析脚本 - 复现卡顿问题 - 等待录制完成 3. 分析阶段 - 打开Trace文件 - 定位卡顿时间点 - 分析主线程状态 - 分析渲染线程状态 - 分析系统资源 4. 报告阶段 - 记录卡顿原因 - 生成分析报告 - 提供优化建议 ``` ### 2. 分析检查清单 #### 2.1 启动分析检查清单 - [ ] 进程创建时间 - [ ] Application初始化时间 - [ ] Activity创建时间 - [ ] 首帧渲染时间 - [ ] 主线程阻塞情况 - [ ] 系统服务调用耗时 - [ ] CPU使用情况 - [ ] 内存使用情况 #### 2.2 卡顿分析检查清单 - [ ] 卡顿时间点定位 - [ ] 帧率统计 - [ ] 主线程状态分析 - [ ] RenderThread状态分析 - [ ] CPU性能分析 - [ ] 内存性能分析 - [ ] GPU性能分析 - [ ] 根本原因定位 ## 五、快捷键和技巧 ### 1. Perfetto Web UI快捷键 | 快捷键 | 功能 | |--------|------| | `W` | 放大时间轴 | | `S` | 缩小时间轴 | | `A` | 向左移动 | | `D` | 向右移动 | | `M` | 添加书签 | | `G` | 跳转到书签 | | `F` | 查找 | | `?` | 显示所有快捷键 | | `Shift + 拖拽` | 选择时间范围 | | `Ctrl + F` | 搜索框 | ### 2. 快速定位技巧 #### 2.1 使用书签 ``` 1. 找到关键时间点 2. 按M键添加书签 3. 给书签命名(如"启动开始"、"首帧") 4. 使用G键快速跳转 ``` #### 2.2 使用时间选择 ``` 1. Shift + 鼠标拖拽选择时间范围 2. 只显示选择范围内的事件 3. 缩小分析范围 4. 提高分析效率 ``` #### 2.3 使用筛选器 ``` 1. 在进程列表中筛选 2. 在线程列表中筛选 3. 使用搜索框筛选事件 4. 只关注相关进程和线程 ``` ### 3. SQL查询模板 #### 3.1 启动时间查询模板 ```sql -- 查询启动各阶段耗时 SELECT 'Process Creation' AS stage, (SELECT ts FROM slice WHERE name LIKE '%startProcess%' LIMIT 1) AS start_ts, (SELECT ts FROM slice WHERE name LIKE '%handleBindApplication%' LIMIT 1) AS end_ts, ((SELECT ts FROM slice WHERE name LIKE '%handleBindApplication%' LIMIT 1) - (SELECT ts FROM slice WHERE name LIKE '%startProcess%' LIMIT 1)) / 1000000.0 AS duration_ms UNION ALL SELECT 'Application Init' AS stage, (SELECT ts FROM slice WHERE name LIKE '%handleBindApplication%' LIMIT 1) AS start_ts, (SELECT ts FROM slice WHERE name LIKE '%performLaunchActivity%' LIMIT 1) AS end_ts, ((SELECT ts FROM slice WHERE name LIKE '%performLaunchActivity%' LIMIT 1) - (SELECT ts FROM slice WHERE name LIKE '%handleBindApplication%' LIMIT 1)) / 1000000.0 AS duration_ms; ``` #### 3.2 卡顿分析查询模板 ```sql -- 查询掉帧统计 SELECT COUNT(*) AS jank_count, AVG(dur) / 1000000.0 AS avg_duration_ms, MAX(dur) / 1000000.0 AS max_duration_ms, MIN(dur) / 1000000.0 AS min_duration_ms FROM slice WHERE name = 'Choreographer#doFrame' AND dur > 16666667; ``` #### 3.3 主线程分析查询模板 ```sql -- 查询主线程耗时操作 SELECT name, dur / 1000000.0 AS duration_ms, ts FROM slice WHERE utid = (SELECT utid FROM thread WHERE name LIKE '%main%' LIMIT 1) ORDER BY dur DESC LIMIT 20; ``` ## 六、批量处理方案 ### 1. 批量录制和分析 #### 1.1 批量录制脚本 **batch_analysis.sh:** ```bash #!/bin/bash # 批量录制和分析脚本 # 用法: ./batch_analysis.sh [次数] [时长] [应用包名] COUNT=${1:-5} DURATION=${2:-10} PACKAGE=${3:-com.example.app} OUTPUT_DIR="batch_traces_$(date +%Y%m%d_%H%M%S)" mkdir -p ${OUTPUT_DIR} echo "批量录制和分析 ${COUNT} 次Trace..." for i in $(seq 1 $COUNT); do echo "========== 第 ${i} 次 ==========" # 录制 echo "录制Trace..." adb shell perfetto -c - --out /data/misc/perfetto-traces/trace_${i} \ -a ${PACKAGE} -t ${DURATION}s # 拉取 echo "拉取Trace文件..." adb pull /data/misc/perfetto-traces/trace_${i} \ ${OUTPUT_DIR}/trace_${i}.pb # 分析(使用Python脚本) echo "分析Trace..." python analyze_trace.py ${OUTPUT_DIR}/trace_${i}.pb > \ ${OUTPUT_DIR}/analysis_${i}.txt echo "第 ${i} 次完成" echo "" sleep 2 done echo "所有Trace已保存到 ${OUTPUT_DIR}/" echo "分析结果已保存到 ${OUTPUT_DIR}/analysis_*.txt" ``` #### 1.2 批量对比脚本 **batch_compare.sh:** ```bash #!/bin/bash # 批量对比脚本 # 用法: ./batch_compare.sh [基准目录] [对比目录] [输出文件] BASELINE_DIR=${1:-baseline_traces} COMPARE_DIR=${2:-compare_traces} OUTPUT=${3:-compare_report.txt} echo "批量对比分析..." echo "基准目录: ${BASELINE_DIR}" echo "对比目录: ${COMPARE_DIR}" echo "输出文件: ${OUTPUT}" # 这里应该实现对比逻辑 # 对比启动时间、帧率、卡顿等指标 echo "对比报告已生成: ${OUTPUT}" ``` ### 2. 自动化报告生成 #### 2.1 报告模板 **report_template.html:** ```html 性能分析报告

性能分析报告

``` #### 2.2 报告生成脚本 **generate_batch_report.py:** ```python #!/usr/bin/env python3 """ 批量生成分析报告 """ import os import json from datetime import datetime def generate_batch_report(trace_dir, output_file): """批量生成报告""" reports = [] for trace_file in os.listdir(trace_dir): if trace_file.endswith('.pb'): # 分析每个Trace文件 # 这里应该调用实际的分析函数 report = { 'file': trace_file, 'timestamp': datetime.now().isoformat(), 'metrics': {} } reports.append(report) # 生成汇总报告 with open(output_file, 'w', encoding='utf-8') as f: json.dump(reports, f, indent=2) print(f"批量报告已生成: {output_file}") if __name__ == '__main__': import sys trace_dir = sys.argv[1] if len(sys.argv) > 1 else 'traces' output_file = sys.argv[2] if len(sys.argv) > 2 else 'batch_report.json' generate_batch_report(trace_dir, output_file) ``` ## 七、团队协作方案 ### 1. 共享配置和模板 #### 1.1 Git仓库管理 ``` perfetto-tools/ ├── templates/ # 配置模板 │ ├── startup_config.txt │ ├── jank_config.txt │ └── memory_config.txt ├── scripts/ # 脚本 │ ├── quick_trace.sh │ ├── analyze_trace.py │ └── generate_report.py ├── sql/ # SQL查询模板 │ ├── startup_queries.sql │ ├── jank_queries.sql │ └── memory_queries.sql └── docs/ # 文档 ├── README.md └── best_practices.md ``` #### 1.2 配置版本管理 - 使用Git管理配置模板 - 记录配置变更历史 - 共享最佳实践配置 - 建立配置评审机制 ### 2. 知识库建设 #### 2.1 案例库 - **成功案例**:记录优化成功的案例 - **问题案例**:记录常见问题和解决方案 - **分析模板**:建立标准分析模板 - **优化建议**:积累优化建议库 #### 2.2 文档管理 - **分析流程文档**:标准化的分析流程 - **工具使用文档**:工具和脚本使用说明 - **最佳实践文档**:总结最佳实践 - **FAQ文档**:常见问题解答 ### 3. 协作工具 #### 3.1 共享Trace文件 - 使用云存储共享Trace文件 - 建立Trace文件命名规范 - 记录Trace文件元数据 - 建立Trace文件索引 #### 3.2 协作分析 - 使用在线协作工具 - 共享分析结果 - 建立分析讨论机制 - 记录分析决策 ## 八、智能分析方案 ### 1. 自动化问题检测 #### 1.1 问题检测规则 **detect_issues.py:** ```python #!/usr/bin/env python3 """ 自动检测性能问题 """ def detect_startup_issues(trace_file): """检测启动问题""" issues = [] # 检测启动时间过长 # 检测主线程阻塞 # 检测系统服务调用耗时 # ... return issues def detect_jank_issues(trace_file): """检测卡顿问题""" issues = [] # 检测掉帧 # 检测主线程阻塞 # 检测渲染瓶颈 # ... return issues def generate_issue_report(issues, output_file): """生成问题报告""" with open(output_file, 'w', encoding='utf-8') as f: for issue in issues: f.write(f"{issue['type']}: {issue['description']}\n") f.write(f" 位置: {issue['location']}\n") f.write(f" 建议: {issue['suggestion']}\n\n") print(f"问题报告已生成: {output_file}") ``` #### 1.2 性能基准对比 **compare_baseline.py:** ```python #!/usr/bin/env python3 """ 与性能基准对比 """ def load_baseline(baseline_file): """加载性能基准""" with open(baseline_file, 'r') as f: return json.load(f) def compare_with_baseline(trace_file, baseline): """与基准对比""" # 分析Trace文件 # 与基准对比 # 生成对比报告 pass ``` ### 2. 机器学习辅助分析 #### 2.1 异常检测 - 使用机器学习检测异常模式 - 自动识别性能问题 - 提供问题分类和优先级 #### 2.2 预测分析 - 预测性能趋势 - 识别潜在问题 - 提供预防建议 ## 九、性能监控集成 ### 1. CI/CD集成 #### 1.1 自动化测试 **ci_performance_test.sh:** ```bash #!/bin/bash # CI/CD性能测试脚本 echo "开始性能测试..." # 录制Trace adb shell perfetto -c - --out /data/misc/perfetto-traces/trace -t 10s adb pull /data/misc/perfetto-traces/trace ci_trace.pb # 分析Trace python analyze_trace.py ci_trace.pb > ci_analysis.txt # 检查性能指标 python check_performance.py ci_analysis.txt # 如果性能不达标,退出 if [ $? -ne 0 ]; then echo "性能测试失败" exit 1 fi echo "性能测试通过" ``` #### 1.2 性能回归检测 - 在CI/CD中集成性能测试 - 自动检测性能回归 - 生成性能报告 - 通知相关人员 ### 2. 持续监控 #### 2.1 定期分析 - 定期录制和分析Trace - 建立性能趋势图 - 识别性能退化 - 及时发现问题 #### 2.2 告警机制 - 设置性能阈值 - 自动触发告警 - 通知相关人员 - 记录告警历史 ## 十、总结 ### 1. 提效关键点 1. **工具自动化**:使用脚本自动化重复操作 2. **流程标准化**:建立标准化的分析流程 3. **模板复用**:使用配置和分析模板 4. **批量处理**:批量录制和分析Trace 5. **智能分析**:使用SQL和工具进行智能分析 6. **团队协作**:建立共享配置和知识库 7. **持续监控**:集成到CI/CD和监控系统 ### 2. 实施建议 1. **逐步实施**:从简单的脚本开始,逐步完善 2. **持续改进**:根据实际使用情况不断优化 3. **知识积累**:建立案例库和最佳实践 4. **团队培训**:培训团队成员使用工具和流程 ### 3. 预期效果 - **分析时间**:从数小时缩短到数十分钟 - **分析准确性**:提高分析准确性 - **知识积累**:建立可复用的知识库 - **团队效率**:提高团队整体效率 --- *最后更新:2024年*