blob: ee945cd01d24f07766147723738ca6505a8ad67d [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CC_METRICS_FRAME_SEQUENCE_METRICS_H_
#define CC_METRICS_FRAME_SEQUENCE_METRICS_H_
#include <bitset>
#include <cmath>
#include <memory>
#include "base/callback.h"
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "base/trace_event/traced_value.h"
#include "cc/cc_export.h"
#include "cc/metrics/frame_info.h"
namespace viz {
struct BeginFrameArgs;
} // namespace viz
namespace cc {
class ThroughputUkmReporter;
class JankMetrics;
struct FrameInfo;
enum class FrameSequenceTrackerType {
// Used as an enum for metrics. DO NOT reorder or delete values. Rather,
// add them at the end and increment kMaxType.
kCompositorAnimation = 0,
kMainThreadAnimation = 1,
kPinchZoom = 2,
kRAF = 3,
kTouchScroll = 4,
kVideo = 6,
kWheelScroll = 7,
kScrollbarScroll = 8,
kCustom = 9, // Note that the metrics for kCustom are not reported on UMA,
// and instead are dispatched back to the LayerTreeHostClient.
kCanvasAnimation = 10,
kJSAnimation = 11,
kSETMainThreadAnimation = 12,
kSETCompositorAnimation = 13,
kMaxType
};
using ActiveTrackers =
std::bitset<static_cast<size_t>(FrameSequenceTrackerType::kMaxType)>;
inline bool IsScrollActive(const ActiveTrackers& trackers) {
return trackers.test(
static_cast<size_t>(FrameSequenceTrackerType::kWheelScroll)) ||
trackers.test(
static_cast<size_t>(FrameSequenceTrackerType::kTouchScroll)) ||
trackers.test(
static_cast<size_t>(FrameSequenceTrackerType::kScrollbarScroll));
}
inline bool HasMainThreadAnimation(const ActiveTrackers& trackers) {
return trackers.test(static_cast<size_t>(
FrameSequenceTrackerType::kMainThreadAnimation)) ||
trackers.test(
static_cast<size_t>(FrameSequenceTrackerType::kCanvasAnimation)) ||
trackers.test(
static_cast<size_t>(FrameSequenceTrackerType::kJSAnimation)) ||
trackers.test(static_cast<size_t>(FrameSequenceTrackerType::kRAF));
}
inline bool HasCompositorThreadAnimation(const ActiveTrackers& trackers) {
return trackers.test(
static_cast<size_t>(FrameSequenceTrackerType::kCompositorAnimation));
}
class CC_EXPORT FrameSequenceMetrics {
public:
FrameSequenceMetrics(FrameSequenceTrackerType type,
ThroughputUkmReporter* ukm_reporter);
~FrameSequenceMetrics();
FrameSequenceMetrics(const FrameSequenceMetrics&) = delete;
FrameSequenceMetrics& operator=(const FrameSequenceMetrics&) = delete;
struct ThroughputData {
static std::unique_ptr<base::trace_event::TracedValue> ToTracedValue(
const ThroughputData& impl,
const ThroughputData& main,
FrameInfo::SmoothEffectDrivingThread effective_thred);
static bool CanReportHistogram(
FrameSequenceMetrics* metrics,
FrameInfo::SmoothEffectDrivingThread thread_type,
const ThroughputData& data);
// Returns the dropped throughput in percent
static int ReportDroppedFramePercentHistogram(
FrameSequenceMetrics* metrics,
FrameInfo::SmoothEffectDrivingThread thread_type,
int metric_index,
const ThroughputData& data);
// Returns the missed deadline throughput in percent
static int ReportMissedDeadlineFramePercentHistogram(
FrameSequenceMetrics* metrics,
FrameInfo::SmoothEffectDrivingThread thread_type,
int metric_index,
const ThroughputData& data);
static void ReportCheckerboardingHistogram(
FrameSequenceMetrics* metrics,
FrameInfo::SmoothEffectDrivingThread thread_type,
int percent);
void Merge(const ThroughputData& data) {
frames_expected += data.frames_expected;
frames_produced += data.frames_produced;
frames_ontime += data.frames_ontime;
#if DCHECK_IS_ON()
frames_processed += data.frames_processed;
frames_received += data.frames_received;
#endif
}
int DroppedFramePercent() const {
if (frames_expected == 0)
return 0;
return std::ceil(100 * (frames_expected - frames_produced) /
static_cast<double>(frames_expected));
}
int MissedDeadlineFramePercent() const {
if (frames_produced == 0)
return 0;
return std::ceil(100 * (frames_produced - frames_ontime) /
static_cast<double>(frames_produced));
}
// Tracks the number of frames that were expected to be shown during this
// frame-sequence.
uint32_t frames_expected = 0;
// Tracks the number of frames that were actually presented to the user
// during this frame-sequence.
uint32_t frames_produced = 0;
// Tracks the number of frames that were actually presented to the user
// that didn't miss the vsync deadline during this frame-sequence.
uint32_t frames_ontime = 0;
#if DCHECK_IS_ON()
// Tracks the number of frames that is either submitted or reported as no
// damage.
uint32_t frames_processed = 0;
// Tracks the number of begin-frames that are received.
uint32_t frames_received = 0;
#endif
};
void SetScrollingThread(FrameInfo::SmoothEffectDrivingThread thread);
struct CustomReportData {
uint32_t frames_expected = 0;
uint32_t frames_produced = 0;
int jank_count = 0;
};
using CustomReporter = base::OnceCallback<void(const CustomReportData& data)>;
// Sets reporter callback for kCustom typed sequence.
void SetCustomReporter(CustomReporter custom_reporter);
// Returns the 'effective thread' for the metrics (i.e. the thread most
// relevant for this metric).
FrameInfo::SmoothEffectDrivingThread GetEffectiveThread() const;
void Merge(std::unique_ptr<FrameSequenceMetrics> metrics);
bool HasEnoughDataForReporting() const;
bool HasDataLeftForReporting() const;
// Report related metrics: throughput, checkboarding...
void ReportMetrics();
void AddSortedFrame(const viz::BeginFrameArgs& args,
const FrameInfo& frame_info);
ThroughputData& impl_throughput() { return impl_throughput_; }
ThroughputData& main_throughput() { return main_throughput_; }
void add_checkerboarded_frames(int64_t frames) {
frames_checkerboarded_ += frames;
}
uint32_t frames_checkerboarded() const { return frames_checkerboarded_; }
FrameSequenceTrackerType type() const { return type_; }
ThroughputUkmReporter* ukm_reporter() const {
return throughput_ukm_reporter_;
}
// Must be called before destructor.
void ReportLeftoverData();
void AdoptTrace(FrameSequenceMetrics* adopt_from);
void AdvanceTrace(base::TimeTicks timestamp);
void ComputeJank(FrameInfo::SmoothEffectDrivingThread thread_type,
uint32_t frame_token,
base::TimeTicks presentation_time,
base::TimeDelta frame_interval);
void NotifySubmitForJankReporter(
FrameInfo::SmoothEffectDrivingThread thread_type,
uint32_t frame_token,
uint32_t sequence_number);
void NotifyNoUpdateForJankReporter(
FrameInfo::SmoothEffectDrivingThread thread_type,
uint32_t sequence_number,
base::TimeDelta frame_interval);
private:
const FrameSequenceTrackerType type_;
// Tracks some data to generate useful trace events.
struct TraceData {
explicit TraceData(FrameSequenceMetrics* metrics);
~TraceData();
raw_ptr<FrameSequenceMetrics> metrics;
base::TimeTicks last_timestamp = base::TimeTicks::Now();
int frame_count = 0;
bool enabled = false;
raw_ptr<void> trace_id = nullptr;
void Advance(base::TimeTicks new_timestamp,
uint32_t expected,
uint32_t dropped);
void Terminate();
} trace_data_{this};
// Pointer to the reporter owned by the FrameSequenceTrackerCollection.
const raw_ptr<ThroughputUkmReporter, DanglingUntriaged>
throughput_ukm_reporter_;
// Track state for measuring the PercentDroppedFrames v2 metrics.
struct {
uint32_t frames_expected = 0;
uint32_t frames_dropped = 0;
} v2_;
// Track state for measuring the PercentDroppedFrames v3 metrics.
struct {
uint32_t frames_expected = 0;
uint32_t frames_dropped = 0;
} v3_;
ThroughputData impl_throughput_;
ThroughputData main_throughput_;
FrameInfo::SmoothEffectDrivingThread scrolling_thread_ =
FrameInfo::SmoothEffectDrivingThread::kUnknown;
// Tracks the number of produced frames that had some amount of
// checkerboarding, and how many frames showed such checkerboarded frames.
uint32_t frames_checkerboarded_ = 0;
// Callback invoked to report metrics for kCustom typed sequence.
CustomReporter custom_reporter_;
std::unique_ptr<JankMetrics> jank_reporter_;
};
bool ShouldReportForAnimation(FrameSequenceTrackerType sequence_type,
FrameInfo::SmoothEffectDrivingThread thread_type);
bool ShouldReportForInteraction(
FrameSequenceTrackerType sequence_type,
FrameInfo::SmoothEffectDrivingThread reporting_thread_type,
FrameInfo::SmoothEffectDrivingThread metrics_effective_thread_type);
} // namespace cc
#endif // CC_METRICS_FRAME_SEQUENCE_METRICS_H_