1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cc/metrics/dropped_frame_counter.h"
6 
7 #include "base/bind.h"
8 #include "base/trace_event/trace_event.h"
9 #include "cc/metrics/frame_sorter.h"
10 #include "cc/metrics/total_frame_counter.h"
11 #include "cc/metrics/ukm_smoothness_data.h"
12 
13 namespace cc {
14 
DroppedFrameCounter()15 DroppedFrameCounter::DroppedFrameCounter()
16     : frame_sorter_(base::BindRepeating(&DroppedFrameCounter::NotifyFrameResult,
17                                         base::Unretained(this))) {}
18 DroppedFrameCounter::~DroppedFrameCounter() = default;
19 
GetAverageThroughput() const20 uint32_t DroppedFrameCounter::GetAverageThroughput() const {
21   size_t good_frames = 0;
22   for (auto it = --end(); it; --it) {
23     if (**it == kFrameStateComplete)
24       ++good_frames;
25   }
26   double throughput = 100. * good_frames / ring_buffer_.BufferSize();
27   return static_cast<uint32_t>(throughput);
28 }
29 
AddGoodFrame()30 void DroppedFrameCounter::AddGoodFrame() {
31   ring_buffer_.SaveToBuffer(kFrameStateComplete);
32   ++total_frames_;
33 }
34 
AddPartialFrame()35 void DroppedFrameCounter::AddPartialFrame() {
36   ring_buffer_.SaveToBuffer(kFrameStatePartial);
37   ++total_frames_;
38   ++total_partial_;
39 }
40 
AddDroppedFrame()41 void DroppedFrameCounter::AddDroppedFrame() {
42   ring_buffer_.SaveToBuffer(kFrameStateDropped);
43   ++total_frames_;
44   ++total_dropped_;
45 }
46 
ResetFrameSorter()47 void DroppedFrameCounter::ResetFrameSorter() {
48   frame_sorter_.Reset();
49 }
50 
OnBeginFrame(const viz::BeginFrameArgs & args)51 void DroppedFrameCounter::OnBeginFrame(const viz::BeginFrameArgs& args) {
52   if (fcp_received_)
53     frame_sorter_.AddNewFrame(args);
54 }
55 
OnEndFrame(const viz::BeginFrameArgs & args,bool is_dropped)56 void DroppedFrameCounter::OnEndFrame(const viz::BeginFrameArgs& args,
57                                      bool is_dropped) {
58   if (is_dropped) {
59     if (fcp_received_)
60       ++total_smoothness_dropped_;
61     ReportFrames();
62   }
63 
64   if (fcp_received_)
65     frame_sorter_.AddFrameResult(args, is_dropped);
66 }
67 
ReportFrames()68 void DroppedFrameCounter::ReportFrames() {
69   const auto total_frames =
70       total_counter_->ComputeTotalVisibleFrames(base::TimeTicks::Now());
71   TRACE_EVENT2("cc,benchmark", "SmoothnessDroppedFrame", "total", total_frames,
72                "smoothness", total_smoothness_dropped_);
73 
74   if (ukm_smoothness_data_ && total_frames > 0) {
75     UkmSmoothnessData smoothness_data;
76     smoothness_data.avg_smoothness =
77         static_cast<double>(total_smoothness_dropped_) * 100 / total_frames;
78 
79     ukm_smoothness_data_->seq_lock.WriteBegin();
80     device::OneWriterSeqLock::AtomicWriterMemcpy(&ukm_smoothness_data_->data,
81                                                  &smoothness_data,
82                                                  sizeof(UkmSmoothnessData));
83     ukm_smoothness_data_->seq_lock.WriteEnd();
84   }
85 }
86 
SetUkmSmoothnessDestination(UkmSmoothnessDataShared * smoothness_data)87 void DroppedFrameCounter::SetUkmSmoothnessDestination(
88     UkmSmoothnessDataShared* smoothness_data) {
89   ukm_smoothness_data_ = smoothness_data;
90 }
91 
Reset()92 void DroppedFrameCounter::Reset() {
93   total_frames_ = 0;
94   total_partial_ = 0;
95   total_dropped_ = 0;
96   total_smoothness_dropped_ = 0;
97   fcp_received_ = false;
98   ring_buffer_.Clear();
99   frame_sorter_.Reset();
100 }
101 
NotifyFrameResult(const viz::BeginFrameArgs & args,bool is_dropped)102 void DroppedFrameCounter::NotifyFrameResult(const viz::BeginFrameArgs& args,
103                                             bool is_dropped) {
104   // TODO(crbug.com/1115141) The implementation of smoothness metrics.
105 }
106 
OnFcpReceived()107 void DroppedFrameCounter::OnFcpReceived() {
108   fcp_received_ = true;
109 }
110 
111 }  // namespace cc
112