[Webkit-unassigned] [Bug 246009] New: Object.entries() is 1.5x slower in JSC compared to V8

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Tue Oct 4 00:28:20 PDT 2022


https://bugs.webkit.org/show_bug.cgi?id=246009

            Bug ID: 246009
           Summary: Object.entries() is 1.5x slower in JSC compared to V8
           Product: WebKit
           Version: WebKit Nightly Build
          Hardware: Unspecified
                OS: Unspecified
            Status: NEW
          Severity: Normal
          Priority: P2
         Component: JavaScriptCore
          Assignee: webkit-unassigned at lists.webkit.org
          Reporter: jarred at jarredsumner.com

Created attachment 462781

  --> https://bugs.webkit.org/attachment.cgi?id=462781&action=review

Launch_bun_2022-10-03_23.22.34_2576143F.trace.zip

I've attached an Instruments trace and sampling profiler output of using Rollup.js to bundle the "@babel/standalone" npm package. End-to-end, it runs about 1.6x slower in JSC (bun) compared to V8 (node). Nearly all the time is spent in JSC. 

I think it's _mostly_ because of Object.entries() (which is why the issue is titled about Object.entries()). Rollup seems to use Object.entries() in their code a _lot_. In @babel/standalone's case, Object.entries() is called 550,000 times. For larger objects, Object.entries() is around 1.5x slower than in V8 (microbenchmark). It looks like ObjectKeys exists in DFGSpeculateJIT64.cpp but ObjectEntries and ObjectValues do not. Maybe adding it as a JIT operation would help? I don't know if that's the whole story though. It feels like there's a side effects tracking thing that would enable skipping some of the PropertyTable::find lookups, maybe? 

```
❯ bun /Users/jarred/Code/bun/bench/snippets/object-entries.mjs
cpu: Apple M1 Max
runtime: bun 0.1.14 (arm64-darwin)

benchmark                    time (avg)             (min … max)       p75       p99      p995
--------------------------------------------------------------- -----------------------------
Object.entries(26 keys)    1.27 µs/iter     (1.21 µs … 1.99 µs)   1.28 µs   1.99 µs   1.99 µs
Object.keys(26 keys)     515.77 ns/iter (477.57 ns … 628.68 ns) 526.63 ns 617.05 ns 628.68 ns
Object.entries(2 keys)   132.46 ns/iter (125.25 ns … 205.22 ns) 127.54 ns 194.48 ns 196.87 ns
Object.keys(2 keys)        4.68 ns/iter   (4.12 ns … 219.59 ns)   4.42 ns   7.48 ns  10.22 ns
```

```
❯ node /Users/jarred/Code/bun/bench/snippets/object-entries.mjs
cpu: Apple M1 Max
runtime: node v18.9.1 (arm64-darwin)

benchmark                    time (avg)             (min … max)       p75       p99      p995
--------------------------------------------------------------- -----------------------------
Object.entries(26 keys)  830.02 ns/iter   (803.19 ns … 1.07 µs) 821.85 ns   1.07 µs   1.07 µs
Object.keys(26 keys)     327.72 ns/iter (319.58 ns … 421.81 ns) 329.03 ns 400.85 ns 421.81 ns
Object.entries(2 keys)    98.28 ns/iter  (96.05 ns … 452.63 ns)  97.19 ns  105.5 ns 108.87 ns
Object.keys(2 keys)       13.36 ns/iter   (10.75 ns … 76.29 ns)   15.3 ns  17.92 ns  21.13 ns

```


-

Benchmark:

```
import { bench, run } from "../../node_modules/mitata/src/cli.mjs";

const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
  e: 5,
  f: 6,
  g: 7,
  h: 8,
  i: 9,
  j: 10,
  k: 11,
  l: 12,
  m: 13,
  n: 14,
  o: 15,
  p: 16,
  q: 17,
  r: 18,
  s: 19,
  t: 20,
  u: 21,
  v: 22,
  w: 23,
  x: 24,
  y: 25,
  z: 26,
};

bench("Object.entries(26 keys)", () => {
  var k;
  for (let [key, value] of Object.entries(obj)) {
    value = key;
  }
  return k;
});

bench("Object.keys(26 keys)", () => {
  var k;
  for (let [key, value] of Object.keys(obj)) {
    value = key;
  }
  return k;
});

bench("Object.entries(2 keys)", () => {
  var k;
  for (let [key, value] of Object.entries({ a: 1, b: 2 })) {
    value = key;
  }
  return k;
});

bench("Object.keys(2 keys)", () => {
  var k;
  for (let item of Object.keys({ a: 1, b: 2 })) {
  }
  return k;
});

await run();
```

Sampling profiler output:

Sampling rate: 100.000000 microseconds. Total samples: 19077
Top functions as <numSamples  'functionName#hash:sourceID'>
  4028    'include#<nil>:5'
  1552    'parseNode#<nil>:5'
  1299    '#<nil>:5'
  1089    'entries#<nil>:4294967295'
   979    'includeCallArguments#<nil>:5'
   809    'create#<nil>:4294967295'
   656    'hasEffects#<nil>:5'
   606    'arrayIteratorNextHelper#<nil>:7'
   568    'NodeBase#<nil>:5'
   547    '#<nil>:4294967295'
   506    'bind#<nil>:5'
   495    'render#<nil>:5'
Sampling rate: 100.000000 microseconds. Total samples: 19077
Tier breakdown:
-----------------------------------
LLInt:                   184  (0.964512%)
Baseline:                935  (4.901190%)
DFG:                    3991  (20.920480%)
FTL:                   10469  (54.877601%)
js builtin:              862  (4.518530%)
Wasm:                      0  (0.000000%)
Host:                    559  (2.930230%)
RegExp:                  115  (0.602820%)
C/C++:                     0  (0.000000%)
Unknown Frame:             4  (0.020968%)
Unknown Executable:     2820  (14.782198%)
Hottest bytecodes as <numSamples   'functionName#hash:JITType:bytecodeIndex'>
  1089    'entries#<nil>:None:<nil>'
  1001    'include#<nil>:FTL:bc#33'
   809    'create#<nil>:None:<nil>'
   575    'parseNode#<nil>:FTL:bc#218'
   547    '#<nil>:None:<nil>'
   443    'parseNode#<nil>:FTL:bc#479'
   411    'Set#<nil>:None:<nil>'
   404    'include#<nil>:FTL:bc#107'
   363    'include#<nil>:FTL:bc#296'
   337    'include#<nil>:FTL:bc#93'
   280    'arrayIteratorNextHelper#<nil>:FTL:bc#122'
   272    'include#<nil>:FTL:bc#54'
   251    'arrayIteratorNextHelper#<nil>:FTL:bc#58'
   221    'includeCallArguments#<nil>:FTL:bc#59'
   206    'includeProperties#<nil>:FTL:bc#59'
   127    'Map#<nil>:None:<nil>'
   117    'getEntities#<nil>:FTL:bc#180'
   111    'include#<nil>:FTL:bc#0'
   107    'parseModule#<nil>:None:<nil>'
   106    'values#<nil>:None:<nil>'
   106    'parseNode#<nil>:FTL:bc#760'
    95    'includeCallArguments#<nil>:DFG:bc#201'
    90    'include#<nil>:FTL:bc#138'
    87    'getEntities#<nil>:FTL:bc#76'
    84    'includeCallArguments#<nil>:FTL:bc#0'
    81    'bind#<nil>:FTL:bc#262'
    81    'delete#<nil>:None:<nil>'
    81    'include#<nil>:FTL:bc#196'
    77    '#<nil>:FTL:bc#0'
    75    'createScope#<nil>:FTL:bc#11'
    73    'include#<nil>:FTL:bc#27'
    73    'include#<nil>:FTL:<nil>'
    72    '/^(?:break|case|catch|continue|debugger|default|do|else|finally|for|function|if|return|switch|throw|try|var|while|with|null|true|false|instanceof|typeof|void|delete|new|in|this|const|class|extends|export|import|super)$/#<nil>:RegExp:<nil>'
    72    'bind#<nil>:FTL:bc#65'
    71    'includeCallArguments#<nil>:FTL:<nil>'
    71    'includeProperties#<nil>:FTL:bc#19'
    70    'include#<nil>:DFG:bc#54'
    66    'includeProperties#<nil>:FTL:bc#70'
    65    'includeUnknownTest#<nil>:DFG:bc#22'
    65    'include#<nil>:FTL:bc#229'

-- 
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20221004/6e8eb883/attachment-0001.htm>


More information about the webkit-unassigned mailing list