NEW 240984
[JSC] Promise/async is about 6x slower than v8
https://bugs.webkit.org/show_bug.cgi?id=240984
Summary [JSC] Promise/async is about 6x slower than v8
Jarred Sumner
Reported 2022-05-26 15:33:16 PDT
Created attachment 459797 [details] safari Running https://github.com/v8/promise-performance-tests in jsc vs v8 reports the following on macOS arm64 with JSC: ❯ fd . --exec bun '{}' Time(doxbee-async-es2017-native): 55.3 ms. Time(doxbee-promises-es2015-native): 60.5 ms. Time(doxbee-async-es2017-babel): 73.4 ms. Time(parallel-promises-es2015-native): 255.8 ms. Time(parallel-async-es2017-babel): 383.9 ms. Time(parallel-async-es2017-native): 414.5 ms. Time(fibonacci-async-es2017-babel): 785.8 ms. Time(fibonacci-async-es2017-native): 1923.3 ms. with V8: ❯ fd . --exec node '{}' Time(doxbee-async-es2017-native): 20.9 ms. Time(doxbee-promises-es2015-native): 26.6 ms. Time(doxbee-async-es2017-babel): 42 ms. Time(parallel-promises-es2015-native): 55.6 ms. Time(parallel-async-es2017-native): 63.1 ms. Time(parallel-async-es2017-babel): 82.7 ms. Time(fibonacci-async-es2017-native): 110.9 ms. Time(fibonacci-async-es2017-babel): 222.6 ms. the bluebird ones were skipped because bun doesn't support node's async_hooks In another microbench, we can run the following in jsc's shell with Mitata (https://github.com/evanwashere/mitata) import {run, bench} from './mitata/src/cli.mjs'; bench("sync", () => {}); bench("async", async () => {}); await run(); That reports: ❯ node a.mjs cpu: Apple M1 Max runtime: node v18.2.0 (arm64-darwin) benchmark time (avg) (min … max) p75 p99 p995 ------------------------------------------------- ----------------------------- sync 320.19 ps/iter (304.1 ps … 258.77 ns) 316.7 ps 358.3 ps 370.8 ps async 57.01 ns/iter (52.72 ns … 122.63 ns) 59.06 ns 107.38 ns 115.63 ns ❯ jsc a.mjs -m cpu: unknown runtime: unknown (unknown) benchmark time (avg) (min … max) p75 p99 p995 ------------------------------------------------- ----------------------------- sync 322.29 ps/iter (300 ps … 15.65 ns) 316.7 ps 387.5 ps 416.6 ps async 369.04 ns/iter (357.71 ns … 519.04 ns) 365.94 ns 476.6 ns 519.04 ns Running this in Safari (attached screenshot) shows async to be about 565 ns/iter, something like 10x slower compared to V8/node Running the https://github.com/v8/promise-performance-tests/blob/master/src/parallel-async-es2017-native.js with Instruments, shows this: https://user-images.githubusercontent.com/709451/170589528-852d693f-94c3-40ab-a460-f697225e150b.png We can see that a lot of time is spent in bookkeeping – preparing to call microtasks, creating JSC::JSMicrotask, destroying JSC::JSMicrotask, writing to handleset, etc
Attachments
safari (46.76 KB, image/png)
2022-05-26 15:33 PDT, Jarred Sumner
no flags
Jarred Sumner
Comment 1 2022-05-26 21:06:38 PDT
If we look at V8's implementation We can see that they don't use a generic JSC::JSMicrotask-like type with a JS implementation. Instead, they have specific types for each job. https://github.com/v8/v8/blob/f32335fea75b7bde495e0800d7f7349253f81a7c/src/builtins/builtins-microtask-queue-gen.cc#L118 They also implement an optimization for resolving promises that skips allocating a temporary promise. https://github.com/v8/v8/blob/f32335fea75b7bde495e0800d7f7349253f81a7c/src/builtins/promise-jobs.tq#L15
Radar WebKit Bug Importer
Comment 3 2022-06-02 15:34:12 PDT
Yusuke Suzuki
Comment 4 2022-06-10 10:35:47 PDT
(In reply to Jarred Sumner from comment #1) > > They also implement an optimization for resolving promises that skips > allocating a temporary promise. > > https://github.com/v8/v8/blob/f32335fea75b7bde495e0800d7f7349253f81a7c/src/ > builtins/promise-jobs.tq#L15 Note that JSC is doing the same thing internally :)
Brent Fulgham
Comment 5 2024-02-26 15:50:32 PST
*** Bug 243472 has been marked as a duplicate of this bug. ***
Note You need to log in before you can comment on or make changes to this bug.