-
Notifications
You must be signed in to change notification settings - Fork 9.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize mono runtime #5469
Comments
I was thinking about giving this a try, but I'm not sure what
@javiercn was there a particular set of actions you had in mind, or just executing a large portion of the existing demos? |
@drewdelano Thanks for your interest. We don't yet have a final plan for how to know what to strip out from The approach mentioned by @javiercn above is really a description of a proof-of-concept form of optimization I did a while ago. It's not a totally realistic approach, since in reality you can't enumerate every possible code path. If you have any clever ideas about how this could be make to work reliably that would definitely be interesting. If you have time to investigate things in this area, it would be great to find out what we can about how the payload size of |
@SteveSandersonMS I'll take a look at it this weekend. The two approaches I see are:
|
That's great to hear. I'll be interested in what you find! As for making optimisations that could be built into the product, we'd probably need to be able to reason about why a particular thing is legit to strip out (as in, why we believe it's never going to be used in anyone's app, e.g., because it's some code specific to running on Win32 or macOS which isn't applicable on WebAssembly). Observing that something happens not to be used during a particular test pass is interesting and can guide us towards knowing what to remove, but on its own wouldn't be enough of a guarantee that it's safe to remove in all cases. |
Wasabi didn't work, sadly. It just results in an "Aw, Snap!" page in Chrome. I moved on from there to a more manual approach:
This is a very hacky function that always writes a breadcrumb (0xdeadbeef) + 0xff at offset just past our breadcrumb + the function number offset. If a function WAS called then there should be 0xff at it's offset; otherwise, it should be 0. There's probably a way better way to do this, but I was having difficulty understanding the WASM memory model. Expand this, if you get something like this error: expected 2 arguments, got 1 (func (;instr;) (type 1) (param i32)It means the types have shifted at the top of the wat file you you'll need to update the type. Scroll to the top of the file and find the one that takes a single i32 parameter and returns nothing like this:
Then update the
This adds two instructions to each function: a const of the function offset + a call to our instrumentation function
This is also pretty hacky. I basically scan through the entire memory space available to the Blazor app (around 128 MB worth) until I find the deadbeef breadcrumb and write that out. Once I had that I update the mono.js again to set All of this yields some pretty high level stats, but I plan to drill into them more next weekend: Now I just need a way to figure out which WASM func corresponds to which mono method 🤔 @SteveSandersonMS any idea if there's anything like symbol information for the mono binaries? |
That's really interesting. Thanks for the update, @drewdelano!
@kumpera would be the best person to ask. |
The closest to symbol information is the strings custom section in the debug build of mono.wasm. |
|
For anyone else trying to perform similar steps, I'm following a lot of the steps contained in the "How to upgrade mono" docs: https://github.com/aspnet/Blazor/blob/master/src/mono/HowToUpgradeMono.md I had to add Then I ran across two other interesting switches you can add to the CommonEmccArgs from
But they don't appear to be compatible with each other
|
LINQPad script to turn symbols + wat instructions into something usable: we want both the function offset + number of instructions so we can sort them later
. Updated mono.js to easily sort unused functions by their weight: Configure to show only the top 300 as that's still probably more than we can comfortably work with
. Top 300 results weighted by instruction count: Still need to chase these down in Mono and find out why they aren't being called
. So far it looks like a random bag of stuff that we probably don't use: threading, file system stuff, sockets, some things I'm surprised aren't called (_mono_jit_runtime_invoke, _interp_exec_method_full) and some things that might be called if the sample code changed (atan2f, _memcpy, _ves_icall_System_Globalization_CalendarData_fill_calendar_data). @SteveSandersonMS Does anything else stand out to you? Think I should drill into why those exist in Mono or just try stubbing them and seeing what happens? Or do you think I should try something else? |
@drewdelano the simple way to remove this functions is by changing how mono is built. I'll cook up a sample PR that shows how to do this sort of work on mono. |
Hmm, process is not a good case for enable-minimal, but to replace the unix port with a wasm specific. |
Here's a skeleton commit that sets up the stage to remove a lot of the non-sense platform stuff like process/socket support. kumpera/mono@5a4fcf5 It still requires some work |
I was going to start by testing this concept locally by just removing the instructions for those functions in the wat file and then rebuilding it. Just to test that all of this is actually working. But I agree changing it in mono is probably the best long term goal. |
I got distracted with some other stuff. I should be returning to this next weekend. |
This should be covered as part of #22432. |
We need to figure out what parts of mono.wasm and mono.asm.js we are using and remove everything else.
The original approach is described below.
JS code. On the JS side, track which numbers you receive.
in it will be modified so that it starts by invoking function 115, passing the ID of the caller.
Change the '115' const to whatever else is the ID of your compiled function from step 1.
use the browser debug console to evaluate the list of function IDs that were invoked.
the uncalled functions are replaced with empty stubs.
The text was updated successfully, but these errors were encountered: