New issue
Advanced search Search tips

Issue 908743 link

Starred by 2 users

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Windows , Mac
Pri: 2
Type: Feature



Sign in to add a comment

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
 
A working test case attached below.
Also observed in Firefox.

The string key speed was just as slow before r142179 V8 roll landed in Chrome 21.0.1175.0:
https://chromium.googlesource.com/v8/v8/+log/052b24ac..06e015b4?pretty=fuller

test.html
1.6 KB View Download
Components: -Blink Blink>JavaScript
Labels: Needs-Milestone
Cc: susan.boorgula@chromium.org
Labels: Triaged-ET Target-73 M-73 FoundIn-71 FoundIn-70 FoundIn-73 FoundIn-72 OS-Mac OS-Windows
Status: Untriaged (was: Unconfirmed)
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..
908743-M60.PNG
49.9 KB View Download
Cc: petermarshall@chromium.org
Labels: -Type-Bug Type-Feature
Status: Available (was: Untriaged)
"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.
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
Cc: verwa...@chromium.org
cc Toon re. bisect in #7
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.

Comment 10 by verwa...@chromium.org, 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.

Comment 11 by vita...@gmail.com, 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