1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <cutils/compiler.h>
17 #include <algorithm>
18 
19 #include "ringbuffer.h"
20 
current_time() const21 nsecs_t histogram::DefaultTimeKeeper::current_time() const {
22     return systemTime(SYSTEM_TIME_MONOTONIC);
23 }
24 
Ringbuffer(size_t ringbuffer_size,std::unique_ptr<histogram::TimeKeeper> tk)25 histogram::Ringbuffer::Ringbuffer(size_t ringbuffer_size, std::unique_ptr<histogram::TimeKeeper> tk) :
26     rb_max_size(ringbuffer_size),
27     timekeeper(std::move(tk)),
28     cumulative_frame_count(0) {
29     cumulative_bins.fill(0);
30 }
31 
create(size_t ringbuffer_size,std::unique_ptr<histogram::TimeKeeper> tk)32 std::unique_ptr<histogram::Ringbuffer> histogram::Ringbuffer::create(
33     size_t ringbuffer_size, std::unique_ptr<histogram::TimeKeeper> tk) {
34     if ((ringbuffer_size == 0) || !tk)
35         return nullptr;
36     return std::unique_ptr<histogram::Ringbuffer>(new histogram::Ringbuffer(ringbuffer_size, std::move(tk)));
37 }
38 
update_cumulative(nsecs_t now,uint64_t & count,std::array<uint64_t,HIST_V_SIZE> & bins) const39 void histogram::Ringbuffer::update_cumulative(nsecs_t now,
40     uint64_t& count, std::array<uint64_t, HIST_V_SIZE>& bins) const {
41 
42     if (ringbuffer.empty())
43         return;
44 
45     count++;
46 
47     const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
48         std::chrono::nanoseconds(now - ringbuffer.front().start_timestamp));
49 
50     for (auto i = 0u; i < bins.size(); i++) {
51         auto const increment = ringbuffer.front().histogram.data[i] * delta.count();
52         if (CC_UNLIKELY((bins[i] + increment < bins[i]) || (increment < ringbuffer.front().histogram.data[i]))) {
53             bins[i] = std::numeric_limits<uint64_t>::max();
54         } else {
55             bins[i] += increment;
56         }
57     }
58 }
59 
insert(drm_msm_hist const & frame)60 void histogram::Ringbuffer::insert(drm_msm_hist const& frame) {
61     std::unique_lock<decltype(mutex)> lk(mutex);
62     auto now = timekeeper->current_time();
63     update_cumulative(now, cumulative_frame_count, cumulative_bins);
64 
65     if (ringbuffer.size() == rb_max_size)
66         ringbuffer.pop_back();
67     if (!ringbuffer.empty())
68         ringbuffer.front().end_timestamp = now;
69     ringbuffer.push_front({frame, now, 0});
70 }
71 
resize(size_t ringbuffer_size)72 bool histogram::Ringbuffer::resize(size_t ringbuffer_size) {
73     std::unique_lock<decltype(mutex)> lk(mutex);
74     if (ringbuffer_size == 0)
75         return false;
76     rb_max_size = ringbuffer_size;
77     if (ringbuffer.size() > rb_max_size)
78         ringbuffer.resize(rb_max_size);
79     return true;
80 }
81 
collect_cumulative() const82 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_cumulative() const {
83     std::unique_lock<decltype(mutex)> lk(mutex);
84     histogram::Ringbuffer::Sample sample { cumulative_frame_count, cumulative_bins };
85     update_cumulative(timekeeper->current_time(), std::get<0>(sample), std::get<1>(sample));
86     return sample;
87 }
88 
collect_ringbuffer_all() const89 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_ringbuffer_all() const {
90     std::unique_lock<decltype(mutex)> lk(mutex);
91     return collect_max(ringbuffer.size(), lk);
92 }
93 
collect_after(nsecs_t timestamp) const94 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_after(
95         nsecs_t timestamp) const {
96     std::unique_lock<decltype(mutex)> lk(mutex);
97     return collect_max_after(timestamp, ringbuffer.size(), lk);
98 }
99 
collect_max(uint32_t max_frames) const100 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max(uint32_t max_frames) const {
101     std::unique_lock<decltype(mutex)> lk(mutex);
102     return collect_max(max_frames, lk);
103 }
104 
collect_max_after(nsecs_t timestamp,uint32_t max_frames) const105 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max_after(
106         nsecs_t timestamp, uint32_t max_frames) const {
107     std::unique_lock<decltype(mutex)> lk(mutex);
108     return collect_max_after(timestamp, max_frames, lk);
109 }
110 
collect_max(uint32_t max_frames,std::unique_lock<std::mutex> const &) const111 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max(
112         uint32_t max_frames, std::unique_lock<std::mutex> const&) const {
113     auto collect_first = std::min(static_cast<size_t>(max_frames), ringbuffer.size());
114     if (collect_first == 0)
115         return {0, {}};
116     std::array<uint64_t, HIST_V_SIZE> bins;
117     bins.fill(0);
118     for (auto it = ringbuffer.begin(); it != ringbuffer.begin() + collect_first; it++) {
119         nsecs_t end_timestamp = it->end_timestamp;
120         if (it == ringbuffer.begin() ) {
121             end_timestamp = timekeeper->current_time();
122         }
123         const auto time_displayed = std::chrono::nanoseconds(end_timestamp - it->start_timestamp);
124         const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(time_displayed);
125         for (auto i = 0u; i < HIST_V_SIZE; i++) {
126             bins[i] += it->histogram.data[i] * delta.count();
127         }
128     }
129     return { collect_first, bins };
130 }
131 
collect_max_after(nsecs_t timestamp,uint32_t max_frames,std::unique_lock<std::mutex> const & lk) const132 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max_after(
133         nsecs_t timestamp, uint32_t max_frames, std::unique_lock<std::mutex> const& lk) const {
134     auto ts_filter_begin = std::lower_bound(
135         ringbuffer.begin(), ringbuffer.end(), HistogramEntry{{}, timestamp, 0},
136         [](auto const &a, auto const &b) { return a.start_timestamp >= b.start_timestamp; });
137 
138     auto collect_last = std::min(std::distance(ringbuffer.begin(), ts_filter_begin),
139                                  static_cast<std::ptrdiff_t>(max_frames));
140     return collect_max(collect_last, lk);
141 }
142