Very slow performance of numeric getters / setters
Reported by
wojciech...@gmail.com,
Nov 27
|
||||||
Issue description
UserAgent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.72 Safari/537.36
Steps to reproduce the problem:
I'm using Object.defineProperty to define getters and setters on prototypes of my classes. When I create numeric getters setters (so I can access my objects like `obj[0]`), their performance of accessing the fields is about 100 times slower than if I would name the fields using letters, like 'i0' and accessed them using `obj['i0']`.
Use the following code (coffeescript) to reproduce the problem
```
class Test
constructor: (@array) ->
Object.defineProperty Test.prototype, '0', get: -> @array[0]
Object.defineProperty Test.prototype, '1', get: -> @array[1]
Object.defineProperty Test.prototype, '2', get: -> @array[2]
Object.defineProperty Test.prototype, 'i0', get: -> @array[0]
Object.defineProperty Test.prototype, 'i1', get: -> @array[1]
Object.defineProperty Test.prototype, 'i2', get: -> @array[2]
arr = new Test (new Float32Array [7,8,9])
for i in [0 ... 10]
console.log "----- #{i} -----"
t1 = performance.now()
x = 0
for i in [0...1000000] by 1
x += arr[0]
x -= arr[1]
x *= arr[2]
t2 = performance.now()
console.log "numeric", (t2-t1)
t1 = performance.now()
x = 0
for i in [0...1000000] by 1
x += arr['i0']
x -= arr['i1']
x *= arr['i2']
t2 = performance.now()
console.log "string", (t2-t1)
```
RESULTS:
numeric: 450 ms
string: 4.2 ms
What is the expected behavior?
The performance of numeric getters should be the same as performance of string getters.
What went wrong?
I've observed performance slowdown of 100x factor.
Did this work before? N/A
Chrome version: 69.0.3497.72 Channel: stable
OS Version: Gentoo
Flash Version:
I'm terrified :O
,
Nov 27
,
Nov 27
,
Dec 3
wojciech.danilo@ Thanks for the issue. Able to reproduce this issue on Mac OS 10.13.6,Windows 10 and Ubuntu 17.10 on the latest Stable 70.0.3538.110 and latest Canary 73.0.3629.0 as per comment #1. This is a Non-Regression issue as this behavior is observed from M-60 chrome builds. Attached is the screen shot for reference. Hence marking this as Untriaged for further updates from Dev. Thanks..
,
Dec 4
,
Jan 15
"This is a Non-Regression issue as this behavior is observed from M-60 chrome builds." https://jsperf.com/es5-getters-setters-versus-getter-setter-methods/18 history suggests that it _is_ a regression. Between M48 and M57 performance dropped by an order of magnitude. The latest revision of this benchmark was on 2016-2-8, by which time M48 already existed. Hope this may be helpful in tracking down the cause of the issue.
,
Jan 15
re 6, using the same test.html bisected to https://chromium.googlesource.com/v8/v8/+log/98d2ed87..aaf1b5c3 Suspecting 4c41d007d932ed6eba7514f2d4e44def61cd5fb8 = crrev.com/1697153002 Landed in 50.0.2652.0 via r375485
,
Jan 15
cc Toon re. bisect in #7
,
Jan 15
Note, #6-#7 is probably a sub-issue about the string name getter slowdown in Chrome 50 whereas the initial report is about a numeric name getter being slow, which was that way since at least Chrome 5 where Object.defineProperty was added.
,
Jan 16
(6 days ago)
I don't think that CL has anything to do with this since that's about speeding up adding *data* properties.
I think you're interpreting JSPerf wrongly; as is often the case with microbenchmarks through a complex runner like jsperf. I presume that something with the runner possibly in combination with the optimizing compiler is now not kicking in in a way that seems fast on the resulting graph. E.g., if you run the following without JSPerf:
function test() {
var obj = {
_prop: 0,
get prop() {
return this._prop;
},
set prop(value) {
this._prop = value;
},
getProp: function() {
return this._prop;
},
setProp: function(value) {
this._prop = value;
}
};
var a = 0;
var s1 = Date.now();
for (let i = 0; i < 100000000; i++) {
a += obj.prop;
}
print(Date.now() - s1);
a = 0;
var s2 = Date.now();
for (let i = 0; i < 100000000; i++) {
a += obj.prop;
}
print(Date.now() - s2);
}
test();
You get roughly the same results for both (slightly slower for the second, but that's just due to other side effects, and not because getters are actually slower).
Numeric getters have never been inlined in the optimizing compiler since non-default-data-properties always cause the object to go in dictionary mode. At that point we lose all guarantees and the optimizing compiler can't do anything but access the property through dynamic lookup, whereas the data properties are simple array accesses. Even inline caches have worse performance because they need to do a dictionary lookup.
As mentioned by others before, this is working as it always has.
,
Yesterday
(36 hours ago)
re 10, I can confirm this. Although, I had to change `print` to `console.log`, as the former literally brings up the print dialog :) I get 1983ms and 2005ms, respectively in Chrome 71.0.3578.98 and about the same performance in Safari. But it only takes 61ms and 60ms in Firefox 64.0.2, even if I change the value of `_prop` from zero to some other number and console.log the resulting sum (which is correct). Probably some other optimization on their part, not related to getter performance, but still noteworthy, I think. |
||||||
►
Sign in to add a comment |
||||||
Comment 1 by woxxom@gmail.com
, Nov 271.6 KB
1.6 KB View Download