Skip to content

[Draft] Add trimmable typemap OTEL instrumentation#11502

Draft
simonrozsival wants to merge 4 commits into
mainfrom
dev/simonrozsival/typemap-otel-startup
Draft

[Draft] Add trimmable typemap OTEL instrumentation#11502
simonrozsival wants to merge 4 commits into
mainfrom
dev/simonrozsival/typemap-otel-startup

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

Summary

Draft instrumentation PR for trimmable typemap startup and steady-state performance investigation.

This adds:

  • Microsoft.Android.Runtime.TrimmableTypeMap ActivitySource + Meter infrastructure.
  • Startup spans for jnienv.initialize, typemap.data.initialize, typemap.initialize, and native registration.
  • Lookup/activation spans for JNI-name lookups, managed-type lookups, uncached paths, type-manager calls, peer creation, and OnRegisterNatives.
  • Early startup buffering so operations that happen before app-level OTEL listeners exist are replayed as timed spans once OpenTelemetry is configured.
  • duration.us span attributes so we can get microsecond precision instead of relying on Aspire's integer millisecond duration fields.
  • A samples/TypemapOtelAspire AppHost + launcher script that builds, installs, starts samples/HelloWorld, forwards OTLP/HTTP through adb reverse, and passes the Aspire dashboard OTLP API key to the Android app.
  • samples/TypemapOtelAspire/README.md explaining how to run and inspect the data with Aspire.

Findings from local measurements

Tracked separately in #11501.

Local Aspire/OTEL runs showed trimmable typemap data initialization is roughly 2/3 of the JNIEnvInit.Initialize budget:

  • median jnienv.initialize: 99,591 us
  • median typemap.data.initialize: 62,103 us

Related follow-up: #11473 packages ReadyToRun trimmable typemap assemblies. We should rerun these measurements after #11473 lands because missing R2R packaging may inflate the typemap initialization cost.

How to use with Aspire

From samples/TypemapOtelAspire after a local make all:

export PATH="$HOME/.dotnet/tools:$PATH"
ASPIRE_ALLOW_UNSECURED_TRANSPORT=true \
ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL=http://localhost:4318 \
aspire run --detach --non-interactive

Then inspect telemetry with:

aspire describe
aspire otel traces --format Json -n 100
aspire otel spans --format Json -n 500
aspire logs helloworld-android --tail 200

If the dashboard browser UI shows a Blazor circuit error while the CLI still returns traces, clear browser site data/cache for the dashboard URL or open in a private window.

Validation

  • git diff --check
  • bash -n samples/TypemapOtelAspire/run-helloworld-android.sh
  • make all
  • Release/CoreCLR/trimmable HelloWorld build/install/start through the Aspire resource.
  • aspire otel traces --format Json confirmed spans including:
    • jnienv.initialize
    • typemap.data.initialize
    • typemap.initialize
    • typemap.register_native_methods
    • typemap.lookup.*
    • typemap.lookup.*.uncached
    • typemap.type_manager.*
    • typemap.peer.create
    • typemap.on_register_natives

Instrument trimmable typemap startup and lookup operations with ActivitySource and Meter events, add buffered startup span replay for pre-listener operations, and wire the HelloWorld sample to export typemap telemetry through an Aspire AppHost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instrument the existing TypeManager-based LLVM-IR typemap path so JNI-name lookup, uncached native lookup, activation, and proxy creation can be compared directly with trimmable typemap spans. Allow the Aspire sample to switch typemap implementations via HELLOWORLD_ANDROID_TYPEMAP.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival
Copy link
Copy Markdown
Member Author

Updated the draft PR to include LLVM-IR typemap OTEL coverage as well: typemap.llvm.lookup.jni_name, typemap.llvm.lookup.jni_name.uncached, typemap.llvm.activation, and typemap.llvm.proxy.create. The Aspire AppHost now honors HELLOWORLD_ANDROID_TYPEMAP, so the same sample can be launched with HELLOWORLD_ANDROID_TYPEMAP=llvm-ir for direct comparison against trimmable. Local validation with HELLOWORLD_ANDROID_TYPEMAP=llvm-ir produced LLVM spans including jnienv.initialize, typemap.llvm.lookup.jni_name, .uncached, and activation spans.

Break down the LLVM-IR activation and peer creation paths into nested spans so simple startup has enough telemetry for comparison. Capture a 10x LLVM-IR launch summary in the local OTEL data report.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival
Copy link
Copy Markdown
Member Author

Added more detailed LLVM-IR OTEL spans after the first smoke run showed too few events. The LLVM path now breaks activation into nested spans (peek_object, resolve_type, get_parameter_types, get_object_array, constructor_lookup, activate_uninitialized, set_peer_reference, invoke_constructor) and peer creation into class/signature/assignability sub-spans. Rebuilt with make all, relaunched with HELLOWORLD_ANDROID_TYPEMAP=llvm-ir, then ran the app 10x and collected per-run logs/spans under artifacts/llvm-typemap-otel-runs/20260526-130206. Median LLVM span count is now 103.5; median jnienv.initialize is 38,970 us; median typemap.llvm.activation is 987 us; median uncached JNI lookup is 93 us.

Add paired median comparisons for trimmable and LLVM-IR typemap startup spans, showing that the trimmable JNIEnv initialization delta is explained by typemap data initialization.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant