Slow wasm compared to nodejs 14: anyref boxing and table operations are slow
Categories
(Core :: JavaScript: WebAssembly, defect, P3)
Tracking
()
People
(Reporter: amirouche, Unassigned)
References
(Depends on 1 open bug, Blocks 1 open bug)
Details
Attachments
(1 file, 2 obsolete files)
270.00 KB,
application/x-tar
|
Details |
User Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0
Steps to reproduce:
I created a wasm module and benchmarked it with jsshell nightly (1304 ms) and nodejs14 (245 ms). jsshell performs much less
Actual results:
jsshell nightly is slow.
Expected results:
jsshell is as fast or faster than nodejs
Reporter | ||
Comment 1•4 years ago
|
||
All the code can be found at https://git.sr.ht/~amirouche/xp-web-assembly
Comment 2•4 years ago
|
||
There are also lots of "out of line" returns conversions too. Looks like they are taking some of the time: the function returns number values, but wasm expects reference, so slow boxing is happening.
Comment 3•4 years ago
|
||
Blocking the Slow vcalls bug for now; revisit when some of those fixes have landed, and/or profile to see if there are inefficiencies in the JS/wasm conversion paths.
Updated•3 years ago
|
Updated•3 years ago
|
Updated•3 years ago
|
Comment 4•3 years ago
|
||
Current results on my development system (Linux x64): SpiderMonkey 11.4s, node16 7.9s, still quite a large difference. I'll attach an archive of the cleaned-up test case. See the Makefile for more.
Comment 5•3 years ago
|
||
Comment 6•3 years ago
|
||
Updated archive, this removes spurious differences between the JS and Node versions.
Updated•3 years ago
|
Comment 7•3 years ago
|
||
No evidence of indirect calls being an important problem here.
Comment 8•3 years ago
|
||
Table operations (probably mostly on table<externref>) and externref aka "anyref" boxing are very hot:
3.98% js js [.] JS::WeakCache<JS::GCHashSet<js::WeakHeapPtr<js::Shape*>, js::InitialShapeHasher, js::SystemAllocPolicy> >::lookupForAdd ◆
3.94% js js [.] js::wasm::Instance::tableGet ▒
3.32% js js [.] js::wasm::Table::fillAnyRef ▒
3.11% js js [.] js::wasm::Instance::tableSet ▒
2.29% js js [.] js::InternalBarrierMethods<JSObject*, void>::postBarrier ▒
1.87% js js [.] js::SharedShape::getInitialShape ▒
1.81% js js [.] js::NativeObject::create ▒
1.70% js js [.] js::NewObjectWithGivenTaggedProto ▒
1.55% js js [.] BoxValue_Anyref ▒
1.54% js [JIT] tid 339227 [.] 0x0000272b6aeef3e2 ▒
1.35% js js [.] js::wasm::BoxAnyRef ▒
1.30% js [JIT] tid 339227 [.] 0x0000272b6aeef3f5 ▒
1.20% js [JIT] tid 339227 [.] 0x0000272b6aeef5e9 ▒
1.11% js js [.] js::AllocateObject<(js::AllowGC)1> ▒
1.10% js [JIT] tid 339227 [.] 0x0000272b6aeef3ce ▒
1.03% js [JIT] tid 339227 [.] 0x0000272b6aedf0d3 ▒
1.00% js [JIT] tid 339227 [.] 0x0000272b6aeef3b2 ▒
Here, the hash table lookup, the getInitialShape, the NativeObject::create, the NewObjectWithGivenTaggedProto, both box methods, and AllocateObject are all related to boxing - totalling about 13%. The anyref boxes can probably be streamlined a lot, they were hastily implemented so that we could experiment.
Table access is generally slow at the moment. Here it's mostly anyref tables. Ryan was trying to optimize that recently but ran into problems with the write barrier, but this suggests that it may be worth it to try again.
In the future, a lot of code compiled from higher-level languages may have this type of profile.
Updated•3 years ago
|
Updated•3 years ago
|
Comment 9•3 years ago
|
||
As Yury notes above, BoxValue_Anyref is the root of the callout boxing path that is taken when wasm expects a reference but JS returns something that is not.
Updated•1 year ago
|
Description
•