1 #pragma once
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <deque>
19 #include <mutex>
20 #include <set>
21 
22 #include <android-base/thread_annotations.h>
23 
24 #include "common/libs/time/monotonic_time.h"
25 
26 #include "guest/hals/hwcomposer/common/base_composer.h"
27 #include "guest/hals/hwcomposer/common/hwcomposer.h"
28 
29 namespace cvd {
30 
31 class CompositionData {
32  public:
CompositionData(cvd::time::MonotonicTimePoint time_point,int num_prepares,int num_layers,int num_hwcomposited_layers,cvd::time::Nanoseconds prepare_time,cvd::time::Nanoseconds set_calls_time)33   CompositionData(cvd::time::MonotonicTimePoint time_point, int num_prepares,
34                   int num_layers, int num_hwcomposited_layers,
35                   cvd::time::Nanoseconds prepare_time,
36                   cvd::time::Nanoseconds set_calls_time)
37       : time_point_(time_point),
38         num_prepare_calls_(num_prepares),
39         num_layers_(num_layers),
40         num_hwcomposited_layers_(num_hwcomposited_layers),
41         prepare_time_(prepare_time),
42         set_calls_time_(set_calls_time) {}
43 
time_point()44   cvd::time::MonotonicTimePoint time_point() const { return time_point_; }
45 
num_prepare_calls()46   int num_prepare_calls() const { return num_prepare_calls_; }
47 
num_layers()48   int num_layers() const { return num_layers_; }
49 
num_hwcomposited_layers()50   int num_hwcomposited_layers() const { return num_hwcomposited_layers_; }
51 
prepare_time()52   cvd::time::Nanoseconds prepare_time() const { return prepare_time_; }
53 
set_calls_time()54   cvd::time::Nanoseconds set_calls_time() const { return set_calls_time_; }
55 
56  private:
57   cvd::time::MonotonicTimePoint time_point_;
58   int num_prepare_calls_;
59   int num_layers_;
60   int num_hwcomposited_layers_;
61   cvd::time::Nanoseconds prepare_time_;
62   cvd::time::Nanoseconds set_calls_time_;
63 };
64 
65 struct HWCCompositionStats {
66   cvd::time::MonotonicTimePoint prepare_start;
67   cvd::time::MonotonicTimePoint prepare_end;
68   cvd::time::MonotonicTimePoint set_start;
69   cvd::time::MonotonicTimePoint set_end;
70   cvd::time::MonotonicTimePoint last_vsync;
71   // There may be more than one call to prepare, the timestamps are with regards
72   // to the last one (the one that precedes the set call)
73   int num_prepare_calls;
74   int num_layers;
75   // The number of layers composed by the hwcomposer
76   int num_hwc_layers;
77 };
78 
79 class StatsKeeper {
80  public:
81   // The timespan parameter indicates for how long we keep stats about the past
82   // compositions.
83   StatsKeeper(cvd::time::TimeDifference timespan, int64_t vsync_base,
84               int32_t vsync_period);
85   StatsKeeper();
86   ~StatsKeeper();
87 
88   // Record the time at which a call to prepare was made, takes the number of
89   // layers received (excluding the framebuffer) as a parameter.
90   void RecordPrepareStart(int num_layers);
91   // Record the time at which a call to prepare (was about to) returned, takes
92   // the number of layers marked for hardware composition as a parameter.
93   void RecordPrepareEnd(int num_hwcomposited_layers);
94   void RecordSetStart();
95   void RecordSetEnd() EXCLUDES(mutex_);
96 
97   void GetLastCompositionStats(CompositionStats* stats_p);
98 
99   // Calls to this function are synchronized with calls to 'RecordSetEnd' with a
100   // mutex. The other Record* functions do not need such synchronization because
101   // they access last_* variables only, which are not read by 'Dump'.
102   void SynchronizedDump(char* buffer, int buffer_size) const EXCLUDES(mutex_);
103 
104  private:
105   cvd::time::TimeDifference period_length_;
106 
107   // Base and period of the VSYNC signal, allows to accurately calculate the
108   // time of the last vsync broadcast.
109   int64_t vsync_base_;
110   int32_t vsync_period_;
111   // Data collected about ongoing composition. These variables are not accessed
112   // from Dump(), so they don't need to be guarded by a mutex.
113   HWCCompositionStats last_composition_stats_;
114 
115   // Aggregated performance data collected from past compositions. These
116   // variables are modified when a composition is completed and when old
117   // compositions need to be discarded in RecordSetEnd(), and is accessed from
118   // Dump(). Non-aggregated data is kept in the raw_composition_data_ deque to
119   // be able to discard old values from the aggregated data.
120   int num_layers_ GUARDED_BY(mutex_);
121   int num_hwcomposited_layers_ GUARDED_BY(mutex_);
122   int num_prepare_calls_ GUARDED_BY(mutex_);
123   int num_set_calls_ GUARDED_BY(mutex_);
124   cvd::time::Nanoseconds prepare_call_total_time_ GUARDED_BY(mutex_);
125   cvd::time::Nanoseconds set_call_total_time_ GUARDED_BY(mutex_);
126   // These are kept in multisets to be able to calculate mins and maxs of
127   // changing sets of (not necessarily different) values.
128   std::multiset<int> prepare_calls_per_set_calls_ GUARDED_BY(mutex_);
129   std::multiset<int> layers_per_compositions_ GUARDED_BY(mutex_);
130   std::multiset<cvd::time::Nanoseconds> prepare_call_times_ GUARDED_BY(mutex_);
131   std::multiset<cvd::time::Nanoseconds> set_call_times_ GUARDED_BY(mutex_);
132   std::multiset<int64_t> set_call_times_per_hwcomposited_layer_ns_
133       GUARDED_BY(mutex_);
134 
135   // Time-ordered list of compositions, used to update the global aggregated
136   // performance data when old compositions fall out of the period of interest.
137   std::deque<CompositionData> raw_composition_data_ GUARDED_BY(mutex_);
138 
139   // TODO(jemoreira): Add min/max/average composition times per layer area units
140 
141   std::deque<std::pair<int64_t, int64_t> > composition_areas GUARDED_BY(mutex_);
142   int64_t total_layers_area GUARDED_BY(mutex_);
143   int64_t total_invisible_area GUARDED_BY(mutex_);
144 
145   // Controls access to data from past compositions.
146   mutable std::mutex mutex_;
147 };
148 
149 class WrappedScreenView : public ScreenView {
150  public:
WrappedScreenView(std::unique_ptr<ScreenView> screen_view,std::function<void (CompositionStats *)> stats_getter)151   WrappedScreenView(std::unique_ptr<ScreenView> screen_view,
152                     std::function<void(CompositionStats*)> stats_getter)
153       : screen_view_(std::move(screen_view)), stats_getter_(stats_getter) {}
154   virtual ~WrappedScreenView() = default;
155 
Broadcast(int buffer_id,const CompositionStats *)156   void Broadcast(int buffer_id, const CompositionStats*) override {
157     // The composer object in stats_keeper produces null stats, use the ones
158     // provided by the stats_keeper instead.
159     CompositionStats stats;
160     stats_getter_(&stats);
161     return screen_view_->Broadcast(buffer_id, &stats);
162   }
163 
GetBuffer(int buffer_id)164   void* GetBuffer(int buffer_id) override {
165     return screen_view_->GetBuffer(buffer_id);
166   }
167 
x_res()168   int32_t x_res() const override { return screen_view_->x_res(); }
169 
y_res()170   int32_t y_res() const override { return screen_view_->y_res(); }
171 
dpi()172   int32_t dpi() const override { return screen_view_->dpi(); }
173 
refresh_rate()174   int32_t refresh_rate() const override { return screen_view_->refresh_rate(); }
175 
num_buffers()176   int num_buffers() const override { return screen_view_->num_buffers(); }
177 
178  private:
179   std::unique_ptr<ScreenView> screen_view_;
180   std::function<void(CompositionStats*)> stats_getter_;
181 };
182 
183 template <class Composer>
184 class StatsKeepingComposer : public BaseComposer {
185  public:
186   // Keep stats from the last 10 seconds.
StatsKeepingComposer(int64_t vsync_base_timestamp,std::unique_ptr<ScreenView> screen_view)187   StatsKeepingComposer(int64_t vsync_base_timestamp,
188                        std::unique_ptr<ScreenView> screen_view)
189       : composer_(std::unique_ptr<ScreenView>(
190                       new WrappedScreenView(std::move(screen_view),
191                                             [this](CompositionStats* stats) {
192                                               FinalizeStatsAndGet(stats);
193                                             }))),
194         stats_keeper_(cvd::time::TimeDifference(cvd::time::Seconds(10), 1),
195                       vsync_base_timestamp, 1e9 / composer_.refresh_rate()) {}
196   virtual ~StatsKeepingComposer() = default;
197 
PrepareLayers(size_t num_layers,hwc_layer_1_t * layers)198   int PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) override {
199     stats_keeper_.RecordPrepareStart(num_layers);
200     int num_hwc_layers = composer_.PrepareLayers(num_layers, layers);
201     stats_keeper_.RecordPrepareEnd(num_hwc_layers);
202     return num_hwc_layers;
203   }
204 
SetLayers(size_t num_layers,hwc_layer_1_t * layers)205   int SetLayers(size_t num_layers, hwc_layer_1_t* layers) override {
206     stats_keeper_.RecordSetStart();
207     return composer_.SetLayers(num_layers, layers);
208   }
209 
Dump(char * buff,int buff_len)210   void Dump(char* buff, int buff_len) override {
211     stats_keeper_.SynchronizedDump(buff, buff_len);
212   }
213 
FinalizeStatsAndGet(CompositionStats * stats)214   void FinalizeStatsAndGet(CompositionStats* stats) {
215     stats_keeper_.RecordSetEnd();
216     stats_keeper_.GetLastCompositionStats(stats);
217   }
218 
219  private:
220   Composer composer_;
221   StatsKeeper stats_keeper_;
222 };
223 
224 }  // namespace cvd
225