I'm using the following to record the frame rate of an application:
let _lastCalledTime;
let _fps;
let _frame = 0;
let _csv = 'Frame,Timestamp,FPS';
const _refreshLoop = () =>
window.requestAnimationFrame((timestamp) => {
if (!_lastCalledTime) {
_lastCalledTime = timestamp;
_fps = 0;
} else {
const delta = (timestamp - _lastCalledTime) / 1000;
_lastCalledTime = timestamp;
_fps = 1 / delta;
}
_csv += `\n${_frame++},${timestamp},${_fps}`;
_refreshLoop();
});
_refreshLoop();
Which is a variation of some code I found here: https://www.growingwiththeweb.com/2017/12/fast-simple-js-fps-counter.html
Every time a frame is rendered, the elapsed time since the last frame is calculated using the timestamp
parameter passed to the callback. This is used to calculate the FPS and the values logged as a CSV.
I have a MacBook and a Raspberry Pi 3, both running at FPS, and I want to calculate the performance of the application. The MacBook reports a very precise value and, once stable, reports a value very close to 60 fps:
Frame | Timestamp (ms) | FPS |
---|---|---|
0 | 188.835 | 0 |
1 | 238.833 | 20.000800032001283 |
2 | 255.499 | 60.00240009600385 |
3 | 272.165 | 60.002400096003754 |
4 | 338.829 | 15.000600024000963 |
5 | 405.493 | 15.000600024000963 |
6 | 422.159 | 60.00240009600385 |
7 | 438.825 | 60.00240009600385 |
8 | 455.765 | 59.03187721369541 |
9 | 472.431 | 60.00240009600385 |
10 | 489.097 | 60.00240009600385 |
11 | 505.763 | 60.00240009600385 |
12 | 522.429 | 60.00240009600385 |
13 | 539.095 | 60.002400096003655 |
14 | 555.761 | 60.00240009600405 |
The Raspberry Pi has a less-precise reading for timestamp
(1 ms) leading to a stable frame rate of 62.5/58.8 fps:
Frame | Timestamp (ms) | FPS |
---|---|---|
0 | 1303 | 0 |
1 | 1394 | 10.989010989010989 |
2 | 1411 | 58.8235294117647 |
3 | 1428 | 58.8235294117647 |
4 | 1444 | 62.5 |
5 | 1461 | 58.8235294117647 |
6 | 1477 | 62.5 |
7 | 1689 | 4.716981132075472 |
8 | 2321 | 1.5822784810126582 |
9 | 2443 | 8.19672131147541 |
10 | 2455 | 83.33333333333333 |
11 | 2487 | 31.25 |
12 | 2505 | 55.55555555555556 |
13 | 2521 | 62.5 |
14 | 2537 | 62.5 |
The bit that is confusing me is that the Raspberry Pi sometimes reports intervals of less than 16 ms, suggesting frame rates of much more than 60 fps, eg:
Frame | Timestamp (ms) | FPS |
---|---|---|
106 | 4378 | 40.00 |
107 | 4380 | 500.00 |
108 | 4397 | 58.82 |
109 | 4412 | 66.67 |
110 | 4428 | 62.50 |
111 | 4450 | 45.45 |
112 | 4462 | 83.33 |
113 | 4478 | 62.50 |
So my question is: how can this be? My initial thought was that multiple callbacks might be being called for the same frame, but in that case they would receive the same value for timestamp
( per the spec ). My two other suspicions are that, either timestamp
is very inaccurate, or requestAnimationFrame()
is not actually locked to the display's refresh rate and is sometimes executing faster.
requestAnimationFrame
(rAF) is not "forced" to be locked to the display refresh rate no. A simple reason for that is that there may very well be no actual "display", eg in an headless browser. Still that browser will need rAF to fire at some interval.
You don't specify which browsers you are testing this on, but Chrome and Firefox will tie rAF to the V-Sync signal when there is one. I'm not sure what they do with adaptive sync monitors (like G-Sync) though. Also to be noted, the first call to rAF from a "non-animated" document, is actually scheduled to fire as soon as possible in both browsers.
Then in WebKit browsers, they don't look at the monitor at all and instead use a simple timer to try to reach 60FPS no matter the actual display rate. (Note that this is true only for rAF, CSS animations are synced to the monitor).
And this is all in agreement with the specs... which leave some leeway to the user-agent as to when it should update the rendering:
A browsing context has a rendering opportunity if the user agent is currently able to present the contents of the browsing context to the user, accounting for hardware refresh rate constraints and user agent throttling for performance reasons, but considering content presentable even if it's outside the viewport.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.