12 KiB
12 KiB
Phase 4 性能测试计划
阶段: Week 11-12 - 性能优化与基准测试
测试负责人: 测试工程师
更新日期: 2026-03-07
状态: 🟡 进行中
📊 性能目标
核心性能指标
| 指标 | 目标值 | 最低可接受 | 测量方法 |
|---|---|---|---|
| 渲染帧率 (100 元件) | 60fps | 60fps | Flutter DevTools |
| 渲染帧率 (500 元件) | 60fps | 55fps | Flutter DevTools |
| 渲染帧率 (1000 元件) | 60fps | 50fps | Flutter DevTools |
| 渲染帧率 (5000 元件) | 30fps | 24fps | Flutter DevTools |
| 冷启动时间 | <2s | <3s | Firebase Performance |
| 热启动时间 | <1s | <2s | Firebase Performance |
| 内存占用 (1000 元件) | <300MB | <500MB | Xcode Instruments / Android Profiler |
| 保存耗时 (1000 元件) | <1s | <2s | 代码埋点 |
| 加载耗时 (1000 元件) | <1s | <2s | 代码埋点 |
| 崩溃率 | <0.1% | <0.5% | Firebase Crashlytics |
| ANR 率 (Android) | <0.1% | <0.5% | Firebase Crashlytics |
🧪 性能测试场景
PERF-001: 渲染性能基准测试
优先级: P0
测试工具: Flutter DevTools, PerformanceOverlay
测试步骤:
- 打开性能监控
// main.dart 添加性能监控
import 'package:flutter/scheduler.dart';
void main() {
// ...
runApp(MyApp());
// 开启性能监控(仅调试模式)
if (kDebugMode) {
WidgetsBinding.instance.addPostFrameCallback((_) {
debugProfileBuildsEnabled = true;
debugProfilePaintsEnabled = true;
});
}
}
- 创建不同规模的测试项目
| 项目名 | 元件数 | 连线数 | 用途 |
|---|---|---|---|
| Test-Small | 50 | 30 | 基础性能 |
| Test-Medium | 200 | 150 | 常规使用 |
| Test-Large | 1000 | 800 | 性能基准 |
| Test-Extreme | 5000 | 4000 | 压力测试 |
- 测量帧率
操作 目标帧率 测量时间
- 静态显示 60fps 10 秒
- 缓慢平移 60fps 10 秒
- 快速平移 60fps 10 秒
- 缓慢缩放 60fps 10 秒
- 快速缩放 60fps 10 秒
- 旋转 60fps 10 秒
- 记录结果
| 项目规模 | 静态 | 平移 | 缩放 | 旋转 | 平均 |
|---|---|---|---|---|---|
| 50 元件 | - | - | - | - | - |
| 200 元件 | - | - | - | - | - |
| 1000 元件 | - | - | - | - | - |
| 5000 元件 | - | - | - | - | - |
验收标准:
- 1000 元件场景平均帧率 ≥50fps
- 5000 元件场景平均帧率 ≥24fps
- 无明显掉帧或卡顿
PERF-002: 内存性能测试
优先级: P0
测试工具: Xcode Instruments (iOS), Android Profiler (Android)
测试步骤:
- 基线测量
应用启动后空闲状态内存:___ MB
- 加载不同规模项目
| 操作 | 内存增量 | 峰值内存 | 释放后内存 |
|---|---|---|---|
| 加载 50 元件 | - | - | - |
| 加载 200 元件 | - | - | - |
| 加载 1000 元件 | - | - | - |
| 加载 5000 元件 | - | - | - |
- 内存泄漏检测
操作 内存变化
- 打开/关闭项目 10 次 -
- 快速缩放 100 次 -
- 添加/删除元件 100 次 -
- 应用前后台切换 10 次 -
- 长时间运行测试
运行时间 内存占用 备注
0 min - 初始
15 min - 持续编辑
30 min - 持续编辑
60 min - 持续编辑
验收标准:
- 1000 元件场景内存 <500MB
- 无明显内存泄漏(1 小时增长 <50MB)
- 内存释放正常
PERF-003: 启动性能测试
优先级: P1
测试工具: Firebase Performance Monitoring
测试步骤:
- 冷启动时间测量(应用完全关闭后首次启动)
测试次数 启动时间 备注
1 - 首次安装
2 - 第二次
3 - 第三次
4 - 第四次
5 - 第五次
平均 -
- 热启动时间测量(应用在后台,切换到前台)
测试次数 启动时间 备注
1 -
2 -
3 -
4 -
5 -
平均 -
- 启动流程分解
阶段 耗时
- 应用初始化 -
- Isar 数据库打开 -
- 主 Widget 构建 -
- 首页渲染完成 -
- 可交互状态 -
总计 -
验收标准:
- 冷启动时间 <3s
- 热启动时间 <2s
- 启动过程无白屏
PERF-004: 存储性能测试
优先级: P1
测试工具: 代码埋点
测试步骤:
- 保存性能
| 项目规模 | 保存耗时 | 文件大小 | 状态 |
|---|---|---|---|
| 50 元件 | - | - | ⏳ |
| 200 元件 | - | - | ⏳ |
| 1000 元件 | - | - | ⏳ |
| 5000 元件 | - | - | ⏳ |
- 加载性能
| 项目规模 | 加载耗时 | 文件大小 | 状态 |
|---|---|---|---|
| 50 元件 | - | - | ⏳ |
| 200 元件 | - | - | ⏳ |
| 1000 元件 | - | - | ⏳ |
| 5000 元件 | - | - | ⏳ |
- 云同步性能
| 操作 | 网络条件 | 耗时 | 状态 |
|---|---|---|---|
| 上传 1MB | WiFi | - | ⏳ |
| 上传 1MB | 4G | - | ⏳ |
| 下载 1MB | WiFi | - | ⏳ |
| 下载 1MB | 4G | - | ⏳ |
验收标准:
- 1000 元件保存 <2s
- 1000 元件加载 <2s
- 云同步有进度提示
PERF-005: 电池性能测试
优先级: P2
测试工具: 系统电池统计
测试步骤:
- 正常使用场景
场景 10 分钟耗电
- 静态显示 -
- 持续编辑 -
- 频繁缩放 -
- 屏幕常亮 -
- 低电量模式
模式 性能变化 备注
正常模式 100% -
省电模式 - 系统限制
低电量模式 - 应用适配
验收标准:
- 1 小时持续编辑耗电 <15%
- 低电量模式有适配
PERF-006: 网络性能测试
优先级: P1
测试工具: Network Link Conditioner (iOS), Android Emulator Network
测试场景:
| 网络条件 | 延迟 | 带宽 | 测试项 | 预期结果 |
|---|---|---|---|---|
| WiFi | 20ms | 100Mbps | 同步 | <5s |
| 4G | 100ms | 10Mbps | 同步 | <10s |
| 3G | 300ms | 1Mbps | 同步 | <30s |
| 2G | 1000ms | 50Kbps | 同步 | 超时提示 |
| 弱网 | 500ms+ | 波动 | 同步 | 不崩溃 |
| 断网 | - | 0 | 本地操作 | 正常 |
验收标准:
- 正常网络同步流畅
- 弱网有超时处理
- 断网可本地操作
🔧 性能优化技术
渲染优化
1. 视口裁剪(Viewport Culling)
只绘制可见区域内的元件:
void _drawComponents(Canvas canvas, Size size) {
// 计算可见区域(考虑缩放和平移)
final visibleRect = _calculateVisibleRect(size);
// 只绘制可见区域内的元件
for (final component in components) {
if (_isVisible(visibleRect, component.bounds)) {
_drawComponent(canvas, component);
}
}
}
Rect _calculateVisibleRect(Size size) {
return Rect.fromLTWH(
-offset.dx / zoomLevel,
-offset.dy / zoomLevel,
size.width / zoomLevel,
size.height / zoomLevel,
);
}
2. 分层渲染(Layer Rendering)
使用 Layer 隔离不同元素的重绘:
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: Stack(
children: [
// 网格层(静态,很少重绘)
RepaintBoundary(
child: CustomPaint(painter: GridPainter()),
),
// 元件层(中等频率)
RepaintBoundary(
child: CustomPaint(painter: ComponentPainter()),
),
// 交互层(高频重绘)
CustomPaint(painter: InteractionPainter()),
],
),
);
}
3. 离屏缓存(Off-screen Caching)
缓存静态内容:
Picture? _cachedPicture;
void _cacheComponents() {
final recorder = PictureRecorder();
final canvas = Canvas(recorder);
// 绘制到离屏
_drawComponentsToCanvas(canvas);
_cachedPicture = recorder.endRecording();
}
@override
void paint(Canvas canvas, Size size) {
if (_cachedPicture != null) {
// 使用缓存
canvas.drawPicture(_cachedPicture!);
} else {
// 实时绘制
_drawComponents(canvas);
}
}
内存优化
1. 图片资源优化
// 使用适当分辨率的图片
Image.asset(
'assets/icons/component.png',
width: 24,
height: 24,
cacheWidth: 48, // 2x 分辨率
cacheHeight: 48,
)
2. 及时释放资源
@override
void dispose() {
_cachedPicture?.dispose();
_animationController.dispose();
super.dispose();
}
3. 使用 const 构造函数
// 使用 const 减少重建
const Icon(Icons.save)
const SizedBox(width: 8)
启动优化
1. 延迟加载
// 非关键数据延迟加载
Future.delayed(Duration.zero, () {
_loadBackgroundData();
});
2. 异步初始化
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 并行初始化
await Future.wait([
Firebase.initializeApp(),
Isar.open([...]),
AppConfig.init(),
]);
runApp(MyApp());
}
📈 性能监控
Firebase Performance Monitoring
// pubspec.yaml
dependencies:
firebase_core: ^2.24.0
firebase_performance: ^0.9.3
// main.dart
import 'package:firebase_performance/firebase_performance.dart';
// 追踪自定义指标
final Trace saveTrace = FirebasePerformance.instance.newTrace('save_project');
await saveTrace.start();
// 执行保存操作
await _saveProject();
await saveTrace.stop();
// 记录自定义指标
final MetricHandle memoryMetric = FirebasePerformance.instance.newMetric('memory_usage');
memoryMetric.setValue(currentMemoryMB);
代码埋点
class PerformanceTracker {
static final Map<String, DateTime> _timers = {};
static void start(String label) {
_timers[label] = DateTime.now();
}
static void end(String label) {
final start = _timers[label];
if (start != null) {
final duration = DateTime.now().difference(start);
print('[$label] ${duration.inMilliseconds}ms');
_timers.remove(label);
}
}
}
// 使用
PerformanceTracker.start('load_project');
await loadProject();
PerformanceTracker.end('load_project');
📊 性能测试报告模板
Mobile EDA 性能测试报告
测试日期: YYYY-MM-DD
测试人员: 测试工程师
设备信息: [设备型号/系统版本]
渲染性能
| 场景 | 目标 | 实测 | 状态 |
|---|---|---|---|
| 100 元件静态 | 60fps | - | ⏳ |
| 100 元件平移 | 60fps | - | ⏳ |
| 1000 元件静态 | 60fps | - | ⏳ |
| 1000 元件平移 | 50fps | - | ⏳ |
| 5000 元件静态 | 30fps | - | ⏳ |
内存性能
| 场景 | 目标 | 实测 | 状态 |
|---|---|---|---|
| 空闲状态 | <100MB | - | ⏳ |
| 1000 元件 | <500MB | - | ⏳ |
| 5000 元件 | <1GB | - | ⏳ |
| 1 小时运行 | 增长<50MB | - | ⏳ |
启动性能
| 类型 | 目标 | 实测 | 状态 |
|---|---|---|---|
| 冷启动 | <3s | - | ⏳ |
| 热启动 | <2s | - | ⏳ |
存储性能
| 操作 | 规模 | 目标 | 实测 | 状态 |
|---|---|---|---|---|
| 保存 | 1000 元件 | <2s | - | ⏳ |
| 加载 | 1000 元件 | <2s | - | ⏳ |
崩溃率
| 指标 | 目标 | 实测 | 状态 |
|---|---|---|---|
| 崩溃率 | <0.1% | - | ⏳ |
| ANR 率 | <0.1% | - | ⏳ |
性能问题汇总
| 问题描述 | 严重程度 | 优化建议 | 状态 |
|---|---|---|---|
| - | - | - | ⏳ |
优化建议
- ...
- ...
- ...
结论: [通过/不通过]
📅 测试计划
Week 11
| 日期 | 测试内容 | 负责人 |
|---|---|---|
| 周一 | PERF-001 渲染性能 | 测试工程师 |
| 周二 | PERF-002 内存性能 | 测试工程师 |
| 周三 | PERF-003 启动性能 | 测试工程师 |
| 周四 | PERF-004 存储性能 | 测试工程师 |
| 周五 | PERF-005/006 电池/网络 | 测试工程师 |
Week 12
| 日期 | 测试内容 | 负责人 |
|---|---|---|
| 周一 | 性能问题修复验证 | 测试工程师 |
| 周二 | 回归测试 | 测试工程师 |
| 周三 | 性能基准报告 | 测试工程师 |
文档维护: 测试工程师
最后更新: 2026-03-07