Open Bug 1776131 Opened 3 years ago Updated 8 months ago

wokwi.com - simulations much slower in FF than other browsers

Categories

(Core :: JavaScript Engine: JIT, defect, P3)

Firefox 100
defect

Tracking

()

Performance Impact medium

People

(Reporter: campbell_kerr, Unassigned)

References

(Blocks 2 open bugs)

Details

(Keywords: perf:animation, perf:responsiveness)

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

Steps to reproduce:

https://wokwi.com/projects/287302452979433992

Click the green Play button (Start the simulation)

A performance indicator shows the speed percentage.

Actual results:

A performance indicator shows the speed percentage. For this project my PCs get around 5 to 12% speed in Firefox.

Performance trace is here:

https://share.firefox.dev/3b9Lwf9

I see speeds of double and up to triple that (35% speed) in Edge, Chrome, Vivaldi and Opera on the same PC. Safari on a Mac is also much faster than Firefox on Mac. The performance difference is consistent across other wokwi projects as well.

Tried another PC, a Mac, other browsers etc with same results.

Expected results:

Just surprised it's significantly faster on every other browser. Thanks!

The Bugbug bot thinks this bug should belong to the 'Core::Performance' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Performance
Product: Firefox → Core

The Performance Priority Calculator has determined this bug's performance priority to be P2.

Platforms: [x] Windows [x] macOS [x] Linux [x] Android
Impact on site: Causes noticeable jank
[x] Affects animation smoothness

Performance Impact: --- → P2
Component: Performance → JavaScript Engine

This testcase spends basically 100% of its time in Ion, and yet it's 3x slower than other browsers. This might be a fun optimization exercise!

Status: UNCONFIRMED → NEW
Component: JavaScript Engine → JavaScript Engine: JIT
Ever confirmed: true
Flags: needinfo?(jdemooij)

I took a quick look at this. This is mostly SetIteratorObject overhead: allocating the iterator, calling next() on it, etc. The JITs have some (scalar replacement etc) optimizations for array iterators for example, maybe we could make Map/Set iterator more similar to those. We should also look at function inlining behavior.

Flags: needinfo?(jdemooij)
Severity: -- → S4
Priority: -- → P3

Took a quick look at this to get an idea of its scope.

There are two main pieces to optimizing away an array iterator:

  1. In CreateArrayIterator, we use NewArrayIterator, which becomes an MNewIterator and triggers an attempt at scalar replacement. MNewIterator takes no arguments; instead, the reserved slots in the ArrayIteratorObject are initialized in self-hosted code, where we can see them. We inline CreateArrayIterator into the script containing the for-of loop.
  2. ArrayIteratorNext is marked as an inlinable large function, so we inline it aggressively. The only uses of the MNewIterator are in the body of ArrayIteratorNext, and they are all supported by scalar replacement (guardclass/guardshape, load/storefixedslot).

The obstacles to doing this for Map/Set are:

  1. Creating a Map/SetIteratorObject is more heavy-weight than an ArrayIteratorObject. Compare SetIteratorObject::create to NewArrayIterator. In particular, we allocate a Range and store it in a reserved slot. We might be able to use the same trick of initializing the slots in self-hosted code, but it's a little harder here, because we decide whether the range should be tenured based on whether the iterator object is tenured.
  2. We already transpile the next method to GetNextEntryForIterator, but the codegen for that op expects an actual object, so we'll have to write a new version that can operate with only the range.

Overall, I think it's doable with a bit of refactoring.

You need to log in before you can comment on or make changes to this bug.