blob: ebeb2cdee2fe810fb230fb4fde21271c2ce100a5 [file] [log] [blame]
// Copyright 2019 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 CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
#define CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
#include <memory>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/time/time.h"
#include "cc/base/base_export.h"
#include "cc/cc_export.h"
#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/metrics/event_metrics.h"
#include "cc/metrics/frame_sequence_tracker.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_timing_details.h"
namespace viz {
struct FrameTimingDetails;
}
namespace cc {
class LatencyUkmReporter;
// This is used for tracing and reporting the duration of pipeline stages within
// a single frame.
//
// For each stage in the frame pipeline, calling StartStage will start tracing
// that stage (and end any currently running stages).
//
// If the tracked frame is presented (i.e. the frame termination status is
// kPresentedFrame), then the duration of each stage along with the total
// latency will be reported to UMA. If the tracked frame is not presented (i.e.
// the frame termination status is kDidNotPresentFrame or
// kReplacedByNewReporter), then the duration is reported under
// CompositorLatency.DroppedFrame.*.
// The format of each stage reported to UMA is
// "CompositorLatency.[DroppedFrame.][Interaction_name.].<StageName>".
class CC_EXPORT CompositorFrameReporter {
public:
enum class FrameTerminationStatus {
// The tracked compositor frame was presented.
kPresentedFrame,
// The tracked compositor frame was submitted to the display compositor but
// was not presented.
kDidNotPresentFrame,
// Reporter that is currently at a stage is replaced by a new one (e.g. two
// BeginImplFrames can happen without issuing BeginMainFrame, so the first
// reporter would terminate with this status).
kReplacedByNewReporter,
// Frame that was being tracked did not end up being submitting (e.g. frame
// had no damage or LTHI was ended).
kDidNotProduceFrame,
// Default termination status. Should not be reachable.
kUnknown
};
// These values are used for indexing the UMA histograms.
enum class FrameReportType {
kNonDroppedFrame = 0,
kMissedDeadlineFrame = 1,
kDroppedFrame = 2,
kMaxValue = kDroppedFrame
};
// These values are used for indexing the UMA histograms.
enum class StageType {
kBeginImplFrameToSendBeginMainFrame = 0,
kSendBeginMainFrameToCommit = 1,
kCommit = 2,
kEndCommitToActivation = 3,
kActivation = 4,
kEndActivateToSubmitCompositorFrame = 5,
kSubmitCompositorFrameToPresentationCompositorFrame = 6,
kTotalLatency = 7,
kStageTypeCount
};
enum class VizBreakdown {
kSubmitToReceiveCompositorFrame = 0,
kReceivedCompositorFrameToStartDraw = 1,
kStartDrawToSwapStart = 2,
kSwapStartToSwapEnd = 3,
kSwapEndToPresentationCompositorFrame = 4,
kBreakdownCount
};
enum class BlinkBreakdown {
kHandleInputEvents = 0,
kAnimate = 1,
kStyleUpdate = 2,
kLayoutUpdate = 3,
kPrepaint = 4,
kComposite = 5,
kPaint = 6,
kScrollingCoordinator = 7,
kCompositeCommit = 8,
kUpdateLayers = 9,
kBeginMainSentToStarted = 10,
kBreakdownCount
};
struct StageData {
StageType stage_type;
base::TimeTicks start_time;
base::TimeTicks end_time;
StageData();
StageData(StageType stage_type,
base::TimeTicks start_time,
base::TimeTicks end_time);
StageData(const StageData&);
~StageData();
};
CompositorFrameReporter(
const base::flat_set<FrameSequenceTrackerType>* active_trackers,
const viz::BeginFrameId& id,
const base::TimeTicks frame_deadline,
LatencyUkmReporter* latency_ukm_reporter,
bool should_report_metrics);
~CompositorFrameReporter();
CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
delete;
std::unique_ptr<CompositorFrameReporter> CopyReporterAtBeginImplStage() const;
const viz::BeginFrameId frame_id_;
// Note that the started stage may be reported to UMA. If the histogram is
// intended to be reported then the histograms.xml file must be updated too.
void StartStage(StageType stage_type, base::TimeTicks start_time);
void TerminateFrame(FrameTerminationStatus termination_status,
base::TimeTicks termination_time);
void SetBlinkBreakdown(std::unique_ptr<BeginMainFrameMetrics> blink_breakdown,
base::TimeTicks begin_main_start);
void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown);
void SetEventsMetrics(std::vector<EventMetrics> events_metrics);
int StageHistorySizeForTesting() { return stage_history_.size(); }
void OnFinishImplFrame(base::TimeTicks timestamp);
void OnAbortBeginMainFrame(base::TimeTicks timestamp);
void OnDidNotProduceFrame();
bool did_finish_impl_frame() const { return did_finish_impl_frame_; }
bool did_abort_main_frame() const { return did_abort_main_frame_; }
bool did_not_produce_frame() const { return did_not_produce_frame_; }
base::TimeTicks impl_frame_finish_time() const {
return impl_frame_finish_time_;
}
private:
void DroppedFrame();
void MissedDeadlineFrame();
void TerminateReporter();
void EndCurrentStage(base::TimeTicks end_time);
void ReportCompositorLatencyHistograms() const;
void ReportLatencyHistograms(bool report_event_latency = false,
bool report_delayed_latency = false);
void ReportStageHistogramWithBreakdown(
const StageData& stage,
FrameSequenceTrackerType frame_sequence_tracker_type =
FrameSequenceTrackerType::kMaxType) const;
void ReportBlinkBreakdowns(
const base::TimeTicks start_time,
FrameSequenceTrackerType frame_sequence_tracker_type) const;
// Report histogram and trace event stage for one Viz breakdown
void ReportVizBreakdownStage(
VizBreakdown stage,
const base::TimeTicks start_time,
const base::TimeTicks end_time,
FrameSequenceTrackerType frame_sequence_tracker_type) const;
void ReportVizBreakdowns(
const base::TimeTicks start_time,
FrameSequenceTrackerType frame_sequence_tracker_type) const;
void ReportCompositorLatencyHistogram(
FrameSequenceTrackerType intraction_type,
const int stage_type_index,
base::TimeDelta time_delta) const;
void ReportEventLatencyHistograms() const;
// Generate a trace event corresponding to a Viz breakdown under
// SubmitCompositorFrameToPresentationCompositorFrame stage in
// PipelineReporter. This function only generates trace events and does not
// report histograms.
void ReportVizBreakdownTrace(VizBreakdown substage,
const base::TimeTicks start_time,
const base::TimeTicks end_time) const;
void ReportAllTraceEvents(const char* termination_status_str) const;
const bool should_report_metrics_;
StageData current_stage_;
BeginMainFrameMetrics blink_breakdown_;
viz::FrameTimingDetails viz_breakdown_;
// Stage data is recorded here. On destruction these stages will be reported
// to UMA if the termination status is |kPresentedFrame|. Reported data will
// be divided based on the frame submission status.
std::vector<StageData> stage_history_;
// This method is only used for DCheck
base::TimeDelta SumOfStageHistory() const;
// List of metrics for events affecting this frame.
std::vector<EventMetrics> events_metrics_;
FrameReportType report_type_ = FrameReportType::kNonDroppedFrame;
base::TimeTicks frame_termination_time_;
base::TimeTicks begin_main_frame_start_;
FrameTerminationStatus frame_termination_status_ =
FrameTerminationStatus::kUnknown;
const base::flat_set<FrameSequenceTrackerType>* active_trackers_;
LatencyUkmReporter* latency_ukm_reporter_;
// Indicates if work on Impl frame is finished.
bool did_finish_impl_frame_ = false;
// Indicates if main frame is aborted after begin.
bool did_abort_main_frame_ = false;
// Flag indicating if DidNotProduceFrame is called for this reporter
bool did_not_produce_frame_ = false;
// The time that work on Impl frame is finished. It's only valid if the
// reporter is in a stage other than begin impl frame.
base::TimeTicks impl_frame_finish_time_;
base::TimeTicks frame_deadline_;
};
} // namespace cc
#endif // CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_"