Performance and profiling
This page is integration guidance: the practices that keep map rendering, routing, and navigation responsive, and the readbacks the SDK exposes so you can measure your own integration on your own hardware and scenes. The project publishes no benchmark numbers; any figure you quote should come from your own device and your own route mix.
Construct the SDK once
- Build one
MapSdkobject and register your providers once at startup. Re-registration replaces every slot (including a cached tile slot), so an accidental double registration silently reopens the cache and resets its tuning: register, then tune withsetRasterTileCacheTimeToLive. - Keep a single
MapNavigationControlleraround the lifetime of a trip screen; subscriptions are explicit and cheap, but re-subscribing listeners is wasted work on every frame.
Frame the camera with the contract’s helpers
- Prefer the
fit_boundscamera constructor for route previews and search-result framing. It computes a top-down, north-up camera that keeps the whole box visible inside the insets you give it, instead of a hand-tuned zoom level that breaks on another screen size. - Give it real insets. Route cards, attribution, and sheets are overlays your application owns; the insets tell the camera what the map may not hide. The insets-aware framing is what keeps the destination inside the visible region on every device.
- Read the camera back with the attribute getters (
center,zoomLevel,bearingDegrees,pitchDegrees) when you need to persist or compare a pose; the camera carries no setters, so a new pose is a new constructor call.
Let the render loop stay explicit
- Frames are explicit by design: the platform view drives
drawfrom its own cadence (a display link or choreographer callback). Do not add a second render loop; serialize draws and never calldrawagain while a previous call is still in flight — a draw in flight reports the next frame busy, and the cadence retries it. - Poll
frameSettledin the render pump to skipdrawwhen a re-draw would present the same pixels: true when the camera, overlay list, and location indicator are unchanged and no pending tile pixels remain. This keeps battery cost near zero on a static map. - Read
TileFrameStatisticsfrom every draw. The four readiness counts (present,fallback,deferred,unavailable) always add up to the requested count, so a persistent slice ofdeferredtells you your per-frame fetch budget is the limiter on your network, and a slice ofunavailablepoints at provider refusals rather than slow ones. - Feed gesture deltas through the SDK’s camera seam (pan by pixels, focal-point zoom and rotation) instead of moving the viewport yourself; the SDK clamps zoom and pitch through the camera’s own ranges and holds the focal point exactly.
Size the tile cache deliberately
- Register the tile cache with an absolute byte budget that fits your product (the reference application’s demo budget is 16 MiB for the whole recorded fixture set). The budget is a registration-time fact: retuning it means re-registering.
- Set the tile time-to-live live through
setRasterTileCacheTimeToLive. Imagery-provider terms put a ceiling on what the cache may retain; a request above the ceiling is accepted and the ceiling clamps what is stored. ReadrasterTileCacheTermsto display the effective value, the ceiling, and the default in a settings or diagnostics screen. - Do not set a zero time-to-live; the call is refused because it would expire every entry on capture.
Keep the provider path under your quota
- The provider implementation carries a shared token-bucket rate limiter
and bounded idempotent retries. Treat
RateLimitExhaustedas “retry after the next refill”, not as an error to surface in the UI. - Cache-then-network is the default shape of every provider call, so repeated identical requests inside the time-to-live cost no quota. The tile category defaults to a 30-day time-to-live, the imagery terms ceiling.
- Batch what the contracts batch: the distance matrix answers every origin-destination pair in one call; fetching matrix cells one by one multiplies your request count for the same data.
Use offline where it pays
- The offline routing provider answers routes over a memory-mapped archive with A*; no network round trip. Compile an extract sized to the region your users drive in, not the planet: the compiler is deterministic and the archive is self-describing.
- The routing decorator retries over the offline graph when the online provider fails, so a coverage-limited archive is a graceful degradation, not a failure mode. Its maneuver texts stay honest where the archive carries no street names.
Profile with the SDK’s own readbacks
- Subscribe to diagnostics events at
Infoseverity (orDebugfor frame-path detail). Events stream fire-and-forget from bounded ring buffers, coordinates are scrubbed at the sink, and a slow listener can never slow the SDK. - Drain the backlog with the bounded flush readback from a non-frame context: the flush is synchronous and must stay out of the render path.
- For provider failures, read
latestProviderFailureDiagnosticsafter a suspicious session; the ring carries the contract, method, timestamp, and verbatim failure text for every failed foreign-callback provider call. - Measure on your target device and your real scenes. The SDK reports what it did (tile counts, frame statistics, cache terms); the timing numbers that matter are the ones your profiling run produces.