| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <cutils/compiler.h> |
| #include <algorithm> |
| |
| #include "ringbuffer.h" |
| |
| nsecs_t histogram::DefaultTimeKeeper::current_time() const { |
| return systemTime(SYSTEM_TIME_MONOTONIC); |
| } |
| |
| histogram::Ringbuffer::Ringbuffer(size_t ringbuffer_size, std::unique_ptr<histogram::TimeKeeper> tk) : |
| rb_max_size(ringbuffer_size), |
| timekeeper(std::move(tk)), |
| cumulative_frame_count(0) { |
| cumulative_bins.fill(0); |
| } |
| |
| std::unique_ptr<histogram::Ringbuffer> histogram::Ringbuffer::create( |
| size_t ringbuffer_size, std::unique_ptr<histogram::TimeKeeper> tk) { |
| if ((ringbuffer_size == 0) || !tk) |
| return nullptr; |
| return std::unique_ptr<histogram::Ringbuffer>(new histogram::Ringbuffer(ringbuffer_size, std::move(tk))); |
| } |
| |
| void histogram::Ringbuffer::update_cumulative(nsecs_t now, |
| uint64_t& count, std::array<uint64_t, HIST_V_SIZE>& bins) const { |
| |
| if (ringbuffer.empty()) |
| return; |
| |
| count++; |
| |
| const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>( |
| std::chrono::nanoseconds(now - ringbuffer.front().start_timestamp)); |
| |
| for (auto i = 0u; i < bins.size(); i++) { |
| auto const increment = ringbuffer.front().histogram.data[i] * delta.count(); |
| if (CC_UNLIKELY((bins[i] + increment < bins[i]) || (increment < ringbuffer.front().histogram.data[i]))) { |
| bins[i] = std::numeric_limits<uint64_t>::max(); |
| } else { |
| bins[i] += increment; |
| } |
| } |
| } |
| |
| void histogram::Ringbuffer::insert(drm_msm_hist const& frame) { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| auto now = timekeeper->current_time(); |
| update_cumulative(now, cumulative_frame_count, cumulative_bins); |
| |
| if (ringbuffer.size() == rb_max_size) |
| ringbuffer.pop_back(); |
| if (!ringbuffer.empty()) |
| ringbuffer.front().end_timestamp = now; |
| ringbuffer.push_front({frame, now, 0}); |
| } |
| |
| bool histogram::Ringbuffer::resize(size_t ringbuffer_size) { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| if (ringbuffer_size == 0) |
| return false; |
| rb_max_size = ringbuffer_size; |
| if (ringbuffer.size() > rb_max_size) |
| ringbuffer.resize(rb_max_size); |
| return true; |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_cumulative() const { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| histogram::Ringbuffer::Sample sample { cumulative_frame_count, cumulative_bins }; |
| update_cumulative(timekeeper->current_time(), std::get<0>(sample), std::get<1>(sample)); |
| return sample; |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_ringbuffer_all() const { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| return collect_max(ringbuffer.size(), lk); |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_after( |
| nsecs_t timestamp) const { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| return collect_max_after(timestamp, ringbuffer.size(), lk); |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max(uint32_t max_frames) const { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| return collect_max(max_frames, lk); |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max_after( |
| nsecs_t timestamp, uint32_t max_frames) const { |
| std::unique_lock<decltype(mutex)> lk(mutex); |
| return collect_max_after(timestamp, max_frames, lk); |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max( |
| uint32_t max_frames, std::unique_lock<std::mutex> const&) const { |
| auto collect_first = std::min(static_cast<size_t>(max_frames), ringbuffer.size()); |
| if (collect_first == 0) |
| return {0, {}}; |
| std::array<uint64_t, HIST_V_SIZE> bins; |
| bins.fill(0); |
| for (auto it = ringbuffer.begin(); it != ringbuffer.begin() + collect_first; it++) { |
| nsecs_t end_timestamp = it->end_timestamp; |
| if (it == ringbuffer.begin() ) { |
| end_timestamp = timekeeper->current_time(); |
| } |
| const auto time_displayed = std::chrono::nanoseconds(end_timestamp - it->start_timestamp); |
| const auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(time_displayed); |
| for (auto i = 0u; i < HIST_V_SIZE; i++) { |
| bins[i] += it->histogram.data[i] * delta.count(); |
| } |
| } |
| return { collect_first, bins }; |
| } |
| |
| histogram::Ringbuffer::Sample histogram::Ringbuffer::collect_max_after( |
| nsecs_t timestamp, uint32_t max_frames, std::unique_lock<std::mutex> const& lk) const { |
| auto ts_filter_begin = std::lower_bound( |
| ringbuffer.begin(), ringbuffer.end(), HistogramEntry{{}, timestamp, 0}, |
| [](auto const &a, auto const &b) { return a.start_timestamp >= b.start_timestamp; }); |
| |
| auto collect_last = std::min(std::distance(ringbuffer.begin(), ts_filter_begin), |
| static_cast<std::ptrdiff_t>(max_frames)); |
| return collect_max(collect_last, lk); |
| } |