digidem / digidem/comapeo-core-react-native
feat(ios): report app peak memory from MetricKit
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 1
- Forks
- 0
- Avg merge
- 8h 24m
- Merged PRs (30d)
- 9
Description
On Android we now report the backend process's memory footprint as Sentry gauges (#249), including rss_peak_bytes — the peak the low-memory killer scores the process on. iOS deliberately emits only the JS-heap gauges: the process-level pair is gated off because Node runs inside the app process there, so any process number would describe the whole app, UI included.
But the whole-app number is still worth having on iOS — the OS kills the app on memory just as Android does — it just has to come from a different source, for two reasons:
-
Node cannot see the right number on iOS. The iOS kill decision ("jetsam") is made on memory footprint — dirty memory plus compressed memory, the figure Xcode's memory gauge shows — not on resident set size. What Node's
process.memoryUsage.rss()reports on iOS is resident size, which falls as the OS compresses pages while the footprint that determines the kill keeps counting them. Under memory pressure, exactly when the number matters, RSS is misleading. Node has no API for footprint. -
It must not share a metric name with the Android backend gauges.
comapeo.backend.rss_bytesmeans "the backend process" on Android. An iOS value under the same name would mean "the whole app", and any cross-platform query would silently mix the two.
Proposal
MetricKit — the iOS framework we already consume for exit reasons in AppExitMetricsCollector — delivers MXMemoryMetric in the same daily payloads, with peakMemoryUsage measured by the OS as actual footprint (the jetsam-relevant quantity), plus averageSuspendedMemory (memory held while backgrounded, which speaks to background survival). No in-process sampling needed.
Wire these through the existing collector as app-level distributions, e.g.:
comapeo.app.peak_memory_bytes— frompeakMemoryUsagecomapeo.app.suspended_memory_bytes— fromaverageSuspendedMemory
They pick up platform / device_class / os_major from the centralised injection added in #250, and pair naturally with the iOS exit reasons delivered in the same payloads — the way comapeo.backend.rss_peak_bytes pairs with comapeo.app.exit.rss_bytes on Android: one says what the app grew to, the other what it died holding.
Implementation notes:
- The iOS bridge currently exposes only
countMetric; adistributionMetricequivalent (same device-attribute injection and scrub) is needed.SentryMetricEmit.kton Android is the shape to mirror. - MetricKit payloads are daily aggregates for the previous day, so these are slower-moving than the Android gauges — fine for fleet percentiles, not for boot-time analysis.
- Caveat to document: the metric describes the whole app, so backend regressions show up diluted by UI memory; the JS-heap gauges remain the backend-specific signal on iOS.
- Consent tier: propose diagnostic, matching the other memory gauges (daily aggregate, names nothing the user did) — needs the same second-opinion review the #249 tier decision got in
docs/BENCHMARKING.md.
Depends on #250 (device-attribute injection in the native bridges).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with AppExitMetricsCollector and the iOS bridge's existing countMetric implementation; compare the requested distributionMetric shape with SentryMetricEmit.kt on Android. Review device-attribute injection from #250 and the consent discussion in docs/BENCHMARKING.md. Done means the two MetricKit memory distributions are emitted with the central attributes and the whole-app caveat is documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ios, kotlin
- Domain
- documentation, mobile-dev, observability
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100