Skip to content

Commit 7b648b7

Browse files
committed
split jvm and android profiling
1 parent c199dee commit 7b648b7

File tree

3 files changed

+106
-29
lines changed

3 files changed

+106
-29
lines changed

.cursor/rules/overview_dev.mdc

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,21 @@ Use the `fetch_rules` tool to include these rules when working on specific areas
5353
- `SentryMetricsEvent`, `SentryMetricsEvents`
5454
- `SentryOptions.getMetrics()`, `beforeSend` callback
5555

56-
- **`profiling`**: Use when working with:
57-
- Continuous profiling (`sentry-async-profiler` module)
58-
- `IContinuousProfiler`, `JavaContinuousProfiler`, `AndroidContinuousProfiler`
59-
- `ProfileChunk`, chunk rotation and sending
56+
- **`profiling_jvm`**: Use when working with:
57+
- JVM continuous profiling (`sentry-async-profiler` module)
58+
- `IContinuousProfiler`, `JavaContinuousProfiler`
59+
- `ProfileChunk`, chunk rotation, JFR file handling
6060
- `ProfileLifecycle` (MANUAL vs TRACE modes)
61-
- `profilesSampleRate`, `profilingTracesHz`, `profileLifecycle` options
62-
- Integration with rate limiting, offline caching, scopes
63-
- JFR file handling, async-profiler integration
64-
- Platform differences (JVM vs Android profiling)
61+
- async-profiler integration, ServiceLoader discovery
62+
- Rate limiting, offline caching, scopes integration
63+
64+
- **`profiling_android`**: Use when working with:
65+
- Android profiling (`sentry-android-core`)
66+
- `AndroidContinuousProfiler`, `AndroidProfiler`, `AndroidTransactionProfiler`
67+
- `Debug.startMethodTracingSampling()`, trace files
68+
- Frame metrics, CPU, memory measurement collectors
69+
- `SentryFrameMetricsCollector`, `SpanFrameMetricsCollector`
70+
- App start profiling, `AndroidOptionsInitializer` setup
6571

6672
### Integration & Infrastructure
6773
- **`opentelemetry`**: Use when working with:
@@ -94,4 +100,5 @@ Use the `fetch_rules` tool to include these rules when working on specific areas
94100
- System test/e2e/sample → `e2e_tests`
95101
- Feature flag/addFeatureFlag/flag evaluation → `feature_flags`
96102
- Metrics/count/distribution/gauge → `metrics`
97-
- Profiling/profiler/ProfileChunk/JFR → `profiling`
103+
- JVM profiling/async-profiler/JFR/ProfileChunk → `profiling_jvm`
104+
- Android profiling/AndroidProfiler/frame metrics/method tracing → `profiling_android`
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
alwaysApply: false
3+
description: Android Profiling (sentry-android-core)
4+
---
5+
# Android Profiling
6+
7+
Android profiling lives in `sentry-android-core` and uses `Debug.startMethodTracingSampling()` for trace collection, with additional measurement collectors for frames, CPU, and memory.
8+
9+
## Key Classes
10+
11+
### `AndroidContinuousProfiler`
12+
- Implements `IContinuousProfiler` for continuous profiling across app lifecycle
13+
- Delegates to `AndroidProfiler` for actual trace collection
14+
- 60-second chunk duration (`MAX_CHUNK_DURATION_MILLIS`)
15+
- Platform: "android"
16+
- Maintains `rootSpanCounter` for TRACE mode, `profilerId` and `chunkId` per session/chunk
17+
- Collects measurements via `CompositePerformanceCollector` and `SentryFrameMetricsCollector`
18+
- Thread-safe with `lock` and `payloadLock`
19+
20+
### `AndroidProfiler`
21+
- Low-level wrapper around `Debug.startMethodTracingSampling()`
22+
- Buffer size: 3MB, timeout: 30 seconds (for transaction profiling)
23+
- `start()`: Calls `Debug.startMethodTracingSampling(path, bufferSize, intervalUs)` and registers frame metrics listener
24+
- `endAndCollect()`: Stops tracing, collects measurements, returns `ProfileEndData` with trace file and measurements
25+
26+
### `AndroidTransactionProfiler`
27+
- Implements `ITransactionProfiler` for per-transaction profiling (legacy)
28+
- `start()` / `bindTransaction()` / `onTransactionFinish()` lifecycle
29+
- Returns `ProfilingTraceData` on finish
30+
31+
## Measurement Collectors
32+
33+
- **`SentryFrameMetricsCollector`**: Frame metrics via `Window.OnFrameMetricsAvailableListener`
34+
- Uses `Choreographer` reflection for frame start timestamps
35+
- Tracks slow frames (> expected duration at refresh rate) and frozen frames (> 700ms)
36+
- **`AndroidMemoryCollector`**: Heap (`Runtime`) and native memory (`Debug.getNativeHeapSize()`)
37+
- **`AndroidCpuCollector`**: CPU usage from `/proc/self/stat`
38+
- **`SpanFrameMetricsCollector`**: Per-span frame metrics with interpolation
39+
40+
## Measurements Included in Profile Chunks
41+
42+
| Measurement | Unit | Source |
43+
|---|---|---|
44+
| Slow frame renders | nanoseconds | `SentryFrameMetricsCollector` |
45+
| Frozen frame renders | nanoseconds | `SentryFrameMetricsCollector` |
46+
| Screen frame rates | Hz | `SentryFrameMetricsCollector` |
47+
| CPU usage | percent | `AndroidCpuCollector` |
48+
| Memory footprint | bytes | `AndroidMemoryCollector` (heap) |
49+
| Native memory footprint | bytes | `AndroidMemoryCollector` (native) |
50+
51+
## Configuration
52+
53+
Same base options as JVM profiling (`profilesSampleRate`, `profileLifecycle`, `profilingTracesHz`), plus:
54+
- `profilingTracesDirPath` set automatically from app cache directory
55+
- Frame metrics collector initialized with Android `Context`
56+
- Setup in `AndroidOptionsInitializer.installDefaultIntegrations()`
57+
58+
## Profiling Flow
59+
60+
**Start**: `AndroidContinuousProfiler.start()` -> `AndroidProfiler.start()` -> `Debug.startMethodTracingSampling()` + register frame metrics listener + schedule 60s timeout
61+
62+
**Chunk Rotation** (every 60s): Stop tracing -> collect measurements -> create `ProfileChunk.Builder` with measurements and trace file -> queue in `payloadBuilders` -> restart profiler
63+
64+
**Sending**: `sendChunks()` builds each `ProfileChunk.Builder` and calls `scopes.captureProfileChunk()`
65+
66+
**Lifecycle modes**: Same as JVM - MANUAL (explicit start/stop) and TRACE (`rootSpanCounter` for automatic lifecycle)
67+
68+
## Initialization
69+
70+
In `AndroidOptionsInitializer`:
71+
- `AndroidContinuousProfiler` created with `AndroidProfiler`, `BuildInfoProvider`, `SentryFrameMetricsCollector`
72+
- Profiler may already be running from app start profiling before SDK init
73+
- If already running at init, existing chunk ID is preserved
74+
75+
## Code Locations
76+
77+
- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidContinuousProfiler.java`
78+
- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidProfiler.java`
79+
- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java`
80+
- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidMemoryCollector.java`
81+
- `sentry-android-core/src/main/java/io/sentry/android/core/AndroidCpuCollector.java`
82+
- `sentry-android-core/src/main/java/io/sentry/android/core/SpanFrameMetricsCollector.java`
83+
- `sentry-android-core/src/main/java/io/sentry/android/core/internal/util/SentryFrameMetricsCollector.java`
Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
alwaysApply: false
3-
description: Java SDK Profiling
3+
description: JVM Continuous Profiling (sentry-async-profiler)
44
---
5-
# Java SDK Profiling
5+
# JVM Continuous Profiling
66

7-
The Sentry Java SDK provides continuous profiling through the `sentry-async-profiler` module, which integrates async-profiler for low-overhead CPU profiling.
7+
The `sentry-async-profiler` module integrates async-profiler for low-overhead CPU profiling on JVM.
88

99
## Module Structure
1010

@@ -25,9 +25,10 @@ The Sentry Java SDK provides continuous profiling through the `sentry-async-prof
2525
### `JavaContinuousProfiler` (sentry-async-profiler)
2626
- Wraps native async-profiler library
2727
- Writes JFR files to `profilingTracesDirPath`
28-
- Rotates chunks periodically (`MAX_CHUNK_DURATION_MILLIS`)
28+
- Rotates chunks periodically (`MAX_CHUNK_DURATION_MILLIS`, default 10s)
2929
- Implements `RateLimiter.IRateLimitObserver` for rate limiting
3030
- Maintains `rootSpanCounter` for TRACE mode lifecycle
31+
- Platform: "java", Chunk ID always `EMPTY_ID`
3132

3233
### `ProfileChunk`
3334
- Contains profiler ID (session-level, persists across chunks), chunk ID, JFR file reference
@@ -40,12 +41,11 @@ The Sentry Java SDK provides continuous profiling through the `sentry-async-prof
4041

4142
## Configuration
4243

43-
- **`profilesSampleRate`**: Sample rate (0.0 to 1.0). If set with `tracesSampleRate`, enables transaction profiling. If set alone, enables continuous profiling.
44+
- **`profilesSampleRate`**: Sample rate (0.0 to 1.0)
4445
- **`profileLifecycle`**: `ProfileLifecycle.MANUAL` (default) or `ProfileLifecycle.TRACE`
4546
- **`cacheDirPath`**: Directory for JFR files (required)
4647
- **`profilingTracesHz`**: Sampling frequency in Hz (default: 101)
4748

48-
Example:
4949
```java
5050
options.setProfilesSampleRate(1.0);
5151
options.setCacheDirPath("/tmp/sentry-cache");
@@ -85,7 +85,7 @@ options.setProfileLifecycle(ProfileLifecycle.MANUAL);
8585

8686
## TRACE Mode Lifecycle
8787
- `rootSpanCounter` incremented when sampled root span starts
88-
- `rootSpanCounter` decremented when root span finishes
88+
- `rootSpanCounter` decremented when root span finishes
8989
- Profiler runs while counter > 0
9090
- Allows multiple concurrent transactions to share profiler session
9191

@@ -106,19 +106,6 @@ options.setProfileLifecycle(ProfileLifecycle.MANUAL);
106106
- Sent when SDK comes online, files deleted after successful send
107107
- Profiler can start before SDK initialized - chunks buffered until scopes available (`initScopes()`)
108108

109-
## Platform Differences
110-
111-
### JVM (sentry-async-profiler)
112-
- Native async-profiler library
113-
- Platform: "java"
114-
- Chunk ID always `EMPTY_ID`
115-
116-
### Android (sentry-android-core)
117-
- `AndroidContinuousProfiler` with `Debug.startMethodTracingSampling()`
118-
- Longer chunk duration (60s vs 10s for JVM)
119-
- Includes measurements (frames, memory)
120-
- Platform: "android"
121-
122109
## Extending
123110

124111
Implement `IContinuousProfiler` and `JavaContinuousProfilerProvider`, register in `META-INF/services/io.sentry.profiling.JavaContinuousProfilerProvider`.

0 commit comments

Comments
 (0)