更新性能分析器及更改部分注释

This commit is contained in:
YHH
2025-06-30 20:33:45 +08:00
parent f88a402b0c
commit 992338d924
48 changed files with 3322 additions and 1038 deletions

View File

@@ -0,0 +1,615 @@
import { IECSDebugConfig, IECSDebugData } from '../../types';
import { EntityDataCollector } from './EntityDataCollector';
import { SystemDataCollector } from './SystemDataCollector';
import { PerformanceDataCollector } from './PerformanceDataCollector';
import { ComponentDataCollector } from './ComponentDataCollector';
import { SceneDataCollector } from './SceneDataCollector';
import { WebSocketManager } from './WebSocketManager';
import { Core } from '../../Core';
/**
* 调试管理器
*
* 整合所有调试数据收集器,负责收集和发送调试数据
*/
export class DebugManager {
private config: IECSDebugConfig;
private webSocketManager: WebSocketManager;
private entityCollector: EntityDataCollector;
private systemCollector: SystemDataCollector;
private performanceCollector: PerformanceDataCollector;
private componentCollector: ComponentDataCollector;
private sceneCollector: SceneDataCollector;
private frameCounter: number = 0;
private lastSendTime: number = 0;
private sendInterval: number;
private isRunning: boolean = false;
constructor(core: Core, config: IECSDebugConfig) {
this.config = config;
// 初始化数据收集器
this.entityCollector = new EntityDataCollector();
this.systemCollector = new SystemDataCollector();
this.performanceCollector = new PerformanceDataCollector();
this.componentCollector = new ComponentDataCollector();
this.sceneCollector = new SceneDataCollector();
// 初始化WebSocket管理器
this.webSocketManager = new WebSocketManager(
config.websocketUrl,
config.autoReconnect !== false
);
// 设置消息处理回调
this.webSocketManager.setMessageHandler(this.handleMessage.bind(this));
// 计算发送间隔(基于帧率)
const debugFrameRate = config.debugFrameRate || 30;
this.sendInterval = 1000 / debugFrameRate;
this.start();
}
/**
* 启动调试管理器
*/
public start(): void {
if (this.isRunning) return;
this.isRunning = true;
this.connectWebSocket();
}
/**
* 停止调试管理器
*/
public stop(): void {
if (!this.isRunning) return;
this.isRunning = false;
this.webSocketManager.disconnect();
}
/**
* 更新配置
*/
public updateConfig(config: IECSDebugConfig): void {
this.config = config;
// 更新发送间隔
const debugFrameRate = config.debugFrameRate || 30;
this.sendInterval = 1000 / debugFrameRate;
// 重新连接WebSocket如果URL变化
if (this.webSocketManager && config.websocketUrl) {
this.webSocketManager.disconnect();
this.webSocketManager = new WebSocketManager(
config.websocketUrl,
config.autoReconnect !== false
);
this.webSocketManager.setMessageHandler(this.handleMessage.bind(this));
this.connectWebSocket();
}
}
/**
* 帧更新回调
*/
public onFrameUpdate(deltaTime: number): void {
if (!this.isRunning || !this.config.enabled) return;
this.frameCounter++;
const currentTime = Date.now();
// 基于配置的帧率发送数据
if (currentTime - this.lastSendTime >= this.sendInterval) {
this.sendDebugData();
this.lastSendTime = currentTime;
}
}
/**
* 场景变更回调
*/
public onSceneChanged(): void {
// 场景变更时立即发送一次数据
if (this.isRunning && this.config.enabled) {
this.sendDebugData();
}
}
/**
* 处理来自调试面板的消息
*/
private handleMessage(message: any): void {
try {
switch (message.type) {
case 'capture_memory_snapshot':
this.handleMemorySnapshotRequest();
break;
case 'config_update':
if (message.config) {
this.updateConfig({ ...this.config, ...message.config });
}
break;
case 'ping':
this.webSocketManager.send({
type: 'pong',
timestamp: Date.now()
});
break;
default:
// 未知消息类型,忽略
break;
}
} catch (error) {
// console.error('[ECS Debug] 处理消息失败:', error);
}
}
/**
* 处理内存快照请求
*/
private handleMemorySnapshotRequest(): void {
try {
const memorySnapshot = this.captureMemorySnapshot();
this.webSocketManager.send({
type: 'memory_snapshot_response',
data: memorySnapshot
});
} catch (error) {
this.webSocketManager.send({
type: 'memory_snapshot_error',
error: error instanceof Error ? error.message : '内存快照捕获失败'
});
}
}
/**
* 捕获内存快照
*/
private captureMemorySnapshot(): any {
const scene = Core.scene;
if (!scene) {
throw new Error('没有活跃的场景');
}
const entityList = (scene as any).entities;
if (!entityList?.buffer) {
throw new Error('无法访问实体列表');
}
const timestamp = Date.now();
// 1. 收集基础内存信息
const baseMemoryInfo = this.collectBaseMemoryInfo();
// 2. 收集实体内存统计
const entityMemoryStats = this.collectEntityMemoryStats(entityList);
// 3. 收集组件内存统计
const componentMemoryStats = this.collectComponentMemoryStats(entityList);
// 4. 收集系统内存统计
const systemMemoryStats = this.collectSystemMemoryStats();
// 5. 收集对象池内存统计
const poolMemoryStats = this.collectPoolMemoryStats();
// 6. 收集性能监控器统计
const performanceStats = this.collectPerformanceStats();
return {
timestamp,
version: '2.0',
summary: {
totalEntities: entityList.buffer.length,
totalMemoryUsage: baseMemoryInfo.usedMemory,
totalMemoryLimit: baseMemoryInfo.totalMemory,
memoryUtilization: (baseMemoryInfo.usedMemory / baseMemoryInfo.totalMemory * 100),
gcCollections: baseMemoryInfo.gcCollections,
entityMemory: entityMemoryStats.totalMemory,
componentMemory: componentMemoryStats.totalMemory,
systemMemory: systemMemoryStats.totalMemory,
poolMemory: poolMemoryStats.totalMemory
},
baseMemory: baseMemoryInfo,
entities: entityMemoryStats,
components: componentMemoryStats,
systems: systemMemoryStats,
pools: poolMemoryStats,
performance: performanceStats,
// 保持向后兼容
totalEntities: entityList.buffer.length,
totalMemory: entityMemoryStats.totalMemory,
detailedArchetypes: entityMemoryStats.archetypes
};
}
/**
* 收集基础内存信息
*/
private collectBaseMemoryInfo(): any {
const memoryInfo: any = {
totalMemory: 0,
usedMemory: 0,
freeMemory: 0,
gcCollections: 0,
heapInfo: null
};
try {
if ((performance as any).memory) {
const perfMemory = (performance as any).memory;
memoryInfo.totalMemory = perfMemory.jsHeapSizeLimit || 512 * 1024 * 1024;
memoryInfo.usedMemory = perfMemory.usedJSHeapSize || 0;
memoryInfo.freeMemory = memoryInfo.totalMemory - memoryInfo.usedMemory;
memoryInfo.heapInfo = {
totalJSHeapSize: perfMemory.totalJSHeapSize || 0,
usedJSHeapSize: perfMemory.usedJSHeapSize || 0,
jsHeapSizeLimit: perfMemory.jsHeapSizeLimit || 0
};
} else {
memoryInfo.totalMemory = 512 * 1024 * 1024;
memoryInfo.freeMemory = 512 * 1024 * 1024;
}
// 尝试获取GC信息
if ((performance as any).measureUserAgentSpecificMemory) {
// 这是一个实验性API可能不可用
(performance as any).measureUserAgentSpecificMemory().then((result: any) => {
memoryInfo.detailedMemory = result;
}).catch(() => {
// 忽略错误
});
}
} catch (error) {
// 使用默认值
}
return memoryInfo;
}
/**
* 收集实体内存统计
*/
private collectEntityMemoryStats(entityList: any): any {
const archetypeStats = new Map<string, { count: number; memory: number; entities: any[] }>();
const entitySizeDistribution = new Map<string, number>(); // 按大小范围分布
let totalMemory = 0;
let maxEntityMemory = 0;
let minEntityMemory = Number.MAX_VALUE;
const largestEntities: any[] = [];
for (const entity of entityList.buffer) {
if (!entity || entity.destroyed) continue;
// 生成组件签名
const componentTypes = entity.components ?
entity.components.map((c: any) => c.constructor.name).sort() : [];
const signature = componentTypes.length > 0 ? componentTypes.join(',') : 'Empty';
// 计算实体内存使用
const entityMemory = this.entityCollector.estimateEntityMemoryUsage(entity);
totalMemory += entityMemory;
maxEntityMemory = Math.max(maxEntityMemory, entityMemory);
minEntityMemory = Math.min(minEntityMemory, entityMemory);
// 收集大实体信息
largestEntities.push({
id: entity.id,
name: entity.name || `Entity_${entity.id}`,
memory: entityMemory,
componentCount: componentTypes.length,
componentTypes: componentTypes
});
// 内存大小分布统计
const sizeCategory = this.getMemorySizeCategory(entityMemory);
entitySizeDistribution.set(sizeCategory, (entitySizeDistribution.get(sizeCategory) || 0) + 1);
// 更新原型统计
if (!archetypeStats.has(signature)) {
archetypeStats.set(signature, { count: 0, memory: 0, entities: [] });
}
const stats = archetypeStats.get(signature)!;
stats.count++;
stats.memory += entityMemory;
stats.entities.push({
id: entity.id,
name: entity.name || `Entity_${entity.id}`,
memory: entityMemory,
componentCount: componentTypes.length
});
}
// 排序并限制返回的实体数量
largestEntities.sort((a, b) => b.memory - a.memory);
// 转换原型统计
const archetypes = Array.from(archetypeStats.entries()).map(([signature, stats]) => ({
signature,
count: stats.count,
memory: stats.memory,
averageMemory: stats.memory / stats.count,
percentage: totalMemory > 0 ? (stats.memory / totalMemory * 100) : 0,
entities: stats.entities.sort((a, b) => b.memory - a.memory).slice(0, 5) // 只返回前5个最大的
})).sort((a, b) => b.memory - a.memory);
return {
totalMemory,
entityCount: entityList.buffer.length,
averageEntityMemory: totalMemory / entityList.buffer.length,
maxEntityMemory,
minEntityMemory: minEntityMemory === Number.MAX_VALUE ? 0 : minEntityMemory,
archetypes,
largestEntities: largestEntities.slice(0, 10),
sizeDistribution: Array.from(entitySizeDistribution.entries()).map(([category, count]) => ({
category,
count,
percentage: (count / entityList.buffer.length * 100)
}))
};
}
/**
* 收集组件内存统计
*/
private collectComponentMemoryStats(entityList: any): any {
const componentStats = new Map<string, { count: number; totalMemory: number; instances: any[] }>();
let totalComponentMemory = 0;
for (const entity of entityList.buffer) {
if (!entity || entity.destroyed || !entity.components) continue;
for (const component of entity.components) {
const typeName = component.constructor.name;
const componentMemory = this.entityCollector.calculateObjectSize(component, ['entity']);
totalComponentMemory += componentMemory;
if (!componentStats.has(typeName)) {
componentStats.set(typeName, { count: 0, totalMemory: 0, instances: [] });
}
const stats = componentStats.get(typeName)!;
stats.count++;
stats.totalMemory += componentMemory;
stats.instances.push({
entityId: entity.id,
entityName: entity.name || `Entity_${entity.id}`,
memory: componentMemory
});
}
}
const componentBreakdown = Array.from(componentStats.entries()).map(([typeName, stats]) => ({
typeName,
instanceCount: stats.count,
totalMemory: stats.totalMemory,
averageMemory: stats.totalMemory / stats.count,
percentage: totalComponentMemory > 0 ? (stats.totalMemory / totalComponentMemory * 100) : 0,
largestInstances: stats.instances.sort((a, b) => b.memory - a.memory).slice(0, 3)
})).sort((a, b) => b.totalMemory - a.totalMemory);
return {
totalMemory: totalComponentMemory,
componentTypes: componentStats.size,
totalInstances: Array.from(componentStats.values()).reduce((sum, stats) => sum + stats.count, 0),
breakdown: componentBreakdown
};
}
/**
* 收集系统内存统计
*/
private collectSystemMemoryStats(): any {
const scene = Core.scene;
let totalSystemMemory = 0;
const systemBreakdown: any[] = [];
try {
const entityProcessors = (scene as any).entityProcessors;
if (entityProcessors && entityProcessors.processors) {
for (const system of entityProcessors.processors) {
const systemMemory = this.entityCollector.calculateObjectSize(system);
totalSystemMemory += systemMemory;
systemBreakdown.push({
name: system.constructor.name,
memory: systemMemory,
enabled: system.enabled !== false,
updateOrder: system.updateOrder || 0
});
}
}
} catch (error) {
// 忽略错误
}
return {
totalMemory: totalSystemMemory,
systemCount: systemBreakdown.length,
breakdown: systemBreakdown.sort((a, b) => b.memory - a.memory)
};
}
/**
* 收集对象池内存统计
*/
private collectPoolMemoryStats(): any {
let totalPoolMemory = 0;
const poolBreakdown: any[] = [];
try {
// 尝试获取组件池统计
const { ComponentPoolManager } = require('../../ECS/Core/ComponentPool');
const poolManager = ComponentPoolManager.getInstance();
const poolStats = poolManager.getPoolStats();
for (const [typeName, stats] of poolStats.entries()) {
const poolData = stats as any; // 类型断言
const poolMemory = poolData.maxSize * 32; // 估算每个对象32字节
totalPoolMemory += poolMemory;
poolBreakdown.push({
typeName,
maxSize: poolData.maxSize,
currentSize: poolData.currentSize || 0,
estimatedMemory: poolMemory,
utilization: poolData.currentSize ? (poolData.currentSize / poolData.maxSize * 100) : 0
});
}
} catch (error) {
// 如果无法获取池信息,使用默认值
}
try {
// 尝试获取通用对象池统计
const { Pool } = require('../../Utils/Pool');
const poolStats = Pool.getStats();
for (const [typeName, stats] of Object.entries(poolStats)) {
const poolData = stats as any; // 类型断言
totalPoolMemory += poolData.estimatedMemoryUsage;
poolBreakdown.push({
typeName: `Pool_${typeName}`,
maxSize: poolData.maxSize,
currentSize: poolData.size,
estimatedMemory: poolData.estimatedMemoryUsage,
utilization: poolData.size / poolData.maxSize * 100,
hitRate: poolData.hitRate * 100
});
}
} catch (error) {
// 忽略错误
}
return {
totalMemory: totalPoolMemory,
poolCount: poolBreakdown.length,
breakdown: poolBreakdown.sort((a, b) => b.estimatedMemory - a.estimatedMemory)
};
}
/**
* 收集性能统计信息
*/
private collectPerformanceStats(): any {
try {
const performanceMonitor = (Core.Instance as any)._performanceMonitor;
if (!performanceMonitor) {
return { enabled: false };
}
const stats = performanceMonitor.getAllSystemStats();
const warnings = performanceMonitor.getPerformanceWarnings();
return {
enabled: performanceMonitor.enabled,
systemCount: stats.size,
warnings: warnings.slice(0, 10), // 最多10个警告
topSystems: Array.from(stats.entries() as any).map((entry: any) => {
const [name, stat] = entry;
return {
name,
averageTime: stat.averageTime,
maxTime: stat.maxTime,
samples: stat.executionCount
};
}).sort((a: any, b: any) => b.averageTime - a.averageTime).slice(0, 5)
};
} catch (error: any) {
return { enabled: false, error: error.message };
}
}
/**
* 获取内存大小分类
*/
private getMemorySizeCategory(memoryBytes: number): string {
if (memoryBytes < 1024) return '< 1KB';
if (memoryBytes < 10 * 1024) return '1-10KB';
if (memoryBytes < 100 * 1024) return '10-100KB';
if (memoryBytes < 1024 * 1024) return '100KB-1MB';
return '> 1MB';
}
/**
* 获取调试数据
*/
public getDebugData(): IECSDebugData {
const currentTime = Date.now();
const scene = Core.scene;
const debugData: IECSDebugData = {
timestamp: currentTime,
frameworkVersion: '1.0.0', // 可以从package.json读取
isRunning: this.isRunning,
frameworkLoaded: true,
currentScene: scene?.name || 'Unknown'
};
// 根据配置收集各种数据
if (this.config.channels.entities) {
debugData.entities = this.entityCollector.collectEntityData();
}
if (this.config.channels.systems) {
const performanceMonitor = (Core.Instance as any)._performanceMonitor;
debugData.systems = this.systemCollector.collectSystemData(performanceMonitor);
}
if (this.config.channels.performance) {
const performanceMonitor = (Core.Instance as any)._performanceMonitor;
debugData.performance = this.performanceCollector.collectPerformanceData(performanceMonitor);
}
if (this.config.channels.components) {
debugData.components = this.componentCollector.collectComponentData();
}
if (this.config.channels.scenes) {
debugData.scenes = this.sceneCollector.collectSceneData();
}
return debugData;
}
/**
* 连接WebSocket
*/
private async connectWebSocket(): Promise<void> {
try {
await this.webSocketManager.connect();
// console.log('[ECS Debug] 调试管理器已连接到调试服务器');
} catch (error) {
// console.warn('[ECS Debug] 无法连接到调试服务器:', error);
}
}
/**
* 发送调试数据
*/
private sendDebugData(): void {
if (!this.webSocketManager.getConnectionStatus()) {
return;
}
try {
const debugData = this.getDebugData();
// 包装成调试面板期望的消息格式
const message = {
type: 'debug_data',
data: debugData
};
this.webSocketManager.send(message);
} catch (error) {
// console.error('[ECS Debug] 发送调试数据失败:', error);
}
}
}