Add EventPipe interop instrumentation for wrapper lifecycle and GC-bridge reachability - #12258
Add EventPipe interop instrumentation for wrapper lifecycle and GC-bridge reachability#12258jkoritzinsky with Copilot wants to merge 6 commits into
Conversation
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces EventPipe instrumentation across the .NET↔Java interop layer to make wrapper lifecycle and GC-bridge reachability transitions observable in production traces via a new Java.Interop EventSource provider.
Changes:
- Added a new
Java.InteropEventSource (InteropEventSource) with stable event IDs/keywords and a documented payload schema. - Instrumented wrapper creation/release in Java.Interop value managers + Mono.Android runtime, and added GC-bridge reachability transition events with correlation fields.
- Added unit tests (Java.Interop) and runtime-facing tests (Mono.Android) plus documentation for capturing with
dotnet-trace.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/InteropEventSourceRuntimeTests.cs | Runtime tests validating lifecycle events are emitted on-device/in-runtime. |
| src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMapValueManager.cs | Emits wrapper creation events for trimmable typemap value manager paths. |
| src/Mono.Android/Microsoft.Android.Runtime/JavaMarshalRegisteredPeers.cs | Emits wrapper release + GC-bridge reachability events during bridge processing. |
| src/Mono.Android/Android.Runtime/AndroidRuntime.cs | Emits wrapper creation events for AndroidValueManager.CreatePeer. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/InteropEventSourceTests.cs | Unit tests validating EventSource emission and payload shape. |
| external/Java.Interop/src/Java.Interop/PublicAPI.Unshipped.txt | Declares new public API surface for InteropEventSource. |
| external/Java.Interop/src/Java.Interop/Java.Interop/ManagedPeer.cs | Emits JavaWrapperCreated during managed-peer construction from Java. |
| external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.ReflectionJniValueManager.cs | Emits wrapper creation events in reflection-based value manager. |
| external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs | Emits wrapper release events during peer disposal. |
| external/Java.Interop/src/Java.Interop/Java.Interop/InteropEventSource.cs | New provider implementation + event definitions/keywords. |
| external/Java.Interop/Documentation/EventPipeInteropEvents.md | Event catalog, payload schema, and dotnet-trace collection instructions. |
| The .NET ↔ Java interop layer emits EventPipe events through a single provider: | ||
|
|
||
| - **Provider name:** `Java.Interop` | ||
|
|
||
| ## Event catalog | ||
|
|
||
| | Event ID | Event name | Meaning | | ||
| |---|---|---| | ||
| | 1 | `DotNetWrapperCreated` | A managed wrapper for a Java object was created. | | ||
| | 2 | `JavaWrapperCreated` | A Java wrapper for a managed object was created. | | ||
| | 3 | `DotNetWrapperReleasedJavaReference` | A managed wrapper released its Java reference. | | ||
| | 4 | `JavaWrapperReleasedDotNetReference` | A Java wrapper released its managed reference. | | ||
| | 5 | `DotNetObjectOnlyReachableFromJava` | A managed object is only reachable from Java during bridge processing. | | ||
| | 6 | `JavaObjectOnlyReachableFromDotNet` | A Java object is only reachable from .NET during bridge processing. | |
There was a problem hiding this comment.
There is some existing code in here for writing gref/lref logs. It is old and text-based. Does this replace or supplement this?
There was a problem hiding this comment.
I believe this replaces those logs.
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
|
@copilot resolve the merge conflicts in this pull request |
…ava-interop Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
|
This helps — I've been investigating dotnet/runtime#131370 (Android frame drops from the GC bridge) and I think interop visibility is important if we get apps negatively impacted by the bridge. I suspect promotion cost has the potential to get in the way for games / high responsive graphic apps. A couple questions:
The bridge's cost tracks promoted bytes, not peer count — it force-promotes each peer's whole If we add one, these two fields are what would let the two sides join: "this bridge round promoted
I built a probe that has millions of peer registrations over a 40 s run. Each event carries two strings, Repro and scripts: https://github.com/steveisok/android-gcbridge-investigation |
This adds first-class EventPipe visibility into the .NET↔Java interop layer so wrapper lifecycle and cross-runtime reachability transitions can be observed in production traces. The instrumentation covers wrapper creation/release on both sides and GC-bridge reachability state transitions with correlation data.
New interop EventSource provider
Java.InteropDotNetWrapperCreatedJavaWrapperCreatedDotNetWrapperReleasedJavaReferenceJavaWrapperReleasedDotNetReferenceDotNetObjectOnlyReachableFromJavaJavaObjectOnlyReachableFromDotNetWrapper creation instrumentation
.NET wrapper for Java objectevents from:ReflectionJniValueManager.CreatePeerTrimmableTypeMapValueManager.CreatePeerAndroidRuntime.AndroidValueManager.CreatePeerJava wrapper for .NET objectevents from:ManagedPeer.ConstructConstructPeerCorepaths where Java peer references are establishedWrapper release instrumentation
.NET wrapper releases Java referencefrom disposal/finalization paths:JniValueManager.DisposePeerJavaMarshalRegisteredPeers.FinalizePeerJava wrapper releases .NET referencefrom registered-peer removal:JavaMarshalRegisteredPeers.RemovePeerGC-bridge reachability instrumentation
JavaMarshalRegisteredPeersbridge processing:.NET object only reachable from JavaJava object only reachable from .NETcomponentIndex,contextIndex,contextPointer) for trace-side reconstruction.Low-overhead event gating
InteropEventSource.IsEnabled()before payload-heavy work (e.g., Java type resolution) to avoid unnecessary overhead when no listener is attached.API, tests, and docs
InteropEventSource.dotnet-traceusage documentation.