Closed Bug 1607784 Opened 6 years ago Closed 5 years ago

High per-function import cost (was: WebAssembly.instantiate is slower by 20x for larger number of imports/exports)

Categories

(Core :: JavaScript: WebAssembly, enhancement, P3)

71 Branch
Desktop
All
enhancement

Tracking

()

RESOLVED FIXED
mozilla78
Tracking Status
firefox78 --- fixed

People

(Reporter: kevin.cheung, Assigned: rhunt)

Details

Attachments

(3 files)

Attached file 35000imports.7z

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0

Steps to reproduce:

  1. Unzip the package
  2. Start a http-server
  3. Run http://localhost:8080/index.html

Actual results:

The time taken for WebAssembly.instantiate takes 165ms while the module with only 2000 imports takes around 8ms. The time taken for the module with the larger number of imports/exports is around 20x slower.

The time taken is printed out in the developer console.

Expected results:

The duration taken for WebAssembly.instantiate should be similar to the case with a smaller number of imports/exports.

Attached file 2000imports.7z

From a previous email discussion: it's not surprising that more imports take longer (there's some inherently O(n) stuff to do, where n is the number of imports), but from the measurements Kevin is reporting, it sounds like we're taking ~4us per import, which seems to leave some possible room for optimization.

Component: Untriaged → Javascript: WebAssembly
Product: Firefox → Core
Priority: -- → P3

Repro'd on Mac with Nightly.

Status: UNCONFIRMED → NEW
Ever confirmed: true
OS: Unspecified → All
Hardware: Unspecified → Desktop
Summary: WebAssembly.instantiate is slower by 20x for larger number of imports/exports → High per-function import cost (was: WebAssembly.instantiate is slower by 20x for larger number of imports/exports)

Saw some potential improvements we could make to instantiation and was pointed to this issue. I've taken a profile on Nightly OSX [1].

Some notes.

There's two instantiation events. One is synchronous and is taking about ~270ms. The other is the asynchronous and is taking 198ms + 40ms for the actual scheduled work. For both of these modules there is a large amount of both imports and exports.

The async instantiation is taking 148ms to create the export object. 89ms to JS_FreezeObject it, due to triggering a GC when defining a property. 36ms in getting exported functions. And 12ms in just defining the properties. Getting the import values is taking 41ms with nearly all of it (39ms) spent in property lookup.

The sync instantiation is interesting. Getting the import values here takes 139ms and nearly all of it is in property lookup, which is actually executing script as an import module is a Proxy object. Creating the export object is very similar to the async instantiation.

I think there's some work we can avoid in getting import values in the non-proxy case. Will experiment with that a bit.

As for creating the export object, I'm not sure what we can do. We're already lazy with exported wasm functions, I wonder if being even more lazy and not defining properties until accessed could help here. That, of course, would depend on if the application doesn't access all exports.

[1] https://perfht.ml/2Llvejr

Profiles indicate that JS_FreezeObject can be expensive for large exports
objects. It looks like properties are re-allocated. It would be better to
just build the exports object correctly the first time. In the attached
test-case to this bug, this commit dropped instantiation time from 160ms
to 70ms.

According to MDN,

An object is frozen if and only if it is not extensible, all its properties are non-configurable, and all its data properties (that is, properties which are not accessor properties with getter or setter components) are non-writable.

We can accomplish this by changing the JSPROP_FLAG used for each data property
and marking the object as non-extensible at the end.

Assignee: nobody → rhunt
Status: NEW → ASSIGNED

I've attached an improvement to our instantiation code that should help out here.

I also investigated changing how we store the module import section to allow us to do property lookup of imports[module] once for every import that shares the same module name. This turned into a very large change and gave a very meager improvement, so I've dropped it for now.

Pushed by rhunt@eqrion.net: https://hg.mozilla.org/integration/autoland/rev/ea5b26e729f1 Avoid JS_FreezeObject when creating wasm exports object. r=lth
Status: ASSIGNED → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla78
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: