mobile-eda/test/performance/large_circuit_benchmark.dart

433 lines
13 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 大电路性能压测基准
*
* 测试场景1000/5000/10000 元件设计
* 测试指标:启动时间、帧率、内存占用、操作延迟
* 瓶颈分析:渲染/数据/手势识别
*
* @version 1.0.0
* @date 2026-03-07
* @author 性能优化专家
*/
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'dart:math' as math;
import '../../lib/domain/models/core_models.dart';
import '../../lib/presentation/components/editable_canvas.dart';
import '../../lib/domain/managers/selection_manager.dart';
// ============================================================================
// 性能指标模型
// ============================================================================
/// 性能测试结果
class PerformanceMetrics {
final int componentCount;
final Duration startupTime;
final double averageFPS;
final int minFPS;
final int maxFPS;
final int memoryUsageMB;
final Duration panLatency;
final Duration zoomLatency;
final Duration tapLatency;
final Duration dragLatency;
final String bottleneck;
final Map<String, dynamic> details;
PerformanceMetrics({
required this.componentCount,
required this.startupTime,
required this.averageFPS,
required this.minFPS,
required this.maxFPS,
required this.memoryUsageMB,
required this.panLatency,
required this.zoomLatency,
required this.tapLatency,
required this.dragLatency,
required this.bottleneck,
required this.details,
});
@override
String toString() {
return '''
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
性能报告 - ${componentCount} 元件
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
启动时间:${startupTime.inMilliseconds}ms
帧率:${averageFPS.toStringAsFixed(1)} FPS (min: $minFPS, max: $maxFPS)
内存占用:${memoryUsageMB}MB
操作延迟:
- 平移:${panLatency.inMilliseconds}ms
- 缩放:${zoomLatency.inMilliseconds}ms
- 点击:${tapLatency.inMilliseconds}ms
- 拖拽:${dragLatency.inMilliseconds}ms
瓶颈分析:$bottleneck
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
''';
}
Map<String, dynamic> toJson() {
return {
'componentCount': componentCount,
'startupTime': startupTime.inMilliseconds,
'averageFPS': averageFPS,
'minFPS': minFPS,
'maxFPS': maxFPS,
'memoryUsageMB': memoryUsageMB,
'panLatency': panLatency.inMilliseconds,
'zoomLatency': zoomLatency.inMilliseconds,
'tapLatency': tapLatency.inMilliseconds,
'dragLatency': dragLatency.inMilliseconds,
'bottleneck': bottleneck,
'details': details,
};
}
}
// ============================================================================
// 测试数据生成器
// ============================================================================
/// 测试电路生成器
class TestCircuitGenerator {
static Design generateDesign({
required int componentCount,
String name = 'Performance Test',
}) {
final timestamp = DateTime.now().millisecondsSinceEpoch;
final random = math.Random(42); // 固定种子保证可重复性
final components = <ID, Component>{};
final nets = <ID, Net>{};
// 生成元件
for (int i = 0; i < componentCount; i++) {
final id = 'comp_$i';
final x = random.nextInt(10000) * 1000; // 0-10000mm
final y = random.nextInt(10000) * 1000;
final pinCount = 4 + random.nextInt(12); // 4-16 pins
final pins = <PinReference>[];
for (int p = 0; p < pinCount; p++) {
pins.add(PinReference(
pinId: 'pin_$p',
name: 'P$p',
x: (p % 4) * 100000 - 150000,
y: (p ~/ 4) * 100000 - 150000,
rotation: 0,
electricalType: PinElectricalType.passive,
));
}
components[id] = Component(
id: id,
name: 'U$i',
type: ComponentType.ic,
value: 'TEST_${i % 100}',
footprint: Footprint(
id: 'fp_$i',
name: 'TEST_FP',
pads: [],
metadata: Metadata(
createdAt: timestamp,
updatedAt: timestamp,
),
),
position: Position2D(x: x, y: y),
layerId: 'layer_signal_1',
rotation: 0,
mirror: MirrorState.none,
pins: pins,
metadata: Metadata(
createdAt: timestamp,
updatedAt: timestamp,
),
);
}
// 生成网络连接(每个元件随机连接 1-3 个其他元件)
int netIndex = 0;
components.forEach((id, component) {
final connectionCount = 1 + random.nextInt(3);
for (int c = 0; c < connectionCount; c++) {
final targetId = components.keys.elementAt(
random.nextInt(components.length),
);
if (targetId == id) continue;
final targetComponent = components[targetId]!;
final netId = 'net_${netIndex++}';
nets[netId] = Net(
id: netId,
name: 'N$netIndex',
type: NetType.signal,
connections: [
ConnectionPoint(
id: '$id:pin_0',
type: ConnectionType.pin,
componentId: id,
pinId: 'pin_0',
position: Position2D(
x: component.position.x + component.pins[0].x,
y: component.position.y + component.pins[0].y,
),
layerId: component.layerId,
),
ConnectionPoint(
id: '$targetId:pin_0',
type: ConnectionType.pin,
componentId: targetId,
pinId: 'pin_0',
position: Position2D(
x: targetComponent.position.x + targetComponent.pins[0].x,
y: targetComponent.position.y + targetComponent.pins[0].y,
),
layerId: targetComponent.layerId,
),
],
metadata: Metadata(
createdAt: timestamp,
updatedAt: timestamp,
),
);
}
});
return Design(
id: 'perf_test_design',
name: name,
version: '1.0.0',
components: components,
nets: nets,
layers: {
'layer_signal_1': Layer(
id: 'layer_signal_1',
name: 'Signal Layer 1',
type: LayerType.signal,
stackupOrder: 1,
metadata: Metadata(
createdAt: timestamp,
updatedAt: timestamp,
),
),
},
designRules: DesignRules(),
createdAt: timestamp,
updatedAt: timestamp,
);
}
}
// ============================================================================
// 性能测试工具
// ============================================================================
/// FPS 计数器
class FPSCounter {
final List<int> _frameTimes = [];
DateTime? _lastFrameTime;
int _frameCount = 0;
void markFrame() {
final now = DateTime.now();
if (_lastFrameTime != null) {
_frameTimes.add(now.difference(_lastFrameTime!).inMilliseconds);
if (_frameTimes.length > 300) {
_frameTimes.removeAt(0);
}
}
_lastFrameTime = now;
_frameCount++;
}
double get averageFPS {
if (_frameTimes.isEmpty) return 0.0;
final avgFrameTime = _frameTimes.reduce((a, b) => a + b) / _frameTimes.length;
return avgFrameTime > 0 ? 1000.0 / avgFrameTime : 0.0;
}
int get minFPS {
if (_frameTimes.isEmpty) return 0;
final maxFrameTime = _frameTimes.reduce(math.max);
return maxFrameTime > 0 ? (1000.0 / maxFrameTime).floor() : 0;
}
int get maxFPS {
if (_frameTimes.isEmpty) return 0;
final minFrameTime = _frameTimes.reduce(math.min);
return minFrameTime > 0 ? (1000.0 / minFrameTime).floor() : 0;
}
void reset() {
_frameTimes.clear();
_lastFrameTime = null;
_frameCount = 0;
}
}
// ============================================================================
// 基准测试
// ============================================================================
void main() {
group('大电路性能基准测试', () {
testWidgets('1000 元件 - 启动性能', (WidgetTester tester) async {
final design = TestCircuitGenerator.generateDesign(componentCount: 1000);
final selectionManager = SelectionManager();
final stopwatch = Stopwatch()..start();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: EditableCanvas(
design: design,
onDesignChanged: (newDesign) {},
selectionManager: selectionManager,
),
),
),
);
await tester.pumpAndSettle();
stopwatch.stop();
final startupTime = stopwatch.elapsed;
print('✓ 1000 元件启动时间:${startupTime.inMilliseconds}ms');
expect(startupTime.inMilliseconds, lessThan(3000),
reason: '1000 元件启动时间应小于 3 秒');
});
testWidgets('1000 元件 - 平移性能', (WidgetTester tester) async {
final design = TestCircuitGenerator.generateDesign(componentCount: 1000);
final selectionManager = SelectionManager();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: EditableCanvas(
design: design,
onDesignChanged: (newDesign) {},
selectionManager: selectionManager,
),
),
),
);
await tester.pumpAndSettle();
final fpsCounter = FPSCounter();
final stopwatch = Stopwatch();
// 执行平移操作
stopwatch.start();
final gesture = await tester.startGesture(const Offset(200, 200));
for (int i = 0; i < 10; i++) {
await gesture.moveBy(const Offset(50, 0));
await tester.pump();
fpsCounter.markFrame();
}
await gesture.up();
stopwatch.stop();
final avgLatency = stopwatch.elapsedMilliseconds ~/ 10;
print('✓ 1000 元件平移延迟:${avgLatency}ms, FPS: ${fpsCounter.averageFPS.toStringAsFixed(1)}');
expect(avgLatency, lessThan(50),
reason: '平移延迟应小于 50ms');
expect(fpsCounter.averageFPS, greaterThan(30),
reason: '帧率应大于 30 FPS');
});
testWidgets('5000 元件 - 启动性能', (WidgetTester tester) async {
final design = TestCircuitGenerator.generateDesign(componentCount: 5000);
final selectionManager = SelectionManager();
final stopwatch = Stopwatch()..start();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: EditableCanvas(
design: design,
onDesignChanged: (newDesign) {},
selectionManager: selectionManager,
),
),
),
);
await tester.pumpAndSettle();
stopwatch.stop();
final startupTime = stopwatch.elapsed;
print('✓ 5000 元件启动时间:${startupTime.inMilliseconds}ms');
// 5000 元件允许更长的启动时间
expect(startupTime.inMilliseconds, lessThan(10000),
reason: '5000 元件启动时间应小于 10 秒');
});
testWidgets('10000 元件 - 启动性能', (WidgetTester tester) async {
final design = TestCircuitGenerator.generateDesign(componentCount: 10000);
final selectionManager = SelectionManager();
final stopwatch = Stopwatch()..start();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: EditableCanvas(
design: design,
onDesignChanged: (newDesign) {},
selectionManager: selectionManager,
),
),
),
);
await tester.pumpAndSettle();
stopwatch.stop();
final startupTime = stopwatch.elapsed;
print('✓ 10000 元件启动时间:${startupTime.inMilliseconds}ms');
// 10000 元件需要优化,这里先记录基线
print('⚠ 10000 元件启动时间基线:${startupTime.inMilliseconds}ms (待优化)');
});
test('生成性能基准报告', () {
// 这是一个示例报告生成测试
final metrics = PerformanceMetrics(
componentCount: 1000,
startupTime: const Duration(milliseconds: 1500),
averageFPS: 55.5,
minFPS: 45,
maxFPS: 60,
memoryUsageMB: 128,
panLatency: const Duration(milliseconds: 16),
zoomLatency: const Duration(milliseconds: 20),
tapLatency: const Duration(milliseconds: 8),
dragLatency: const Duration(milliseconds: 24),
bottleneck: '渲染性能',
details: {
'renderTime': 12,
'layoutTime': 4,
'gestureTime': 2,
},
);
print(metrics);
print('JSON: ${metrics.toJson()}');
});
});
}