第14.3章:着色器性能分析

性能分析是着色器优化的基础。本教程将深入讲解如何系统性地分析着色器性能,识别瓶颈并制定优化策略。

🎯 学习目标

  • 掌握着色器性能分析的方法和工具
  • 学会识别和定位性能瓶颈
  • 理解GPU性能指标和优化目标
  • 建立完整的性能监控体系

📊 性能分析基础

GPU性能指标体系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
// GPU性能分析器
class GPUPerformanceProfiler {
private gl: WebGLRenderingContext | WebGL2RenderingContext;
private queryExtension: any;
private frameMetrics: FrameMetrics[] = [];
private shaderMetrics: Map<string, ShaderMetrics> = new Map();

interface FrameMetrics {
frameNumber: number;
frameTime: number;
gpuTime: number;
drawCalls: number;
triangles: number;
vertices: number;
textureBinds: number;
stateChanges: number;
shaderSwitches: number;
overdrawRatio: number;
fillrate: number;
memoryUsage: MemoryUsage;
timestamp: number;
}

interface ShaderMetrics {
name: string;
compileTime: number;
complexity: ShaderComplexity;
usage: ShaderUsage;
performance: ShaderPerformance;
optimizationSuggestions: string[];
}

interface ShaderComplexity {
vertexInstructions: number;
fragmentInstructions: number;
textureReads: number;
mathOperations: number;
branchingComplexity: number;
registerPressure: number;
}

interface ShaderUsage {
timesUsed: number;
totalPixelsShaded: number;
totalVerticesProcessed: number;
averageInstanceCount: number;
}

interface ShaderPerformance {
averageGPUTime: number;
peakGPUTime: number;
averageFillrate: number;
bottleneckType: 'vertex' | 'fragment' | 'bandwidth' | 'none';
efficiency: number; // 0-1
}

interface MemoryUsage {
totalAllocated: number;
textureMemory: number;
bufferMemory: number;
framebufferMemory: number;
availableMemory: number;
}

constructor(gl: WebGLRenderingContext | WebGL2RenderingContext) {
this.gl = gl;
this.initializeProfiler();
}

private initializeProfiler(): void {
// 尝试获取时间查询扩展
this.queryExtension = this.gl.getExtension('EXT_disjoint_timer_query_webgl2') ||
this.gl.getExtension('EXT_disjoint_timer_query');

if (this.queryExtension) {
console.log('✅ GPU时间查询扩展可用');
} else {
console.warn('⚠️ GPU时间查询扩展不可用,将使用替代方法');
}

this.startFrameMonitoring();
}

private startFrameMonitoring(): void {
let frameCount = 0;
const startTime = performance.now();

const measureFrame = () => {
const currentTime = performance.now();
const frameTime = currentTime - (this.lastFrameTime || currentTime);
this.lastFrameTime = currentTime;

// 收集帧指标
this.collectFrameMetrics(frameCount++, frameTime);

requestAnimationFrame(measureFrame);
};

requestAnimationFrame(measureFrame);
}

private collectFrameMetrics(frameNumber: number, frameTime: number): void {
const metrics: FrameMetrics = {
frameNumber: frameNumber,
frameTime: frameTime,
gpuTime: this.measureGPUTime(),
drawCalls: this.getDrawCallCount(),
triangles: this.getTriangleCount(),
vertices: this.getVertexCount(),
textureBinds: this.getTextureBindCount(),
stateChanges: this.getStateChangeCount(),
shaderSwitches: this.getShaderSwitchCount(),
overdrawRatio: this.measureOverdraw(),
fillrate: this.calculateFillrate(),
memoryUsage: this.getMemoryUsage(),
timestamp: performance.now()
};

this.frameMetrics.push(metrics);

// 保持最近100帧的数据
if (this.frameMetrics.length > 100) {
this.frameMetrics.shift();
}

// 每30帧分析一次性能
if (frameNumber % 30 === 0) {
this.analyzePerformance();
}
}

private measureGPUTime(): number {
if (!this.queryExtension) {
return -1; // 无法测量
}

// 这里实现GPU时间查询
// WebGL的时间查询是异步的,需要特殊处理
return 0; // 简化示例
}

private measureOverdraw(): number {
// 通过渲染统计估算overdraw
const canvas = this.gl.canvas as HTMLCanvasElement;
const totalPixels = canvas.width * canvas.height;
const shadedPixels = this.estimateShadedPixels();

return shadedPixels / totalPixels;
}

private calculateFillrate(): number {
// 计算填充率(像素/秒)
const canvas = this.gl.canvas as HTMLCanvasElement;
const pixelsPerFrame = canvas.width * canvas.height * this.measureOverdraw();
const frameTime = this.getAverageFrameTime();

return frameTime > 0 ? (pixelsPerFrame / frameTime) * 1000 : 0;
}

private analyzePerformance(): void {
const recentMetrics = this.frameMetrics.slice(-30);
const analysis = this.performBottleneckAnalysis(recentMetrics);

if (analysis.bottleneck !== 'none') {
console.log(`⚠️ 性能瓶颈检测: ${analysis.bottleneck}`);
console.log('🔧 优化建议:', analysis.suggestions);
}
}

private performBottleneckAnalysis(metrics: FrameMetrics[]): BottleneckAnalysis {
const avgGPUTime = metrics.reduce((sum, m) => sum + m.gpuTime, 0) / metrics.length;
const avgFrameTime = metrics.reduce((sum, m) => sum + m.frameTime, 0) / metrics.length;
const avgOverdraw = metrics.reduce((sum, m) => sum + m.overdrawRatio, 0) / metrics.length;
const avgDrawCalls = metrics.reduce((sum, m) => sum + m.drawCalls, 0) / metrics.length;

let bottleneck: 'cpu' | 'gpu' | 'bandwidth' | 'fillrate' | 'drawcalls' | 'none' = 'none';
const suggestions: string[] = [];

// GPU限制分析
if (avgGPUTime > avgFrameTime * 0.8) {
if (avgOverdraw > 3.0) {
bottleneck = 'fillrate';
suggestions.push('减少overdraw,优化深度测试');
suggestions.push('简化fragment shader复杂度');
} else {
bottleneck = 'gpu';
suggestions.push('优化着色器算法复杂度');
suggestions.push('减少纹理采样次数');
}
}

// CPU限制分析
if (avgFrameTime - avgGPUTime > avgFrameTime * 0.3) {
bottleneck = 'cpu';
suggestions.push('减少draw call数量');
suggestions.push('优化状态切换');
}

// Draw call瓶颈
if (avgDrawCalls > 1000) {
bottleneck = 'drawcalls';
suggestions.push('使用实例化渲染');
suggestions.push('合并渲染批次');
}

return { bottleneck, suggestions };
}

public generatePerformanceReport(): PerformanceReport {
const recentMetrics = this.frameMetrics.slice(-60); // 最近60帧

if (recentMetrics.length === 0) {
return this.getEmptyReport();
}

const report: PerformanceReport = {
summary: this.generateSummary(recentMetrics),
frameAnalysis: this.analyzeFrames(recentMetrics),
shaderAnalysis: this.analyzeShaders(),
memoryAnalysis: this.analyzeMemory(recentMetrics),
recommendations: this.generateRecommendations(recentMetrics),
timestamp: Date.now()
};

return report;
}

private generateSummary(metrics: FrameMetrics[]): PerformanceSummary {
const frameTime = metrics.map(m => m.frameTime);
const gpuTime = metrics.map(m => m.gpuTime).filter(t => t >= 0);

return {
averageFPS: 1000 / (frameTime.reduce((a, b) => a + b) / frameTime.length),
averageFrameTime: frameTime.reduce((a, b) => a + b) / frameTime.length,
averageGPUTime: gpuTime.length > 0 ? gpuTime.reduce((a, b) => a + b) / gpuTime.length : -1,
minFPS: 1000 / Math.max(...frameTime),
maxFPS: 1000 / Math.min(...frameTime),
frameTimeVariance: this.calculateVariance(frameTime),
averageDrawCalls: metrics.reduce((sum, m) => sum + m.drawCalls, 0) / metrics.length,
averageTriangles: metrics.reduce((sum, m) => sum + m.triangles, 0) / metrics.length,
averageOverdraw: metrics.reduce((sum, m) => sum + m.overdrawRatio, 0) / metrics.length
};
}

public startShaderProfiling(shaderName: string): void {
const startTime = performance.now();

// 记录着色器开始使用
if (!this.shaderMetrics.has(shaderName)) {
this.shaderMetrics.set(shaderName, {
name: shaderName,
compileTime: 0,
complexity: this.analyzeShaderComplexity(shaderName),
usage: { timesUsed: 0, totalPixelsShaded: 0, totalVerticesProcessed: 0, averageInstanceCount: 0 },
performance: { averageGPUTime: 0, peakGPUTime: 0, averageFillrate: 0, bottleneckType: 'none', efficiency: 1.0 },
optimizationSuggestions: []
});
}

const metrics = this.shaderMetrics.get(shaderName)!;
metrics.usage.timesUsed++;
}

private analyzeShaderComplexity(shaderName: string): ShaderComplexity {
// 这里需要实际的着色器源码分析
// 简化示例
return {
vertexInstructions: 50,
fragmentInstructions: 100,
textureReads: 3,
mathOperations: 20,
branchingComplexity: 2,
registerPressure: 0.6
};
}
}

interface BottleneckAnalysis {
bottleneck: 'cpu' | 'gpu' | 'bandwidth' | 'fillrate' | 'drawcalls' | 'none';
suggestions: string[];
}

interface PerformanceReport {
summary: PerformanceSummary;
frameAnalysis: FrameAnalysis;
shaderAnalysis: ShaderAnalysisReport;
memoryAnalysis: MemoryAnalysisReport;
recommendations: string[];
timestamp: number;
}

interface PerformanceSummary {
averageFPS: number;
averageFrameTime: number;
averageGPUTime: number;
minFPS: number;
maxFPS: number;
frameTimeVariance: number;
averageDrawCalls: number;
averageTriangles: number;
averageOverdraw: number;
}

🔍 着色器复杂度分析

着色器指令分析器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// 着色器指令分析器
class ShaderInstructionAnalyzer {
private instructionCosts: Map<string, InstructionCost> = new Map();

interface InstructionCost {
aluCost: number;
textureCost: number;
bandwidthCost: number;
registerPressure: number;
category: 'math' | 'texture' | 'control' | 'memory';
}

interface ShaderAnalysisResult {
totalInstructions: number;
aluInstructions: number;
textureInstructions: number;
controlInstructions: number;
estimatedCycles: number;
registerUsage: number;
complexityScore: number;
optimizationOpportunities: OptimizationOpportunity[];
}

interface OptimizationOpportunity {
type: 'reduce_alu' | 'reduce_texture' | 'reduce_branching' | 'reduce_precision' | 'vectorize';
description: string;
impact: 'high' | 'medium' | 'low';
implementation: string;
}

constructor() {
this.initializeInstructionCosts();
}

private initializeInstructionCosts(): void {
// ALU指令成本
this.instructionCosts.set('add', { aluCost: 1, textureCost: 0, bandwidthCost: 0, registerPressure: 0.1, category: 'math' });
this.instructionCosts.set('mul', { aluCost: 1, textureCost: 0, bandwidthCost: 0, registerPressure: 0.1, category: 'math' });
this.instructionCosts.set('div', { aluCost: 4, textureCost: 0, bandwidthCost: 0, registerPressure: 0.2, category: 'math' });
this.instructionCosts.set('sqrt', { aluCost: 3, textureCost: 0, bandwidthCost: 0, registerPressure: 0.2, category: 'math' });
this.instructionCosts.set('sin', { aluCost: 8, textureCost: 0, bandwidthCost: 0, registerPressure: 0.3, category: 'math' });
this.instructionCosts.set('cos', { aluCost: 8, textureCost: 0, bandwidthCost: 0, registerPressure: 0.3, category: 'math' });
this.instructionCosts.set('pow', { aluCost: 12, textureCost: 0, bandwidthCost: 0, registerPressure: 0.4, category: 'math' });

// 纹理指令成本
this.instructionCosts.set('texture2D', { aluCost: 1, textureCost: 4, bandwidthCost: 8, registerPressure: 0.2, category: 'texture' });
this.instructionCosts.set('textureCube', { aluCost: 1, textureCost: 6, bandwidthCost: 12, registerPressure: 0.3, category: 'texture' });
this.instructionCosts.set('texture2DLod', { aluCost: 2, textureCost: 6, bandwidthCost: 10, registerPressure: 0.3, category: 'texture' });

// 控制流指令成本
this.instructionCosts.set('if', { aluCost: 2, textureCost: 0, bandwidthCost: 0, registerPressure: 0.1, category: 'control' });
this.instructionCosts.set('for', { aluCost: 3, textureCost: 0, bandwidthCost: 0, registerPressure: 0.2, category: 'control' });
this.instructionCosts.set('discard', { aluCost: 5, textureCost: 0, bandwidthCost: 0, registerPressure: 0.1, category: 'control' });
}

public analyzeShaderSource(vertexSource: string, fragmentSource: string): ShaderAnalysisResult {
console.log('🔍 分析着色器复杂度...');

const vertexAnalysis = this.analyzeShaderStage(vertexSource, 'vertex');
const fragmentAnalysis = this.analyzeShaderStage(fragmentSource, 'fragment');

// 合并分析结果
const result: ShaderAnalysisResult = {
totalInstructions: vertexAnalysis.instructions + fragmentAnalysis.instructions,
aluInstructions: vertexAnalysis.aluInstructions + fragmentAnalysis.aluInstructions,
textureInstructions: vertexAnalysis.textureInstructions + fragmentAnalysis.textureInstructions,
controlInstructions: vertexAnalysis.controlInstructions + fragmentAnalysis.controlInstructions,
estimatedCycles: Math.max(vertexAnalysis.estimatedCycles, fragmentAnalysis.estimatedCycles), // 取最大值
registerUsage: Math.max(vertexAnalysis.registerUsage, fragmentAnalysis.registerUsage),
complexityScore: this.calculateComplexityScore(vertexAnalysis, fragmentAnalysis),
optimizationOpportunities: [
...vertexAnalysis.optimizations,
...fragmentAnalysis.optimizations
]
};

console.log('📊 着色器分析结果:', result);
return result;
}

private analyzeShaderStage(source: string, stage: 'vertex' | 'fragment'): StageAnalysis {
const lines = source.split('\n');
let instructions = 0;
let aluInstructions = 0;
let textureInstructions = 0;
let controlInstructions = 0;
let estimatedCycles = 0;
let registerUsage = 0;
const optimizations: OptimizationOpportunity[] = [];

// 简化的指令分析
for (const line of lines) {
const trimmedLine = line.trim();

// 跳过注释和空行
if (trimmedLine.startsWith('//') || trimmedLine.length === 0) continue;

instructions++;

// 分析指令类型
if (this.containsTextureOperation(trimmedLine)) {
textureInstructions++;
estimatedCycles += 4;
registerUsage += 0.2;

// 检查纹理优化机会
if (this.hasTextureOptimizationOpportunity(trimmedLine)) {
optimizations.push({
type: 'reduce_texture',
description: '可以合并或减少纹理采样',
impact: 'medium',
implementation: '使用atlas纹理或减少采样次数'
});
}
}

if (this.containsMathOperation(trimmedLine)) {
aluInstructions++;
estimatedCycles += this.estimateMathCycles(trimmedLine);
registerUsage += 0.1;

// 检查数学优化机会
if (this.hasMathOptimizationOpportunity(trimmedLine)) {
optimizations.push({
type: 'reduce_alu',
description: '可以简化数学计算',
impact: 'medium',
implementation: '使用查找表或简化算法'
});
}
}

if (this.containsControlFlow(trimmedLine)) {
controlInstructions++;
estimatedCycles += 2;
registerUsage += 0.15;

// 检查分支优化机会
optimizations.push({
type: 'reduce_branching',
description: '可以减少条件分支',
impact: 'high',
implementation: '使用step/lerp函数替代if语句'
});
}
}

return {
instructions,
aluInstructions,
textureInstructions,
controlInstructions,
estimatedCycles,
registerUsage,
optimizations
};
}

private containsTextureOperation(line: string): boolean {
return /texture2D|textureCube|texture2DLod|texture2DProj/.test(line);
}

private containsMathOperation(line: string): boolean {
return /\+|\-|\*|\/|pow|sqrt|sin|cos|tan|normalize|dot|cross|length/.test(line);
}

private containsControlFlow(line: string): boolean {
return /\bif\b|\bfor\b|\bwhile\b|\bdiscard\b/.test(line);
}

private estimateMathCycles(line: string): number {
let cycles = 1; // 基础成本

if (line.includes('pow')) cycles += 12;
else if (line.includes('sin') || line.includes('cos')) cycles += 8;
else if (line.includes('sqrt')) cycles += 3;
else if (line.includes('/')) cycles += 4;
else if (line.includes('normalize')) cycles += 4;

return cycles;
}

private calculateComplexityScore(vertexAnalysis: StageAnalysis, fragmentAnalysis: StageAnalysis): number {
// 复杂度评分(0-100)
const vertexScore = vertexAnalysis.estimatedCycles / 10;
const fragmentScore = fragmentAnalysis.estimatedCycles / 20; // fragment更重要

return Math.min(100, vertexScore + fragmentScore);
}

public generateOptimizationReport(analysis: ShaderAnalysisResult): string {
let report = '🔍 着色器性能分析报告\n';
report += '='.repeat(40) + '\n';
report += `总指令数: ${analysis.totalInstructions}\n`;
report += `ALU指令: ${analysis.aluInstructions}\n`;
report += `纹理指令: ${analysis.textureInstructions}\n`;
report += `控制流指令: ${analysis.controlInstructions}\n`;
report += `预估周期数: ${analysis.estimatedCycles}\n`;
report += `寄存器使用率: ${(analysis.registerUsage * 100).toFixed(1)}%\n`;
report += `复杂度评分: ${analysis.complexityScore.toFixed(1)}/100\n\n`;

if (analysis.complexityScore > 70) {
report += '⚠️ 着色器复杂度较高,建议优化\n\n';
} else if (analysis.complexityScore > 50) {
report += '💡 着色器复杂度中等,可考虑优化\n\n';
} else {
report += '✅ 着色器复杂度良好\n\n';
}

if (analysis.optimizationOpportunities.length > 0) {
report += '🔧 优化建议:\n';
analysis.optimizationOpportunities.forEach((opt, index) => {
report += `${index + 1}. [${opt.impact.toUpperCase()}] ${opt.description}\n`;
report += ` 实现方式: ${opt.implementation}\n\n`;
});
}

return report;
}
}

interface StageAnalysis {
instructions: number;
aluInstructions: number;
textureInstructions: number;
controlInstructions: number;
estimatedCycles: number;
registerUsage: number;
optimizations: OptimizationOpportunity[];
}

📊 实时性能监控

性能监控仪表板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// 实时性能监控仪表板
class PerformanceDashboard {
private profiler: GPUPerformanceProfiler;
private canvas: HTMLCanvasElement;
private ctx: CanvasRenderingContext2D;
private charts: Map<string, PerformanceChart> = new Map();
private isVisible: boolean = false;

interface PerformanceChart {
name: string;
data: number[];
maxDataPoints: number;
color: string;
unit: string;
range: { min: number; max: number };
}

constructor(profiler: GPUPerformanceProfiler) {
this.profiler = profiler;
this.createDashboard();
this.initializeCharts();
this.startRealTimeUpdates();
}

private createDashboard(): void {
// 创建仪表板DOM元素
const dashboard = document.createElement('div');
dashboard.id = 'performance-dashboard';
dashboard.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
width: 400px;
height: 600px;
background: rgba(0, 0, 0, 0.8);
color: white;
font-family: monospace;
font-size: 12px;
padding: 10px;
border-radius: 5px;
z-index: 10000;
display: none;
`;

// 创建画布
this.canvas = document.createElement('canvas');
this.canvas.width = 380;
this.canvas.height = 580;
this.ctx = this.canvas.getContext('2d')!;

dashboard.appendChild(this.canvas);
document.body.appendChild(dashboard);

// 添加切换按钮
const toggleButton = document.createElement('button');
toggleButton.textContent = 'Performance';
toggleButton.style.cssText = `
position: fixed;
top: 10px;
right: 420px;
z-index: 10001;
padding: 5px 10px;
background: #333;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
`;

toggleButton.onclick = () => this.toggleVisibility();
document.body.appendChild(toggleButton);
}

private initializeCharts(): void {
this.charts.set('fps', {
name: 'FPS',
data: [],
maxDataPoints: 100,
color: '#00ff00',
unit: 'fps',
range: { min: 0, max: 120 }
});

this.charts.set('frameTime', {
name: 'Frame Time',
data: [],
maxDataPoints: 100,
color: '#ffff00',
unit: 'ms',
range: { min: 0, max: 50 }
});

this.charts.set('gpuTime', {
name: 'GPU Time',
data: [],
maxDataPoints: 100,
color: '#ff8800',
unit: 'ms',
range: { min: 0, max: 30 }
});

this.charts.set('drawCalls', {
name: 'Draw Calls',
data: [],
maxDataPoints: 100,
color: '#ff0088',
unit: 'calls',
range: { min: 0, max: 1000 }
});

this.charts.set('triangles', {
name: 'Triangles',
data: [],
maxDataPoints: 100,
color: '#8800ff',
unit: 'k',
range: { min: 0, max: 100 }
});

this.charts.set('overdraw', {
name: 'Overdraw',
data: [],
maxDataPoints: 100,
color: '#00ffff',
unit: 'x',
range: { min: 1, max: 5 }
});
}

private startRealTimeUpdates(): void {
setInterval(() => {
if (this.isVisible) {
this.updateCharts();
this.drawDashboard();
}
}, 100); // 10fps更新率
}

private updateCharts(): void {
const report = this.profiler.generatePerformanceReport();
const summary = report.summary;

// 更新图表数据
this.addDataPoint('fps', summary.averageFPS);
this.addDataPoint('frameTime', summary.averageFrameTime);
this.addDataPoint('gpuTime', summary.averageGPUTime > 0 ? summary.averageGPUTime : 0);
this.addDataPoint('drawCalls', summary.averageDrawCalls);
this.addDataPoint('triangles', summary.averageTriangles / 1000);
this.addDataPoint('overdraw', summary.averageOverdraw);
}

private addDataPoint(chartName: string, value: number): void {
const chart = this.charts.get(chartName);
if (chart) {
chart.data.push(value);
if (chart.data.length > chart.maxDataPoints) {
chart.data.shift();
}
}
}

private drawDashboard(): void {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

// 绘制标题
this.ctx.fillStyle = '#ffffff';
this.ctx.font = '16px monospace';
this.ctx.fillText('Performance Dashboard', 10, 25);

// 绘制图表
let yOffset = 50;
const chartHeight = 80;
const chartSpacing = 90;

for (const [name, chart] of this.charts.entries()) {
this.drawChart(chart, 10, yOffset, 360, chartHeight);
yOffset += chartSpacing;
}

// 绘制实时统计
this.drawRealTimeStats(10, yOffset);
}

private drawChart(chart: PerformanceChart, x: number, y: number, width: number, height: number): void {
// 绘制图表背景
this.ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
this.ctx.fillRect(x, y, width, height);

// 绘制图表标题
this.ctx.fillStyle = chart.color;
this.ctx.font = '12px monospace';
this.ctx.fillText(`${chart.name} (${chart.unit})`, x + 5, y - 5);

// 绘制当前值
const currentValue = chart.data[chart.data.length - 1] || 0;
this.ctx.fillText(`${currentValue.toFixed(1)}`, x + width - 50, y - 5);

// 绘制数据线
if (chart.data.length > 1) {
this.ctx.strokeStyle = chart.color;
this.ctx.lineWidth = 2;
this.ctx.beginPath();

for (let i = 0; i < chart.data.length; i++) {
const dataX = x + (i / (chart.maxDataPoints - 1)) * width;
const normalizedValue = (chart.data[i] - chart.range.min) / (chart.range.max - chart.range.min);
const dataY = y + height - (normalizedValue * height);

if (i === 0) {
this.ctx.moveTo(dataX, dataY);
} else {
this.ctx.lineTo(dataX, dataY);
}
}

this.ctx.stroke();
}

// 绘制网格线
this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
this.ctx.lineWidth = 1;
for (let i = 1; i < 4; i++) {
const gridY = y + (i / 4) * height;
this.ctx.beginPath();
this.ctx.moveTo(x, gridY);
this.ctx.lineTo(x + width, gridY);
this.ctx.stroke();
}
}

private drawRealTimeStats(x: number, y: number): void {
const report = this.profiler.generatePerformanceReport();

this.ctx.fillStyle = '#ffffff';
this.ctx.font = '11px monospace';

const stats = [
`Min FPS: ${report.summary.minFPS.toFixed(1)}`,
`Max FPS: ${report.summary.maxFPS.toFixed(1)}`,
`Frame Variance: ${report.summary.frameTimeVariance.toFixed(2)}ms`,
`Memory Usage: ${this.formatMemorySize(report.memoryAnalysis?.totalUsed || 0)}`,
`Texture Memory: ${this.formatMemorySize(report.memoryAnalysis?.textureMemory || 0)}`
];

stats.forEach((stat, index) => {
this.ctx.fillText(stat, x, y + index * 15);
});
}

private formatMemorySize(bytes: number): string {
if (bytes < 1024) return `${bytes}B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
}

private toggleVisibility(): void {
this.isVisible = !this.isVisible;
const dashboard = document.getElementById('performance-dashboard');
if (dashboard) {
dashboard.style.display = this.isVisible ? 'block' : 'none';
}
}

public exportPerformanceData(): string {
const report = this.profiler.generatePerformanceReport();
return JSON.stringify(report, null, 2);
}
}

🎯 性能优化建议生成器

智能优化建议系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// 性能优化建议生成器
class PerformanceOptimizationAdvisor {
private profiler: GPUPerformanceProfiler;
private analyzer: ShaderInstructionAnalyzer;
private knowledgeBase: OptimizationKnowledgeBase;

interface OptimizationSuggestion {
category: 'shader' | 'rendering' | 'memory' | 'cpu';
priority: 'critical' | 'high' | 'medium' | 'low';
title: string;
description: string;
implementation: string;
expectedImprovement: string;
difficulty: 'easy' | 'medium' | 'hard';
codeExample?: string;
}

interface OptimizationKnowledgeBase {
shaderOptimizations: Map<string, OptimizationRule>;
renderingOptimizations: Map<string, OptimizationRule>;
memoryOptimizations: Map<string, OptimizationRule>;
platformSpecificRules: Map<string, OptimizationRule[]>;
}

interface OptimizationRule {
condition: (metrics: any) => boolean;
suggestion: OptimizationSuggestion;
weight: number;
}

constructor(profiler: GPUPerformanceProfiler, analyzer: ShaderInstructionAnalyzer) {
this.profiler = profiler;
this.analyzer = analyzer;
this.initializeKnowledgeBase();
}

private initializeKnowledgeBase(): void {
this.knowledgeBase = {
shaderOptimizations: new Map(),
renderingOptimizations: new Map(),
memoryOptimizations: new Map(),
platformSpecificRules: new Map()
};

// 着色器优化规则
this.knowledgeBase.shaderOptimizations.set('high_alu', {
condition: (analysis) => analysis.aluInstructions > 100,
suggestion: {
category: 'shader',
priority: 'high',
title: '减少ALU指令复杂度',
description: '着色器包含过多的数学运算指令,影响GPU性能',
implementation: '使用查找表替代复杂计算,简化数学公式,使用内置函数',
expectedImprovement: '10-30%性能提升',
difficulty: 'medium',
codeExample: `
// 优化前
float result = pow(sin(x * 3.14159), 2.0) * cos(y * 2.0);

// 优化后
float sinX = sin(x * 3.14159);
float result = sinX * sinX * cos(y * 2.0);
`
},
weight: 0.8
});

this.knowledgeBase.shaderOptimizations.set('excessive_texture_reads', {
condition: (analysis) => analysis.textureInstructions > 8,
suggestion: {
category: 'shader',
priority: 'high',
title: '减少纹理采样次数',
description: '过多的纹理采样会消耗大量带宽和缓存',
implementation: '合并纹理到atlas,使用纹理数组,缓存采样结果',
expectedImprovement: '15-40%性能提升',
difficulty: 'medium',
codeExample: `
// 优化前
vec3 color1 = texture2D(tex1, uv).rgb;
vec3 color2 = texture2D(tex2, uv).rgb;
vec3 color3 = texture2D(tex3, uv).rgb;

// 优化后 - 使用纹理atlas
vec4 packedColors = texture2D(atlasTexture, uv);
vec3 color1 = packedColors.rgb;
vec3 color2 = packedColors.aaa; // 重用alpha通道
`
},
weight: 0.9
});

// 渲染优化规则
this.knowledgeBase.renderingOptimizations.set('high_overdraw', {
condition: (metrics) => metrics.averageOverdraw > 3.0,
suggestion: {
category: 'rendering',
priority: 'critical',
title: '减少过度绘制',
description: '场景存在严重的过度绘制问题,浪费填充率',
implementation: '优化深度排序,启用early-z测试,减少透明物体重叠',
expectedImprovement: '20-50%性能提升',
difficulty: 'medium'
},
weight: 1.0
});

this.knowledgeBase.renderingOptimizations.set('too_many_drawcalls', {
condition: (metrics) => metrics.averageDrawCalls > 500,
suggestion: {
category: 'rendering',
priority: 'high',
title: '减少Draw Call数量',
description: 'Draw Call过多导致CPU瓶颈',
implementation: '使用批处理,实例化渲染,合并网格',
expectedImprovement: '10-25%性能提升',
difficulty: 'easy'
},
weight: 0.7
});
}

public generateOptimizationReport(): OptimizationReport {
console.log('🔍 生成性能优化建议...');

const performanceReport = this.profiler.generatePerformanceReport();
const suggestions: OptimizationSuggestion[] = [];

// 分析着色器优化机会
const shaderSuggestions = this.analyzeShaderOptimizations();
suggestions.push(...shaderSuggestions);

// 分析渲染优化机会
const renderingSuggestions = this.analyzeRenderingOptimizations(performanceReport);
suggestions.push(...renderingSuggestions);

// 分析内存优化机会
const memorySuggestions = this.analyzeMemoryOptimizations(performanceReport);
suggestions.push(...memorySuggestions);

// 按优先级排序
suggestions.sort((a, b) => {
const priorityOrder = { 'critical': 4, 'high': 3, 'medium': 2, 'low': 1 };
return priorityOrder[b.priority] - priorityOrder[a.priority];
});

return {
overallScore: this.calculateOverallScore(performanceReport),
criticalIssues: suggestions.filter(s => s.priority === 'critical').length,
totalSuggestions: suggestions.length,
suggestions: suggestions,
estimatedImprovement: this.estimateOverallImprovement(suggestions),
generatedAt: Date.now()
};
}

private analyzeShaderOptimizations(): OptimizationSuggestion[] {
const suggestions: OptimizationSuggestion[] = [];

// 这里需要实际的着色器分析数据
// 简化示例
const mockAnalysis = {
aluInstructions: 120,
textureInstructions: 10,
controlInstructions: 5
};

for (const [key, rule] of this.knowledgeBase.shaderOptimizations) {
if (rule.condition(mockAnalysis)) {
suggestions.push(rule.suggestion);
}
}

return suggestions;
}

private analyzeRenderingOptimizations(report: PerformanceReport): OptimizationSuggestion[] {
const suggestions: OptimizationSuggestion[] = [];
const metrics = report.summary;

for (const [key, rule] of this.knowledgeBase.renderingOptimizations) {
if (rule.condition(metrics)) {
suggestions.push(rule.suggestion);
}
}

return suggestions;
}

private analyzeMemoryOptimizations(report: PerformanceReport): OptimizationSuggestion[] {
const suggestions: OptimizationSuggestion[] = [];

// 内存使用分析
if (report.memoryAnalysis && report.memoryAnalysis.totalUsed > 512 * 1024 * 1024) {
suggestions.push({
category: 'memory',
priority: 'high',
title: '优化内存使用',
description: '应用程序内存使用过高,可能影响性能',
implementation: '压缩纹理,减少纹理分辨率,释放未使用资源',
expectedImprovement: '减少内存压力,提升稳定性',
difficulty: 'medium'
});
}

return suggestions;
}

private calculateOverallScore(report: PerformanceReport): number {
// 综合性能评分 (0-100)
let score = 100;

const fps = report.summary.averageFPS;
if (fps < 30) score -= 40;
else if (fps < 45) score -= 20;
else if (fps < 55) score -= 10;

const overdraw = report.summary.averageOverdraw;
if (overdraw > 4) score -= 20;
else if (overdraw > 3) score -= 10;
else if (overdraw > 2) score -= 5;

const drawCalls = report.summary.averageDrawCalls;
if (drawCalls > 1000) score -= 15;
else if (drawCalls > 500) score -= 8;

return Math.max(0, score);
}

private estimateOverallImprovement(suggestions: OptimizationSuggestion[]): string {
const criticalCount = suggestions.filter(s => s.priority === 'critical').length;
const highCount = suggestions.filter(s => s.priority === 'high').length;

if (criticalCount > 0) {
return '30-60%性能提升潜力';
} else if (highCount > 2) {
return '15-30%性能提升潜力';
} else if (highCount > 0) {
return '5-15%性能提升潜力';
} else {
return '小幅性能提升';
}
}

public generateOptimizationGuide(suggestion: OptimizationSuggestion): string {
let guide = `# ${suggestion.title}\n\n`;
guide += `**优先级**: ${suggestion.priority.toUpperCase()}\n`;
guide += `**难度**: ${suggestion.difficulty}\n`;
guide += `**预期改善**: ${suggestion.expectedImprovement}\n\n`;
guide += `## 问题描述\n${suggestion.description}\n\n`;
guide += `## 实现方案\n${suggestion.implementation}\n\n`;

if (suggestion.codeExample) {
guide += `## 代码示例\n\`\`\`glsl\n${suggestion.codeExample}\n\`\`\`\n\n`;
}

guide += `## 验证方法\n`;
guide += `1. 实施优化后重新运行性能分析\n`;
guide += `2. 对比优化前后的关键指标\n`;
guide += `3. 在目标设备上进行实际测试\n`;

return guide;
}
}

interface OptimizationReport {
overallScore: number;
criticalIssues: number;
totalSuggestions: number;
suggestions: OptimizationSuggestion[];
estimatedImprovement: string;
generatedAt: number;
}

📝 本章小结

通过本教程,你应该掌握了:

  1. 性能分析基础: 理解GPU性能指标和分析方法
  2. 着色器复杂度分析: 学会评估着色器的计算复杂度
  3. 实时监控: 掌握实时性能监控和可视化技术
  4. 瓶颈识别: 了解如何识别和定位性能瓶颈
  5. 优化建议: 学会生成智能化的性能优化建议

🚀 下一步学习

继续学习开发工具和工作流优化!🛠️✨