[Javascript Performance] Optimisation and deoptimization
The optimizing compiler optimizes for what it’s seen. If it sees something new, that’s problematic.
Seleting properties has some strange implications on performacne.
We have seen that runing this code, interpertor can optimze js runtime:
const { performance } = require('perf_hooks');
let iterations = 1e7;
const a = 1;
const b = 2;
const add = (x, y) => x + y;
performance.mark('start');
while (iterations--) {
add(a, b);
}
performance.mark('end');
performance.measure('My Special Benchmark', 'start', 'end');
const [ measure ] = performance.getEntriesByName('My Special Benchmark');
console.log(measure);
So what if we do:
performance.mark("start");
while (iterations--) {
add(a, b);
}
add("foo", "bar"); // added this line
performance.mark("end");
So when we call add('foo', 'bar')
we see deoptimizing happens.
If we do:
performance.mark("start");
while (iterations--) {
add(a, b);
}
iterations = 1e7;
while (iterations--) {
add(a, b);
}
performance.mark("end");
We can see the result:
entryType: 'measure',
startTime: 41.05515700019896,
duration: 15.343078000470996,
If we add:
performance.mark("start");
while (iterations--) {
add(a, b);
}
add('foo', 'bar') // add this back
iterations = 1e7;
while (iterations--) {
add(a, b);
}
performance.mark("end");
Result:
entryType: 'measure',
startTime: 40.564633999951184,
duration: 32.49434900004417,
It doubles the runtime from 18ms to 32ms.
If we add:
performance.mark("start");
%NeverOptimizeFunction(add); // add this line
while (iterations--) {
add(a, b);
}
add("foo", "bar");
iterations = 1e7;
while (iterations--) {
add(a, b);
}
performance.mark("end");
Run: node --allow-natives-syntax benchmark.js
We can see the result:
entryType: 'measure',
startTime: 44.788716999813914,
duration: 143.67414100002497,
If we don't allow JS engine to optimize our code, then it would be pretty slow
function add(x, y) {
return x + y;
}
add(1, 2);
%OptimizeFunctionOnNextCall(add);
add(3, '4');
Run: node --trace-opt --trace-deopt --allow-natives-syntax add.js
[manually marking 0x28a977194161 <JSFunction add (sfi = 0x28a97f871b41)> for non-concurrent optimization]
[compiling method 0x28a977194161 <JSFunction add (sfi = 0x28a97f871b41)> (target TURBOFAN) using TurboFan]
[optimizing 0x28a977194161 <JSFunction add (sfi = 0x28a97f871b41)> (target TURBOFAN) - took 0.278, 0.635, 0.037 ms]
[bailout (kind: deopt-soft, reason: Insufficient type feedback for binary operation): begin. deoptimizing 0x28a977194161 <JSFunction add (sfi = 0x28a97f871b41)>, opt id 0, bytecode offset 2, deopt exit 0, FP to SP delta 32, caller SP 0x7ff7b125e810, pc 0x000113c86050]
How does this works?
- We use an interpreter because the optimizing compiler is slow to get started
- Also: it needs some information before it knows what work it can either optimize or skip out on all together
- So, the interpreter starts gathering feedback about what it sees as the function is used.
But what if a string slips in there?
The optimizing compiler optimizes for what it's seen. If it sees something new, that's problematic.
Let's mesure this code:
const { performance } = require("perf_hooks");
let iterations = 1000000;
class Point {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
}
performance.mark("start");
while (iterations--) {
var point = new Point(1, 2, 3);
//point.x = undefined;
//delete point.x;
//point.y = undefined
//delete point.y
//point.z = undefined
//delete point.z
}
performance.mark("end");
performance.measure("My Special Benchmark", "start", "end");
const [measure] = performance.getEntriesByName("My Special Benchmark");
console.log(measure);
Run it to get baseline:
without | point.x = undefined | delete point.x | point.y = undefined | delete point.y | point.z = undefined | delete point.z |
290.2347559928894 | 269.04967099428177 | 709.9430350065231 | 266.5608630031347 | 704.3972899913788 | 267.9879929870367 | 305.1125900000334 |
- Deleting x & y, it is slow
- Deleting z, it is faster
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2021-12-03 [AWS] Using EC2 Roles and Instance Profiles in AWS
2019-12-03 [Algorithm] 122. Best Time to Buy and Sell Stock II
2019-12-03 [ARIA] Create an Accessible Tooltip on a Text Input
2019-12-03 [Algorithm] 121. Best Time to Buy and Sell Stock
2019-12-03 [Go] Filter an Array in Go
2019-12-03 [GO] Remove Elements from a slice in Go
2019-12-03 [Go] Iterate over an Array or Slice in Go