🩺
Dr-Dotnet
The goal is to create a profiler that would ease the tracking of common issues in .NET applications such as deadlocks, cpu hotpaths, zombie threads, async hotpaths (stuck tasks), memory leaks.
It is possible to identify some of these issues using today's existing tools, but with some drawbacks:
- Often you have to explicitely look for such issue.
- Such tools rarely have a good user experience. Appart from dotMemory, I find UX considerations to be often left appart.
- In many cases the tracing/profiling has a noticable impact on the runtime and add bias to the profiling results.
The .NET Profiling API is accessible via COM interop (cross-platform thanks to the Platform Adaptation Layer) and allows little overheap profiling compared to other methods while giving a wide range of possibilities for profiling purpose. Perfview uses this API (on top of ETW) however it does it from managed code calling mocked COM objects written in C#. For the project, the idea would be to do it in C++ or even better in Rust (ideally Rust + including CoreCLR headers in kind of a hybrid fashion, if that is possible). Then the offline tooling (UI) can be in C# or any other "productive" language.
Todo
- Manage to initialize at start
- Manage to initialize on attach
- Write profiler POC in rust
- Add a functional build flow (profiler + attacher)
- Figure out what I really want feature-wise
- Should I even consider attach mode? (because of its limitations)
- Should I even consider start mode? (because it is too invasive and implies process restart, which is bad is issue is live)
- Implement IPC through Event Pipe
- Add simple UI client for attaching
- Add simple UI client for setting up on-start profiler
- Create web app profiler UI that can work in headless scenarios (eg. linux servers)
- Have web app profiler work when used as a sidecar docker container
- Use ffidji to have an interface to share profiler specifications between profilers lib and UI
- For each profiler: Name, Guid, Description, Duration, Parameters (blob?)
- Find out analysis format
- What kind of data should it hold? Summary of analysis or should it allow some kind of browsing?
- json? yaml? custom?
Possibilities
- On object allocated with ObjectAllocated
COR_PRF_MONITOR_OBJECT_ALLOCATED
⚠️ - Object reference is moved during garbage collection with MovedReferences
COR_PRF_MONITOR_GC
- Build reference tree after a GC run with ObjectReferences
COR_PRF_MONITOR_GC
- Object instance allocation per class with ObjectsAllocatedByClass
COR_PRF_MONITOR_GC
- Unmanaged code called from managed code
COR_PRF_MONITOR_CODE_TRANSITIONS
⚠️ - Get surviving references after garbage collection
COR_PRF_MONITOR_GC
SurvivingReferences2 - On runtime suspended / resumed
COR_PRF_MONITOR_SUSPENDS
RuntimeSuspendStarted - On garbage collection started / finished
COR_PRF_MONITOR_GC
- On thread created
COR_PRF_MONITOR_THREADS
- On exception thrown
COR_PRF_MONITOR_EXCEPTIONS
- On method enter / leave with SetEnterLeaveFunctionHooks3WithInfo
COR_PRF_MONITOR_ENTERLEAVE
⚠️ - Write to event pipe
- Request stacktrace (per thread)
COR_PRF_ENABLE_STACK_SNAPSHOT
- Annnnd a lot more :p...
COR_PRF_MONITOR_GC
Profiler is initialized on application start
Any flag from COR_PRF_MONITOR enumeration.
Profiler is initialized on attach
Only possible on a subset of COR_PRF_MONITOR enumeration:
COR_PRF_MONITOR_THREADS
COR_PRF_MONITOR_MODULE_LOADS
COR_PRF_MONITOR_ASSEMBLY_LOADS
COR_PRF_MONITOR_APPDOMAIN_LOADS
COR_PRF_ENABLE_STACK_SNAPSHOT
COR_PRF_MONITOR_GC
COR_PRF_MONITOR_SUSPENDS
COR_PRF_MONITOR_CLASS_LOADS
COR_PRF_MONITOR_EXCEPTIONS
COR_PRF_MONITOR_JIT_COMPILATION
COR_PRF_ENABLE_REJIT
Useful Links
- Pavel Yosifovich — Writing a .NET Core cross platform profiler in an hour
- Pavel Yosifovich — DotNext Moscou 2019 Source Code
- Josef Biehler - Create a .NET profiler with the Profiling API
- Mattias Högström - Building a Mixed-Mode Sampling Profiler
- Christophe Nasarre - Start a journey into the .NET Profiling APIs
- Some random COM C++ source code
- Some random COM C++ source code