blob: 147318b50f0777835a81231cdaf24afa2744cb6b [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_LATENCY_FRAME_METRICS_H_
#define UI_LATENCY_FRAME_METRICS_H_
#include "ui/latency/stream_analyzer.h"
#include <cstdint>
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/time/time.h"
#include "base/trace_event/traced_value.h"
#include "ui/latency/skipped_frame_tracker.h"
namespace ui {
namespace frame_metrics {
class SkipClient : public frame_metrics::StreamAnalyzerClient {
double TransformResult(double result) const override;
};
class LatencyClient : public frame_metrics::StreamAnalyzerClient {
double TransformResult(double result) const override;
};
class LatencySpeedClient : public frame_metrics::StreamAnalyzerClient {
double TransformResult(double result) const override;
};
class LatencyAccelerationClient : public frame_metrics::StreamAnalyzerClient {
double TransformResult(double result) const override;
};
} // namespace frame_metrics
enum class FrameMetricsSource {
Unknown = 0,
UnitTest = 1,
RendererCompositor = 2,
UiCompositor = 3,
};
enum class FrameMetricsSourceThread {
Unknown = 0,
Blink = 1,
RendererCompositor = 2,
Ui = 3,
UiCompositor = 4,
VizCompositor = 5,
};
enum class FrameMetricsCompileTarget {
Unknown = 0,
Chromium = 1,
SynchronousCompositor = 2,
Headless = 3,
};
struct FrameMetricsSettings {
FrameMetricsSettings() = default;
FrameMetricsSettings(FrameMetricsSource source,
FrameMetricsSourceThread source_thread,
FrameMetricsCompileTarget compile_target,
bool trace_results_every_frame = false,
size_t max_window_size = 60)
: source(source),
source_thread(source_thread),
compile_target(compile_target),
trace_results_every_frame(trace_results_every_frame),
max_window_size(max_window_size) {}
void set_is_frame_latency_speed_on(bool is_speed_on) {
is_frame_latency_speed_on_ = is_speed_on;
}
void set_is_frame_latency_acceleration_on(bool is_acceleration_on) {
is_frame_latency_acceleration_on_ = is_acceleration_on;
}
bool is_frame_latency_speed_on() const { return is_frame_latency_speed_on_; }
bool is_frame_latency_acceleration_on() const {
return is_frame_latency_acceleration_on_;
}
// Source configuration.
FrameMetricsSource source;
FrameMetricsSourceThread source_thread;
FrameMetricsCompileTarget compile_target;
// This is needed for telemetry results.
bool trace_results_every_frame;
// Maximum window size in number of samples.
// This is forwarded to each WindowAnalyzer.
size_t max_window_size;
void AsValueInto(base::trace_event::TracedValue* state) const;
private:
// Switch for frame latency speed measurements control.
bool is_frame_latency_speed_on_ = false;
// Switch for frame latency acceleration measurements control.
bool is_frame_latency_acceleration_on_ = false;
};
// Calculates all metrics for a frame source.
// Every frame source that we wish to instrument will own an instance of
// this class and will call AddFrameProduced and AddFrameDisplayed.
// Statistics will be reported automatically. Either periodically, based
// on the client interface, or on destruction if any samples were added since
// the last call to StartNewReportPeriod.
class FrameMetrics : public SkippedFrameTracker::Client {
public:
explicit FrameMetrics(FrameMetricsSettings settings);
~FrameMetrics() override;
// Resets all data and history as if the class were just created.
void Reset();
// AddFrameProduced should be called every time a source produces a frame.
// |source_timestamp| is when frame time in BeginFrameArgs(i.e. when the frame
// is produced); |amount_produced| is the expected time interval between 2
// consecutive frames; |amount_skipped| is number of frame skipped before
// producing this frame multiplies by the interval, i.e., if 1 frame is
// skipped in 30 fps setting, then |amount_skipped| is 33.33ms; if 1 frame is
// skipped in 60FPS setting, then the |amount_skipped| is 16.67ms. Note: If
// the FrameMetrics class is hooked up to an optional SkippedFrameTracker, the
// client should not call this directly.
void AddFrameProduced(base::TimeTicks source_timestamp,
base::TimeDelta amount_produced,
base::TimeDelta amount_skipped) override;
// AddFrameDisplayed should be called whenever a frame causes damage and
// we know when the result became visible on the display. |source_timestamp|
// is when frame time in BeginFrameArgs(i.e. when the frame is produced);
// |display_timestamp| is when the frame is displayed on screen.
// This will affect all latency derived metrics, including latency speed,
// latency acceleration, and latency itself.
// If a frame is produced but not displayed, do not call this; there was
// no change in the displayed result and thus no change to track the visual
// latency of. Guessing a displayed time will only skew the results.
void AddFrameDisplayed(base::TimeTicks source_timestamp,
base::TimeTicks display_timestamp);
// Compute the square root by using method described in paper:
// http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf.
// It finds a result within 0.0001 and 0.1 of the true square root for |x| <
// 100 and |x| < 2^15 respectively. It's more than 2 times faster for Nexus 4
// and other lower end android devices and ~3-5% faster on desktop. Crash when
// x is less than 0.
static double FastApproximateSqrt(double x);
protected:
void TraceStats() const;
// virtual for testing.
virtual base::TimeDelta ReportPeriod();
// Starts a new reporting period after |kDefaultReportPeriod| time that resets
// the various accumulators and memory of worst regions encountered, but does
// not destroy recent sample history in the windowed analyzers and in the
// derivatives for latency speed and latency acceleration. This avoids small
// gaps in coverage when starting a new reporting period.
void StartNewReportPeriod();
FrameMetricsSettings settings_;
const char* source_name_;
frame_metrics::SharedWindowedAnalyzerClient shared_skip_client_;
base::circular_deque<base::TimeTicks> skip_timestamp_queue_;
frame_metrics::SharedWindowedAnalyzerClient shared_latency_client_;
base::circular_deque<base::TimeTicks> latency_timestamp_queue_;
base::TimeDelta time_since_start_of_report_period_;
uint32_t frames_produced_since_start_of_report_period_ = 0;
uint64_t latencies_added_ = 0;
base::TimeTicks source_timestamp_prev_;
base::TimeDelta latency_prev_;
base::TimeDelta source_duration_prev_;
base::TimeDelta latency_delta_prev_;
frame_metrics::SkipClient skip_client_;
frame_metrics::LatencyClient latency_client_;
frame_metrics::LatencySpeedClient latency_speed_client_;
frame_metrics::LatencyAccelerationClient latency_acceleration_client_;
frame_metrics::StreamAnalyzer frame_skips_analyzer_;
frame_metrics::StreamAnalyzer latency_analyzer_;
frame_metrics::StreamAnalyzer latency_speed_analyzer_;
frame_metrics::StreamAnalyzer latency_acceleration_analyzer_;
DISALLOW_COPY_AND_ASSIGN(FrameMetrics);
};
} // namespace ui
#endif // UI_LATENCY_FRAME_METRICS_H_