Home | History | Annotate | Download | only in vsoc
      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 <set>
     20 
     21 #include <android-base/thread_annotations.h>
     22 
     23 #include "common/libs/threads/cuttlefish_thread.h"
     24 #include "common/libs/time/monotonic_time.h"
     25 #include "common/vsoc/lib/screen_region_view.h"
     26 
     27 #include "hwcomposer.h"
     28 
     29 namespace cvd {
     30 
     31 class CompositionData {
     32  public:
     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 
     44   cvd::time::MonotonicTimePoint time_point() const { return time_point_; }
     45 
     46   int num_prepare_calls() const { return num_prepare_calls_; }
     47 
     48   int num_layers() const { return num_layers_; }
     49 
     50   int num_hwcomposited_layers() const { return num_hwcomposited_layers_; }
     51 
     52   cvd::time::Nanoseconds prepare_time() const { return prepare_time_; }
     53 
     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(vsoc::layout::screen::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 cvd::Mutex mutex_;
    147 };
    148 
    149 template <class Composer>
    150 class StatsKeepingComposer {
    151  public:
    152   // Keep stats from the last 10 seconds.
    153   StatsKeepingComposer(int64_t vsync_base_timestamp, int32_t vsync_period_ns)
    154       : stats_keeper_(cvd::time::TimeDifference(cvd::time::Seconds(10), 1),
    155                       vsync_base_timestamp, vsync_period_ns),
    156         composer_(vsync_base_timestamp, vsync_period_ns) {
    157     // Don't let the composer broadcast by itself, allow it to return to collect
    158     // the timings and broadcast then.
    159     composer_.ReplaceFbBroadcaster([this](int buffer_index){
    160         BroadcastWithStats(buffer_index);
    161       });
    162   }
    163   ~StatsKeepingComposer() = default;
    164 
    165   int PrepareLayers(size_t num_layers, vsoc_hwc_layer* layers) {
    166     stats_keeper_.RecordPrepareStart(num_layers);
    167     int num_hwc_layers = composer_.PrepareLayers(num_layers, layers);
    168     stats_keeper_.RecordPrepareEnd(num_hwc_layers);
    169     return num_hwc_layers;
    170   }
    171 
    172   void BroadcastWithStats(int buffer_idx) {
    173     stats_keeper_.RecordSetEnd();
    174     vsoc::layout::screen::CompositionStats stats;
    175     stats_keeper_.GetLastCompositionStats(&stats);
    176     vsoc::screen::ScreenRegionView::GetInstance()
    177       ->BroadcastNewFrame(static_cast<uint32_t>(buffer_idx), &stats);
    178   }
    179 
    180   int SetLayers(size_t num_layers, vsoc_hwc_layer* layers) {
    181     stats_keeper_.RecordSetStart();
    182     return composer_.SetLayers(num_layers, layers);
    183   }
    184 
    185   void Dump(char* buff, int buff_len) {
    186     stats_keeper_.SynchronizedDump(buff, buff_len);
    187   }
    188 
    189  private:
    190   StatsKeeper stats_keeper_;
    191   Composer composer_;
    192 };
    193 
    194 }  // namespace cvd
    195