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 <log/log.h>
18 #include <unistd.h>
19 #include <algorithm>
20 #include <iostream>
21 
22 #include "ringbuffer.h"
23 
current_time() const24 nsecs_t histogram::DefaultTimeKeeper::current_time() const {
25   return systemTime(SYSTEM_TIME_MONOTONIC);
26 }
27 
Ringbuffer(size_t ringbuffer_size,std::unique_ptr<histogram::TimeKeeper> tk)28 histogram::Ringbuffer::Ringbuffer(size_t ringbuffer_size, std::unique_ptr<histogram::TimeKeeper> tk)
29     : rb_max_size(ringbuffer_size), timekeeper(std::move(tk)), cumulative_frame_count(0) {
30   cumulative_bins.fill(0);
31 }
32 
create(size_t ringbuffer_size,std::unique_ptr<histogram::TimeKeeper> tk)33 std::unique_ptr<histogram::Ringbuffer> histogram::Ringbuffer::create(
34     size_t ringbuffer_size, std::unique_ptr<histogram::TimeKeeper> tk) {
35   if ((ringbuffer_size == 0) || !tk)
36     return nullptr;
37   return std::unique_ptr<histogram::Ringbuffer>(
38       new histogram::Ringbuffer(ringbuffer_size, std::move(tk)));
39 }
40 
update_cumulative(nsecs_t now,uint64_t & count,std::array<uint64_t,HIST_V_SIZE> & bins) const41 void histogram::Ringbuffer::update_cumulative(nsecs_t now, uint64_t &count,
42                                               std::array<uint64_t, HIST_V_SIZE> &bins) const {
43   if (ringbuffer.empty())
44     return;
45 
46   count++;
47   ALOGI("count : %llu", static_cast<unsigned long long>(count));
48 
49   const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
50       std::chrono::nanoseconds(now - ringbuffer.front().start_timestamp));
51 
52   for (auto i = 0u; i < bins.size(); i++) {
53     ALOGI("histogram.data[%d]: %u\n", i, ringbuffer.front().histogram.data[i]);
54     auto const increment = ringbuffer.front().histogram.data[i] * delta.count();
55     if (CC_UNLIKELY((bins[i] + increment < bins[i]) ||
56                     (increment < ringbuffer.front().histogram.data[i]))) {
57       bins[i] = std::numeric_limits<uint64_t>::max();
58     } else {
59       bins[i] += increment;
60     }
61     ALOGI("bins[%d]: %llu\n", i, static_cast<unsigned long long>(bins[i]));
62   }
63 }
64 
insert(drm_msm_hist const & frame)65 void histogram::Ringbuffer::insert(drm_msm_hist const &frame) {
66   std::cout << "Enter insert ringbuffer" << std::endl;
67 
68   std::unique_lock<decltype(mutex)> lk(mutex);
69   auto now = timekeeper->current_time();
70 
71   std::cout << "update cumulative count" << std::endl;
72   update_cumulative(now, cumulative_frame_count, cumulative_bins);
73 
74   if (ringbuffer.size() == rb_max_size)
75     ringbuffer.pop_back();
76   if (!ringbuffer.empty())
77     ringbuffer.front().end_timestamp = now;
78 
79   std::cout << "Exit insert ringbuffer" << std::endl;
80   ringbuffer.push_front({frame, now, 0});
81 }
82 
resize(size_t ringbuffer_size)83 bool histogram::Ringbuffer::resize(size_t ringbuffer_size) {
84   std::unique_lock<decltype(mutex)> lk(mutex);
85   if (ringbuffer_size == 0)
86     return false;
87   rb_max_size = ringbuffer_size;
88   if (ringbuffer.size() > rb_max_size)
89     ringbuffer.resize(rb_max_size);
90   return true;
91 }
92 
collect_cumulative() const93 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_cumulative() const {
94   std::unique_lock<decltype(mutex)> lk(mutex);
95   histogram::Ringbuffer::Sample sample{cumulative_frame_count, cumulative_bins};
96   update_cumulative(timekeeper->current_time(), std::get<0>(sample), std::get<1>(sample));
97   return sample;
98 }
99 
collect_ringbuffer_all() const100 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_ringbuffer_all() const {
101   std::unique_lock<decltype(mutex)> lk(mutex);
102   return collect_max(ringbuffer.size(), lk);
103 }
104 
collect_after(nsecs_t timestamp) const105 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_after(nsecs_t timestamp) const {
106   std::unique_lock<decltype(mutex)> lk(mutex);
107   return collect_max_after(timestamp, ringbuffer.size(), lk);
108 }
109 
collect_max(uint32_t max_frames) const110 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max(uint32_t max_frames) const {
111   std::unique_lock<decltype(mutex)> lk(mutex);
112   return collect_max(max_frames, lk);
113 }
114 
collect_max_after(nsecs_t timestamp,uint32_t max_frames) const115 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max_after(nsecs_t timestamp,
116                                                                        uint32_t max_frames) const {
117   std::unique_lock<decltype(mutex)> lk(mutex);
118   return collect_max_after(timestamp, max_frames, lk);
119 }
120 
collect_max(uint32_t max_frames,std::unique_lock<std::mutex> const &) const121 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max(
122     uint32_t max_frames, std::unique_lock<std::mutex> const &) const {
123   auto collect_first = std::min(static_cast<size_t>(max_frames), ringbuffer.size());
124   if (collect_first == 0)
125     return {0, {}};
126   std::array<uint64_t, HIST_V_SIZE> bins;
127   bins.fill(0);
128   for (auto it = ringbuffer.begin(); it != ringbuffer.end() &&
129     it != ringbuffer.begin() + collect_first; it++) {
130     nsecs_t end_timestamp = it->end_timestamp;
131     if (it == ringbuffer.begin()) {
132       end_timestamp = timekeeper->current_time();
133     }
134     const auto time_displayed = std::chrono::nanoseconds(end_timestamp - it->start_timestamp);
135     const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(time_displayed);
136     for (auto i = 0u; i < HIST_V_SIZE; i++) {
137       bins[i] += it->histogram.data[i] * delta.count();
138     }
139   }
140   return {collect_first, bins};
141 }
142 
collect_max_after(nsecs_t timestamp,uint32_t max_frames,std::unique_lock<std::mutex> const & lk) const143 histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max_after(
144     nsecs_t timestamp, uint32_t max_frames, std::unique_lock<std::mutex> const &lk) const {
145   auto ts_filter_begin = std::lower_bound(
146       ringbuffer.begin(), ringbuffer.end(), HistogramEntry{{}, timestamp, 0},
147       [](auto const &a, auto const &b) { return a.start_timestamp >= b.start_timestamp; });
148 
149   auto collect_last = std::min(std::distance(ringbuffer.begin(), ts_filter_begin),
150                                static_cast<std::ptrdiff_t>(max_frames));
151   return collect_max(collect_last, lk);
152 }
153