microsoft / clrmd

Microsoft.Diagnostics.Runtime is a set of APIs for introspecting processes and dumps.
MIT License
1.05k stars 255 forks source link

Ability to load heap-snapshot from EDGE/Chrome browser running .NET WASM (Mono, Blazor) #979

Open hakenr opened 2 years ago

hakenr commented 2 years ago

Analyzing the memory of Blazor WebAssembly applications running in the browser is currently a major problem. Any small step towards making such analysis available in ClrMD will be a big improvement for the ecosystem.

We struggle with problems like https://github.com/dotnet/runtime/issues/62054 where without the ability to explore the heap, diagnostics are extremely difficult.

I am able to volunteer to code such a feature if a usable specification is available or someone points me in the right direction.

leculver commented 2 years ago

I'm not sure I'm familiar enough with WASM to help here.

Is the Edge/Chrome WASM interpreter written in C#/.Net? I assume no...but I don't really work in the Blazor space.

If this WASM code is being run and/or interpreted via the .Net Runtime then there would be a set of objects on the heap already for the interpreter and/or objects created for WASM. In which case, ClrMD already does everything it's designed to do. You could inspect those objects and produce the object model to try to debug.

If this WASM code is being run and/or interpreted via Mono, then unfortunately ClrMD can't help here. ClrMD was designed as a .Net runtime specific inspection API. It's designed is tightly coupled to the CLR diagnostics layer, which is not implemented by mono.

If this C# compiled to WASM code doesn't run on the .Net Runtime, then ClrMD is the wrong place to put something to model that interpreter. You could build a library similar to this if there were proper diagnostic APIs exported.

Of course, please feel free to let me know if I've misunderstood something here.

hakenr commented 2 years ago

It used to be mono.wasm in .NET5, now it is dotnet.wasm in NET6. One .NET...

leculver commented 2 years ago

Right, but that doesn't answer the underlying technical question of how this is implemented and how it works. In order to consider how (or even whether) to implement an API that can inspect these objects we have to answer some basic questions about how this is implemented.

What I'm trying to get at is when this crashes, what process is crashing? Presumably chrome (or edge) itself, right? So here's what I'm getting at:

1) When it crashes, is .Net Core loaded into the process, and is that what's interpreting WASM? If so, then there's likely something we can do with ClrMD to help show what memory is leaking.

2) Is it a native implementation of WASM in Chrome/Edge that executes WASM? (I.E. part of the browser itself that loads an executes wasm instead of mono/.net core...which I suspect is the case?) If so then ClrMD is the wrong tool to try to do this. I'm not sure .Net Diagnostics team is even the right place to add that diagnostics, you would need Chrome and/or Edge to help implement diagnostic tools here. Without a .Net runtime involved, there's not tools that we are ramped up to build on the diagnostics side.

3) Is this Mono loaded into edge/chrome interpreting the WASM? If so, then unfortunately ClrMD itself can't help here. ClrMD is a .Net Core library, and it's a .net core library specifically because it was built in ~2010 and is very tightly coupled to the implementation details of the .Net Core runtime which don't exist in mono.

Until we answer the technical question here, there's nothing we can do here. Unfortunately this isn't my area to know which of those things are true. I strongly suspect 2) above is the case, and that this is just the browser implementing the WASM support...but I don't really know for sure. That's why I'm raising the question here.

One .NET...

Yes, we absolutely are one .Net. That doesn't mean we can put every api everywhere. Mono currently does not have robust, out of process coredump/crash dump/live process debugging in the same way that Desktop .Net or .Net Core does, and that's a requirement of putting Mono support into ClrMD.

(For example, where is the ability (using mono apis) to walk up to an arbitrary coredump and run the equivalent of !dumpheap? If that exists and I don't know about it, great! I'll consider building ClrMD to to target Mono. Until then though, I don't have the fundamental building blocks needed to bring ClrMD up on mono.)

Or are you are trying to say "One .NET" for not building ClrMD to target Edge or Chrome's native interpreter implementation? That's not something this API was ever designed to do. We won't, for example, build a ClrMD for C++ BOOST libraries... Or a ClrMD for javascript operating on the DOM of a web browser... Or the C++ based WASM interpreter built into a web browser.... Because that's not what ClrMD is.

ClrMD is a wrapper around a specific .Net private API (mscordac.dll's ISOSDacInterface, IXClr), published publicly so others can build tools on top of that API. ClrMD is not intended to be a "debug everything including C++ implementations of WASM" library.

To be clear, I'm happy to help where I can and if we find that the interpreter in Chrome/Edge is .Net Core then I'm happy to take a closer look here and see if we can build out the tools further. If that's not the case you'd really want to ask Edge or Chrome (or Mono) to build some more robust debugging here. We are certainly one .Net, but that doesn't mean I have the expertise (or even the time) to make every API work everywhere on anything...even though I'd like to.

hakenr commented 2 years ago

Thank you for trying to find a solution to this problem.

What I'm trying to get at is when this crashes, what process is crashing? Presumably chrome (or edge) itself, right?

No, it is the dotnet.wasm "WASM instance" inside browser "VM" which crashes (if GC issue is hit) or just exits with OutOfMemoryException (in regular conditions, when the available memory is exhausted). The browser process itself remains untouched, it just hosting the WASM application as if it was a JavaScript code.

Regarding 1.+2.+3.

It is native implementation of WASM in browser which loads and runs the dotnet.wasm runtime (Mono-based .NET runtime) in VM. Consider it being another port of Mono to "WASM platform" which then loads regular .NET DLLs and executes them by interpreting the MSIL.

Browsers (the F12 tooling) are able to create a "heap snapshot" which includes something like a huge byte-array (ArrayBuffer) of the dotnet.wasm memory managed by the .NET (mono) runtime. It is the memory used for hosting managed objects and the .NET runtime (dotnet.wasm) is aware of the layout/contents of such memory. My dreams were if there is any chance ClrMD or any other tool might be able to load such memory snapshot and able to analyse the .NET heap stored in it.

(In fact I'm looking for any diagnostic approach which would allow me to examine the memory of the .NET application running inside blazor.wasm. Another approach might be a chance to at least self-examine the heap from the .NET application itself running in dotnet.wasm. It does not have to be post-mortem memory snapshot, if there is any chance from user .NET code itself to ask questions like "Give me GC roots of myself.", or somehow traverse the heap to have a chance to get a better view what's happening there when we are fighting the memory-leak.)

Again, thank you for your time discussing the chances for such diagnostics. And BTW I use ClrMD for regular .NET and it is just amazing!