/** * Protobuf序列化性能测试 */ import { Component } from '../../../src/ECS/Component'; import { Entity } from '../../../src/ECS/Entity'; import { Scene } from '../../../src/ECS/Scene'; import { SnapshotManager } from '../../../src/Utils/Snapshot/SnapshotManager'; import { ProtobufSerializer } from '../../../src/Utils/Serialization/ProtobufSerializer'; import { ProtoSerializable, ProtoFloat, ProtoInt32, ProtoString, ProtoBool } from '../../../src/Utils/Serialization/ProtobufDecorators'; // 性能测试组件 @ProtoSerializable('PerfPosition') class PerfPositionComponent extends Component { @ProtoFloat(1) public x: number = 0; @ProtoFloat(2) public y: number = 0; @ProtoFloat(3) public z: number = 0; constructor(x: number = 0, y: number = 0, z: number = 0) { super(); this.x = x; this.y = y; this.z = z; } } @ProtoSerializable('PerfVelocity') class PerfVelocityComponent extends Component { @ProtoFloat(1) public vx: number = 0; @ProtoFloat(2) public vy: number = 0; @ProtoFloat(3) public vz: number = 0; constructor(vx: number = 0, vy: number = 0, vz: number = 0) { super(); this.vx = vx; this.vy = vy; this.vz = vz; } } @ProtoSerializable('PerfHealth') class PerfHealthComponent extends Component { @ProtoInt32(1) public maxHealth: number = 100; @ProtoInt32(2) public currentHealth: number = 100; @ProtoBool(3) public isDead: boolean = false; @ProtoFloat(4) public regenerationRate: number = 0.5; constructor(maxHealth: number = 100) { super(); this.maxHealth = maxHealth; this.currentHealth = maxHealth; } } @ProtoSerializable('PerfPlayer') class PerfPlayerComponent extends Component { @ProtoString(1) public name: string = ''; @ProtoInt32(2) public level: number = 1; @ProtoInt32(3) public experience: number = 0; @ProtoInt32(4) public score: number = 0; @ProtoBool(5) public isOnline: boolean = true; constructor(name: string = 'Player', level: number = 1) { super(); this.name = name; this.level = level; } } // 传统JSON序列化组件(用于对比) class JsonPositionComponent extends Component { public x: number = 0; public y: number = 0; public z: number = 0; constructor(x: number = 0, y: number = 0, z: number = 0) { super(); this.x = x; this.y = y; this.z = z; } } class JsonPlayerComponent extends Component { public name: string = ''; public level: number = 1; public experience: number = 0; public score: number = 0; public isOnline: boolean = true; constructor(name: string = 'Player', level: number = 1) { super(); this.name = name; this.level = level; } } // Mock protobuf.js for performance testing const createMockProtobuf = () => { const mockEncodedData = new Uint8Array(32); // 模拟32字节的编码数据 mockEncodedData.fill(1); return { parse: jest.fn().mockReturnValue({ root: { lookupType: jest.fn().mockImplementation((typeName: string) => ({ verify: jest.fn().mockReturnValue(null), create: jest.fn().mockImplementation((data) => data), encode: jest.fn().mockReturnValue({ finish: jest.fn().mockReturnValue(mockEncodedData) }), decode: jest.fn().mockReturnValue({ x: 10, y: 20, z: 30, vx: 1, vy: 2, vz: 3, maxHealth: 100, currentHealth: 80, isDead: false, regenerationRate: 0.5, name: 'TestPlayer', level: 5, experience: 1000, score: 5000, isOnline: true }), toObject: jest.fn().mockImplementation((message) => message) })) } }) }; }; describe('Protobuf序列化性能测试', () => { let protobufSerializer: ProtobufSerializer; let snapshotManager: SnapshotManager; let scene: Scene; beforeEach(() => { protobufSerializer = ProtobufSerializer.getInstance(); protobufSerializer.initialize(createMockProtobuf()); snapshotManager = new SnapshotManager(); snapshotManager.initializeProtobuf(createMockProtobuf()); scene = new Scene(); jest.clearAllMocks(); }); describe('单组件序列化性能', () => { const iterations = 1000; it('应该比较protobuf和JSON序列化速度', () => { const protobufComponents: PerfPositionComponent[] = []; const jsonComponents: JsonPositionComponent[] = []; // 准备测试数据 for (let i = 0; i < iterations; i++) { protobufComponents.push(new PerfPositionComponent( Math.random() * 1000, Math.random() * 1000, Math.random() * 100 )); jsonComponents.push(new JsonPositionComponent( Math.random() * 1000, Math.random() * 1000, Math.random() * 100 )); } // 测试Protobuf序列化 const protobufStartTime = performance.now(); let protobufTotalSize = 0; for (const component of protobufComponents) { const result = protobufSerializer.serialize(component); protobufTotalSize += result.size; } const protobufEndTime = performance.now(); const protobufTime = protobufEndTime - protobufStartTime; // 测试JSON序列化 const jsonStartTime = performance.now(); let jsonTotalSize = 0; for (const component of jsonComponents) { const jsonString = JSON.stringify({ x: component.x, y: component.y, z: component.z }); jsonTotalSize += new Blob([jsonString]).size; } const jsonEndTime = performance.now(); const jsonTime = jsonEndTime - jsonStartTime; // 性能断言 console.log(`\\n=== 单组件序列化性能对比 (${iterations} 次迭代) ===`); console.log(`Protobuf时间: ${protobufTime.toFixed(2)}ms`); console.log(`JSON时间: ${jsonTime.toFixed(2)}ms`); console.log(`Protobuf总大小: ${protobufTotalSize} bytes`); console.log(`JSON总大小: ${jsonTotalSize} bytes`); if (jsonTime > 0) { const speedImprovement = ((jsonTime - protobufTime) / jsonTime * 100); console.log(`速度提升: ${speedImprovement.toFixed(1)}%`); } if (jsonTotalSize > 0) { const sizeReduction = ((jsonTotalSize - protobufTotalSize) / jsonTotalSize * 100); console.log(`大小减少: ${sizeReduction.toFixed(1)}%`); } // 基本性能验证 expect(protobufTime).toBeLessThan(1000); // 不应该超过1秒 expect(jsonTime).toBeLessThan(1000); expect(protobufTotalSize).toBeGreaterThan(0); expect(jsonTotalSize).toBeGreaterThan(0); }); it('应该测试复杂组件的序列化性能', () => { const protobufPlayers: PerfPlayerComponent[] = []; const jsonPlayers: JsonPlayerComponent[] = []; // 创建测试数据 for (let i = 0; i < iterations; i++) { protobufPlayers.push(new PerfPlayerComponent( `Player${i}`, Math.floor(Math.random() * 100) + 1 )); jsonPlayers.push(new JsonPlayerComponent( `Player${i}`, Math.floor(Math.random() * 100) + 1 )); } // Protobuf序列化测试 const protobufStart = performance.now(); for (const player of protobufPlayers) { protobufSerializer.serialize(player); } const protobufTime = performance.now() - protobufStart; // JSON序列化测试 const jsonStart = performance.now(); for (const player of jsonPlayers) { JSON.stringify({ name: player.name, level: player.level, experience: player.experience, score: player.score, isOnline: player.isOnline }); } const jsonTime = performance.now() - jsonStart; console.log(`\\n=== 复杂组件序列化性能 (${iterations} 次迭代) ===`); console.log(`Protobuf时间: ${protobufTime.toFixed(2)}ms`); console.log(`JSON时间: ${jsonTime.toFixed(2)}ms`); expect(protobufTime).toBeLessThan(1000); expect(jsonTime).toBeLessThan(1000); }); }); describe('批量实体序列化性能', () => { it('应该测试大量实体的快照创建性能', () => { const entityCount = 100; const entities: Entity[] = []; // 创建测试实体 for (let i = 0; i < entityCount; i++) { const entity = scene.createEntity(`Entity${i}`); entity.addComponent(new PerfPositionComponent( Math.random() * 1000, Math.random() * 1000, Math.random() * 100 )); entity.addComponent(new PerfVelocityComponent( Math.random() * 10 - 5, Math.random() * 10 - 5, Math.random() * 2 - 1 )); entity.addComponent(new PerfHealthComponent(100 + Math.floor(Math.random() * 50))); entity.addComponent(new PerfPlayerComponent(`Player${i}`, Math.floor(Math.random() * 50) + 1)); entities.push(entity); } // 测试快照创建性能 const snapshotStart = performance.now(); const snapshot = snapshotManager.createSceneSnapshot(entities); const snapshotTime = performance.now() - snapshotStart; console.log(`\\n=== 批量实体序列化性能 ===`); console.log(`实体数量: ${entityCount}`); console.log(`每个实体组件数: 4`); console.log(`总组件数: ${entityCount * 4}`); console.log(`快照创建时间: ${snapshotTime.toFixed(2)}ms`); console.log(`平均每组件时间: ${(snapshotTime / (entityCount * 4)).toFixed(3)}ms`); expect(snapshot.entities).toHaveLength(entityCount); expect(snapshotTime).toBeLessThan(5000); // 不应该超过5秒 // 计算快照大小 let totalSnapshotSize = 0; for (const entitySnapshot of snapshot.entities) { for (const componentSnapshot of entitySnapshot.components) { if (componentSnapshot.data && typeof componentSnapshot.data === 'object' && 'size' in componentSnapshot.data) { totalSnapshotSize += (componentSnapshot.data as any).size; } } } console.log(`快照总大小: ${totalSnapshotSize} bytes`); console.log(`平均每实体大小: ${(totalSnapshotSize / entityCount).toFixed(1)} bytes`); expect(totalSnapshotSize).toBeGreaterThan(0); }); }); describe('反序列化性能', () => { it('应该测试快照恢复性能', () => { const entityCount = 50; const originalEntities: Entity[] = []; // 创建原始实体 for (let i = 0; i < entityCount; i++) { const entity = scene.createEntity(`Original${i}`); entity.addComponent(new PerfPositionComponent(i * 10, i * 20, i)); entity.addComponent(new PerfHealthComponent(100 + i)); originalEntities.push(entity); } // 创建快照 const snapshotStart = performance.now(); const snapshot = snapshotManager.createSceneSnapshot(originalEntities); const snapshotTime = performance.now() - snapshotStart; // 创建目标实体 const targetEntities: Entity[] = []; for (let i = 0; i < entityCount; i++) { const entity = scene.createEntity(`Target${i}`); entity.addComponent(new PerfPositionComponent()); entity.addComponent(new PerfHealthComponent()); targetEntities.push(entity); } // 测试恢复性能 const restoreStart = performance.now(); snapshotManager.restoreFromSnapshot(snapshot, targetEntities); const restoreTime = performance.now() - restoreStart; console.log(`\\n=== 反序列化性能测试 ===`); console.log(`实体数量: ${entityCount}`); console.log(`序列化时间: ${snapshotTime.toFixed(2)}ms`); console.log(`反序列化时间: ${restoreTime.toFixed(2)}ms`); console.log(`总往返时间: ${(snapshotTime + restoreTime).toFixed(2)}ms`); console.log(`平均每实体往返时间: ${((snapshotTime + restoreTime) / entityCount).toFixed(3)}ms`); expect(restoreTime).toBeLessThan(2000); // 不应该超过2秒 expect(snapshotTime + restoreTime).toBeLessThan(3000); // 总时间不超过3秒 }); }); describe('内存使用', () => { it('应该监控序列化过程中的内存使用', () => { const entityCount = 200; const entities: Entity[] = []; // 创建大量实体 for (let i = 0; i < entityCount; i++) { const entity = scene.createEntity(`MemoryTest${i}`); entity.addComponent(new PerfPositionComponent( Math.random() * 1000, Math.random() * 1000, Math.random() * 100 )); entity.addComponent(new PerfVelocityComponent( Math.random() * 10, Math.random() * 10, Math.random() * 2 )); entity.addComponent(new PerfHealthComponent(Math.floor(Math.random() * 200) + 50)); entities.push(entity); } // 记录初始内存(如果可用) const initialMemory = (performance as any).memory?.usedJSHeapSize || 0; // 执行序列化 const snapshot = snapshotManager.createSceneSnapshot(entities); // 记录序列化后内存 const afterMemory = (performance as any).memory?.usedJSHeapSize || 0; const memoryIncrease = afterMemory - initialMemory; if (initialMemory > 0) { console.log(`\\n=== 内存使用测试 ===`); console.log(`实体数量: ${entityCount}`); console.log(`初始内存: ${(initialMemory / 1024 / 1024).toFixed(2)} MB`); console.log(`序列化后内存: ${(afterMemory / 1024 / 1024).toFixed(2)} MB`); console.log(`内存增加: ${(memoryIncrease / 1024).toFixed(2)} KB`); console.log(`平均每实体内存: ${(memoryIncrease / entityCount).toFixed(1)} bytes`); } expect(snapshot.entities).toHaveLength(entityCount); // 清理 entities.length = 0; }); }); describe('极端情况性能', () => { it('应该处理大量小组件的性能', () => { const componentCount = 5000; const components: PerfPositionComponent[] = []; // 创建大量小组件 for (let i = 0; i < componentCount; i++) { components.push(new PerfPositionComponent(i, i * 2, i * 3)); } const start = performance.now(); for (const component of components) { protobufSerializer.serialize(component); } const time = performance.now() - start; console.log(`\\n=== 大量小组件性能测试 ===`); console.log(`组件数量: ${componentCount}`); console.log(`总时间: ${time.toFixed(2)}ms`); console.log(`平均每组件: ${(time / componentCount).toFixed(4)}ms`); console.log(`每秒处理: ${Math.floor(componentCount / (time / 1000))} 个组件`); expect(time).toBeLessThan(10000); // 不超过10秒 expect(time / componentCount).toBeLessThan(2); // 每个组件不超过2ms }); }); });