Skip to content

[sync] implement slow frames event-based grouping and add duration to frozen frames like in RN  #186

@yduartep

Description

@yduartep
  • implement slow frames event-based grouping like in RN
  • add total duration higher than zero of frozen frames in milliseconds.
  • Add configurable thresholds to frame monitoring

Slow Frame Detection

Slow frames are detected using event-based grouping to report user-perceptible jank:

  • Tracks consecutive frames below targetFps as a single "slow frame event"
  • Only counts events lasting ≥50ms (~3 frames at 60fps) to filter noise
  • This prevents reporting normal microsecond variations as slow frames
  • Reports meaningful performance degradation that affects user experience

Frozen Frame Detection

Frozen frames are individual frames exceeding frozenFrameThresholdMs (default 100ms).
These represent severe jank where the app appears unresponsive.

Sends measurements via Faro API:

  • app_refresh_rate: Current refresh rate in FPS
  • app_frames_rate: Number of slow frame events (not individual frames)
  • app_frozen_frame: Number of frozen frames (exceeding frozenFrameThresholdMs)
/**
 * Configuration options for Frame Monitoring instrumentation.
 *
 * These are React Native-specific advanced options. The Flutter SDK uses fixed values
 * for these parameters (not configurable). Defaults here match Flutter's hardcoded values
 * for cross-platform consistency.
 *
 * Note: To enable frame monitoring, set `refreshRateVitals: true` in ReactNativeConfig.
 */
export interface FrameMonitoringOptions {
  /**
   * Target frames per second for slow frame detection.
   * Frames rendering below this threshold are considered "slow".
   * Default: 60 (Flutter SDK hardcoded value)
   */
  targetFps?: number;

  /**
   * Threshold in milliseconds for detecting frozen frames.
   * Frames taking longer than this are considered "frozen".
   * Default: 100ms (Flutter SDK uses 100_000_000 nanoseconds)
   */
  frozenFrameThresholdMs?: number;

  /**
   * Interval in milliseconds for collecting and sending frame metrics.
   * Default: 30000 (30 seconds, aligned with fetchVitalsInterval)
   */
  refreshRatePollingInterval?: number;

  /**
   * Normalized refresh rate for ProMotion displays (120Hz, etc.).
   * Used to normalize frame rates for high-refresh-rate displays to a standard baseline.
   * Default: 60 (Flutter SDK's backendSupportedFrameRate)
   */
  normalizedRefreshRate?: number;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions