function FrameRateMonitor(options) {
  //>>includeStart('debug', pragmas.debug);
  if (!defined(options) || !defined(options.scene)) {
    throw new DeveloperError("options.scene is required.");
  }
  //>>includeEnd('debug');

  this._scene = options.scene;

  /**
   * Gets or sets the length of the sliding window over which to compute the average frame rate, in seconds.
   * @type {number}
   */
  this.samplingWindow =
    options.samplingWindow ?? FrameRateMonitor.defaultSettings.samplingWindow;

  /**
   * Gets or sets the length of time to wait at startup and each time the page becomes visible (i.e. when the user
   * switches back to the tab) before starting to measure performance, in seconds.
   * @type {number}
   */
  this.quietPeriod =
    options.quietPeriod ?? FrameRateMonitor.defaultSettings.quietPeriod;

  /**
   * Gets or sets the length of the warmup period, in seconds.  During the warmup period, a separate
   * (usually lower) frame rate is required.
   * @type {number}
   */
  this.warmupPeriod =
    options.warmupPeriod ?? FrameRateMonitor.defaultSettings.warmupPeriod;

  /**
   * Gets or sets the minimum frames-per-second that are required for acceptable performance during
   * the warmup period.  If the frame rate averages less than this during any <code>samplingWindow</code> during the <code>warmupPeriod</code>, the
   * <code>lowFrameRate</code> event will be raised and the page will redirect to the <code>redirectOnLowFrameRateUrl</code>, if any.
   * @type {number}
   */
  this.minimumFrameRateDuringWarmup =
    options.minimumFrameRateDuringWarmup ??
    FrameRateMonitor.defaultSettings.minimumFrameRateDuringWarmup;

  /**
   * Gets or sets the minimum frames-per-second that are required for acceptable performance after
   * the end of the warmup period.  If the frame rate averages less than this during any <code>samplingWindow</code> after the <code>warmupPeriod</code>, the
   * <code>lowFrameRate</code> event will be raised and the page will redirect to the <code>redirectOnLowFrameRateUrl</code>, if any.
   * @type {number}
   */
  this.minimumFrameRateAfterWarmup =
    options.minimumFrameRateAfterWarmup ??
    FrameRateMonitor.defaultSettings.minimumFrameRateAfterWarmup;

  this._lowFrameRate = new Event();
  this._nominalFrameRate = new Event();

  this._frameTimes = [];
  this._needsQuietPeriod = true;
  this._quietPeriodEndTime = 0.0;
  this._warmupPeriodEndTime = 0.0;
  this._frameRateIsLow = false;
  this._lastFramesPerSecond = undefined;
  this._pauseCount = 0;

  const that = this;
  this._preUpdateRemoveListener = this._scene.preUpdate.addEventListener(
    function (scene, time) {
      update(that, time);
    },
  );

  this._hiddenPropertyName =
    document.hidden !== undefined
      ? "hidden"
      : document.mozHidden !== undefined
        ? "mozHidden"
        : document.msHidden !== undefined
          ? "msHidden"
          : document.webkitHidden !== undefined
            ? "webkitHidden"
            : undefined;

  const visibilityChangeEventName =
    document.hidden !== undefined
      ? "visibilitychange"
      : document.mozHidden !== undefined
        ? "mozvisibilitychange"
        : document.msHidden !== undefined
          ? "msvisibilitychange"
          : document.webkitHidden !== undefined
            ? "webkitvisibilitychange"
            : undefined;

  function visibilityChangeListener() {
    visibilityChanged(that);
  }

  this._visibilityChangeRemoveListener = undefined;
  if (defined(visibilityChangeEventName)) {
    document.addEventListener(
      visibilityChangeEventName,
      visibilityChangeListener,
      false,
    );

    this._visibilityChangeRemoveListener = function () {
      document.removeEventListener(
        visibilityChangeEventName,
        visibilityChangeListener,
        false,
      );
    };
  }
}
Monitors the frame rate (frames per second) in a {@link Scene} and raises an event if the frame rate is
lower than a threshold.  Later, if the frame rate returns to the required level, a separate event is raised.
To avoid creating multiple FrameRateMonitors for a single {@link Scene}, use {@link FrameRateMonitor.fromScene}
instead of constructing an instance explicitly.

@alias FrameRateMonitor
@constructor

@param {object} [options] Object with the following properties:
@param {Scene} options.scene The Scene instance for which to monitor performance.
@param {number} [options.samplingWindow=5.0] The length of the sliding window over which to compute the average frame rate, in seconds.
@param {number} [options.quietPeriod=2.0] The length of time to wait at startup and each time the page becomes visible (i.e. when the user
       switches back to the tab) before starting to measure performance, in seconds.
@param {number} [options.warmupPeriod=5.0] The length of the warmup period, in seconds.  During the warmup period, a separate
       (usually lower) frame rate is required.
@param {number} [options.minimumFrameRateDuringWarmup=4] The minimum frames-per-second that are required for acceptable performance during
       the warmup period.  If the frame rate averages less than this during any samplingWindow during the warmupPeriod, the
       lowFrameRate event will be raised and the page will redirect to the redirectOnLowFrameRateUrl, if any.
@param {number} [options.minimumFrameRateAfterWarmup=8] The minimum frames-per-second that are required for acceptable performance after
       the end of the warmup period.  If the frame rate averages less than this during any samplingWindow after the warmupPeriod, the
       lowFrameRate event will be raised and the page will redirect to the redirectOnLowFrameRateUrl, if any.