Profiling — introduction
Profile slow code in your app, view a flame graph in the mobile dashboard, and automatically detect performance regressions between releases. Transaction-scoped model — you pick which path to instrument instead of paying for a continuous sampler.
Why profile?
Section titled “Why profile?”Crash monitoring tells you where things crash. Profiling tells you where it’s slow:
- A screen that takes 3 sec to mount but never crashes → invisible to crash monitor, visible with the profiler
- A perf regression after a refactor → cross-release graph that flags the guilty function
- A backend endpoint eating 80 % of CPU under load → flame graph pointing at the function
It’s the performance counterpart to crash monitoring.
3-line architecture
Section titled “3-line architecture”- The SDK collects stack samples during an interval (1 ms by default on Hermes/V8)
- The SDK POSTs the raw blob to
/api/profilesat the end of each profiled transaction - Samples are aggregated into P50/P95/P99 per function × release for the flame graph + cross-release diff
React Native quickstart
Section titled “React Native quickstart”import { Pionne } from '@pionne/react-native';
// Sugar — wrap an entire transactionawait Pionne.profile('CheckoutFlow', async () => { await fetchCart(); await applyDiscount(); await submitOrder();}, { route: '/checkout' });
// Or manual for more controlPionne.startProfile('HomeScreenMount', { route: '/home' });// … render path …const profileId = await Pionne.stopProfile();console.log('Profile shipped:', profileId);startProfile returns false silently if Hermes doesn’t expose the sampler (JSC, some old versions). Your code stays engine-agnostic — no runtime check to write.
Pionne.profile(name, fn, meta?) is the recommended sugar: it guarantees stopProfile is called even if fn throws, and returns whatever fn returns.
JSON wire format
Section titled “JSON wire format”You can POST directly to POST /api/profiles if you want to profile an SDK that doesn’t have a native implementation yet. The backend accepts two formats:
Format produced by Hermes, V8 (--cpu-prof), Chrome DevTools.
{ "name": "CheckoutFlow", "platform": "react_native", "release": "1.4.2", "environment": "production", "route": "/checkout", "duration_ms": 2840, "samples_count": 2840, "sample_interval_us": 1000, "samples": { "traceEvents": [ { "ph": "X", "name": "App.render", "ts": 0, "dur": 1200 }, { "ph": "X", "name": "Cart.fetch", "ts": 1200, "dur": 980 }, { "ph": "X", "name": "Order.submit", "ts": 2180, "dur": 660 } ] }}The aggregator only reads events with ph: "X" (complete events with explicit dur). The B/E (begin/end) pairs are ignored in the MVP.
Format produced by Excimer (PHP), stackcollapse.pl, and any simple pprof transcoder.
{ "name": "OrderController::store", "platform": "php", "release": "1.4.2", "environment": "production", "route": "POST /orders", "duration_ms": 480, "samples_count": 48, "sample_interval_us": 10000, "samples": [ { "stack": "main;App\\Http\\Kernel::handle;App\\Http\\Controllers\\OrderController::store", "weight_us": 320000 }, { "stack": "main;App\\Http\\Kernel::handle;App\\Http\\Controllers\\OrderController::store;App\\Services\\PaymentService::charge", "weight_us": 280000 }, { "stack": "main;App\\Http\\Kernel::handle;App\\Http\\Controllers\\OrderController::store;DB::transaction", "weight_us": 95000 } ]}Each line = one stack (separated by ;) + its inclusive time in microseconds. Easier to generate than Chrome Trace if you start from a homemade sampler.
Auth: header X-Pionne-Token: pio_live_… (same as for /ingest).
Response:
{ "ok": true, "profile_id": 42 }Overhead per platform
Section titled “Overhead per platform”| SDK | Native profiler | Overhead during capture |
|---|---|---|
| RN (Hermes) | HermesInternal.enableSamplingProfiler | 1–3 % CPU |
| Web | Performance.profile() (Chrome only) | 2–5 % CPU |
| Node | V8 inspector | 3–8 % CPU |
| PHP (Excimer) | wall-clock sampler | ~1 % wall-clock |
| Flutter | Dart VM Profiler | 2–5 % CPU |
When the profiler isn’t active → 0 % overhead. That’s the big win of the transaction-scoped model: you only pay the cost on the paths you instrument.
See also
Section titled “See also”- SDK React Native — install + auto-capture
- API Ingest — sister endpoint of
/profiles - Bundle ID Pinning — mobile only, doesn’t apply to profiles uploaded from the backend