String.charAt performance regression
Reported by
thex...@gmail.com,
Oct 5 2017
|
||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36 Steps to reproduce the problem: https://jsperf.com/indexof-vs-charat In Chrome stable I get these results: indexOf 954,240,572 charAt 966,070,635 And in Canary (63 and 62) these results are: indexOf 956,494,938 charAt 270,937,162 (72% slower) I do understand that using jsperf.com isn't very scientific, but hopefully the reason for this can be found. What is the expected behavior? charAt is faster than indexOf What went wrong? charAt is slower than indexOf Did this work before? N/A Chrome version: 63.0.3233.0 Channel: canary OS Version: 10.0 Flash Version:
,
Oct 6 2017
I'm attaching a simplified test.html. Expected: approximately same times displayed in all tests (100ms) charCodeAt 106 ms charAt 105 ms charAt + if 106 ms indexOf 104 ms Observed: "charAt + if" takes several times longer than other tests (390 - 700ms) charCodeAt 106 ms charAt 105 ms charAt + if 390 ms indexOf 104 ms * Can't bisect chromium snapshots because the issue is not observed there. * The issue is not observed in incognito window in Chrome Canary * The issue disappears for one browser session when v8-cache-options flag is cycled: disable chrome://flags/#v8-cache-options and restart enable chrome://flags/#v8-cache-options and restart run test.html
,
Oct 9 2017
Able to reproduce the issue on windows 10, mac os 10.12.6 and ubuntu 14.04 using M61 #61.0.3163.100 and M63 #63.0.3236.0 as per comment #2. As per comment #2 , the issue disappears when we refersh the page and hence unable to bisect the issue. Marking it as untraiged , so that it would get addressed by respective team . Thanks!
,
Oct 10 2017
,
Oct 10 2017
This seems to be highly dependent on specific dead code elimination, since the values aren't really used. Here's a simplified test case that runs in d8 and where we also don't use any of the computed values.
=============< bench-string-char-at.js >============================
if (typeof console === 'undefined') console = {log:print};
const N = 1e8;
const TESTS = [];
(function() {
var string = 'xhdhdfhdfhdfjfjfgjgf';
TESTS.push(
function charCodeAt() {
for (var i = 0; i < N; i++) {
var result = string.charCodeAt(0);
}
},
function charAt() {
for (var i = 0; i < N; i++) {
var result = string.charAt(0);
}
},
function charAtWithIf() {
for (var i = 0; i < N; i++) {
if (string.charAt(0) === 'x') {}
}
},
function indexOf() {
for (var i = 0; i < N; i++) {
var result = string.indexOf('x');
}
},
function empty() {
for (var i = 0; i < N; i++) { }
}
);
})();
function test(fn) {
var result;
result = fn();
return result;
}
test(x => x);
for (var j = 0; j < TESTS.length; ++j) {
test(TESTS[j]);
}
for (var j = 0; j < TESTS.length; ++j) {
var startTime = Date.now();
test(TESTS[j]);
console.log(TESTS[j].name + ':', (Date.now() - startTime), 'ms.');
}
====================================================================
Running this with V8 6.1 and ToT I get:
====================================================================
$ ./d8-6.1.534.15 bench-string-char-at.js
charCodeAt: 81 ms.
charAt: 80 ms.
charAtWithIf: 81 ms.
indexOf: 80 ms.
empty: 81 ms.
$ out/Release/d8 bench-string-char-at.js
charCodeAt: 81 ms.
charAt: 80 ms.
charAtWithIf: 80 ms.
indexOf: 81 ms.
empty: 80 ms.
====================================================================
As you can see the optimizing compiler eliminates all the code in the loop and effectively turns it into an empty loop. So this test doesn't really measure indexOf vs. charAt. The fact that you get different results sometimes probably means that the tiering up decisions vary, which happens. For example when the VM decides to optimize while the loop is running (via so-called OSR), it'll not be able to eliminate all the dead code always.
|
||||
►
Sign in to add a comment |
||||
Comment 1 by schenney@chromium.org
, Oct 6 2017