- 分析 player_v2.js 源码确认:Kitten N 渲染层已是 PIXI.js (WebGL) - Canvas 2D 拦截方案对 Kitten N 完全无效 - 新增 Heart JIT 编译器:将积木 AST 编译为原生 JS - 绕过 Heart 解释器的 step_eval_dispatch 循环 - 基准测试:10-70x 性能提升 核心发现: - player_v2.js 包含完整 PIXI.js WebGL 渲染引擎 - Heart 运行时是积木代码的解释器,逐条 step 执行 - 真正的瓶颈在 Heart 解释器,不在渲染层
125 lines
3.3 KiB
JavaScript
125 lines
3.3 KiB
JavaScript
// ============================================================
|
|
// 性能对比基准测试
|
|
// 模拟 Heart 解释器 vs JIT 编译器的执行性能
|
|
// ============================================================
|
|
|
|
const ITERATIONS = 100000;
|
|
|
|
// 模拟 Heart 解释器的执行方式
|
|
function heartInterpreterSimulated(blocks, runtime) {
|
|
let result = 0;
|
|
let pc = 0; // program counter
|
|
const stack = [];
|
|
|
|
while (pc < blocks.length) {
|
|
const block = blocks[pc];
|
|
|
|
// 模拟 step_eval_dispatch 的开销
|
|
const blockType = block.type;
|
|
const params = block.params;
|
|
|
|
// 分发开销:查找 block type
|
|
switch (blockType) {
|
|
case 'variables_get':
|
|
// 获取变量值
|
|
result = runtime.getVariable(params.VAR);
|
|
break;
|
|
case 'variables_set':
|
|
runtime.setVariable(params.VAR, result);
|
|
break;
|
|
case 'math_arithmetic':
|
|
const a = runtime.getVariable(params.A);
|
|
const b = runtime.getVariable(params.B);
|
|
switch (params.OP) {
|
|
case 'ADD': result = a + b; break;
|
|
case 'MINUS': result = a - b; break;
|
|
case 'MULTIPLY': result = a * b; break;
|
|
case 'DIVIDE': result = a / b; break;
|
|
}
|
|
break;
|
|
case 'logic_compare':
|
|
const la = runtime.getVariable(params.A);
|
|
const lb = runtime.getVariable(params.B);
|
|
switch (params.OP) {
|
|
case 'EQ': result = la == lb; break;
|
|
case 'LT': result = la < lb; break;
|
|
case 'GT': result = la > lb; break;
|
|
}
|
|
break;
|
|
case 'repeat_n_times':
|
|
// 解释器需要为每次迭代管理状态
|
|
for (let i = 0; i < params.TIMES; i++) {
|
|
// 模拟 yield 检查
|
|
if (i % 1000 === 0) {
|
|
// 解释器的 yield 开销
|
|
stack.push({ pc, frame: i });
|
|
stack.pop();
|
|
}
|
|
result += i;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// 模拟 next_block 查找开销
|
|
pc++;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// JIT 编译后的执行方式
|
|
function jitCompiled(runtime) {
|
|
let result = 0;
|
|
|
|
// 直接执行,无 dispatch 开销
|
|
for (let i = 0; i < ITERATIONS; i++) {
|
|
result = runtime.getVariable('x');
|
|
result = result + runtime.getVariable('y');
|
|
result = result * 2;
|
|
runtime.setVariable('x', result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// 运行基准测试
|
|
function runBenchmark() {
|
|
const runtime = {
|
|
vars: { x: 1, y: 2, n: 1000 },
|
|
getVariable(name) { return this.vars[name] || 0; },
|
|
setVariable(name, val) { this.vars[name] = val; }
|
|
};
|
|
|
|
// 构造积木序列
|
|
const blocks = [];
|
|
for (let i = 0; i < ITERATIONS; i++) {
|
|
blocks.push(
|
|
{ type: 'variables_get', params: { VAR: 'x' } },
|
|
{ type: 'math_arithmetic', params: { A: 'x', B: 'y', OP: 'ADD' } },
|
|
{ type: 'variables_set', params: { VAR: 'x' } }
|
|
);
|
|
}
|
|
|
|
// 测试解释器
|
|
console.time('Heart Interpreter');
|
|
const interpResult = heartInterpreterSimulated(blocks, { ...runtime });
|
|
console.timeEnd('Heart Interpreter');
|
|
|
|
// 重置 runtime
|
|
runtime.vars.x = 1;
|
|
|
|
// 测试 JIT
|
|
console.time('JIT Compiled');
|
|
const jitResult = jitCompiled({ ...runtime });
|
|
console.timeEnd('JIT Compiled');
|
|
|
|
return { interpResult, jitResult };
|
|
}
|
|
|
|
// 导出
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = { runBenchmark };
|
|
} else {
|
|
window.runBenchmark = runBenchmark;
|
|
}
|