关于 code cache 的一些实验

之前的文章 有说利用 vm.Script 可以实现 Node.js 中的 code cache。这里实验了一下效果。

new vm.Script() 过程并不会全量编译代码

new vm.Script() 后立刻获取 cached data,执行代码,再次获取 cached data,两次得到的结果不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const a = new vm.Script(code, {
produceCachedData: true
});
const before = JSON.stringify(a.createCachedData());

const ctx = {
module: {
exports: {}
}
}
vm.createContext(ctx);
a.runInContext(ctx);

ctx.module.exports.xxx();

const after = JSON.stringify(a.createCachedData());

console.log(before === after); // false

将执行代码后获取到的 cached data 存储下来。下次 vm.Script 时通过 cachedData 参数传入,会发现两次的到的 cached data 结果相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const buffer = new Uint8Array([212,3,222,192,168,214,113, ... ,26,20,20,20,20]);
const a = new vm.Script(code, {
cachedData: buffer,
produceCachedData: true
});
const before = JSON.stringify(a.createCachedData());

const ctx = {
module: {
exports: {}
}
}
vm.createContext(ctx);
a.runInContext(ctx);

ctx.module.exports.xxx();

const after = JSON.stringify(a.createCachedData());

console.log(before === after); // true

提供 buffer 可以显著降低 vm.Script 的耗时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const buffer = new Uint8Array([212,3,222,192,168,214,113, ... ,26,20,20,20,20]);

const now = performance.now();
for (let i = 0; i < 10000; i++) {
new vm.Script(code, {
produceCachedData: true,
cachedData: buffer
});
}
console.log(performance.now() - now);

const now = performance.now();
for (let i = 0; i < 10000; i++) {
new vm.Script(code, {
produceCachedData: true
});
}
console.log(performance.now() - now);

第一部分的耗时要比第二次少很多。

提供 buffer 并不能解决相同函数第一次执行时的长耗时

1
2
3
4
5
6
7
8
const render = ctx.module.exports.render;

render();
for (let i = 0; i < 100; i++) {
const now = performance.now();
render();
console.log(performance.now() - now);
}

哪怕提供了 buffer,打印出来的耗时数据也是这样的:

01.png

是否提供buffer,不影响第一次的耗时很长,说明后续时间的降低不是在于编译,而是 V8 中有运行时优化。

如果能有办法把这部分运行时的优化暂存就好了。