1*6dbdd20aSAndroid Build Coastguard Worker /* 2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project 3*6dbdd20aSAndroid Build Coastguard Worker * 4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*6dbdd20aSAndroid Build Coastguard Worker * 8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*6dbdd20aSAndroid Build Coastguard Worker * 10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License. 15*6dbdd20aSAndroid Build Coastguard Worker */ 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Worker #ifndef SRC_PROFILING_PERF_UNWIND_QUEUE_H_ 18*6dbdd20aSAndroid Build Coastguard Worker #define SRC_PROFILING_PERF_UNWIND_QUEUE_H_ 19*6dbdd20aSAndroid Build Coastguard Worker 20*6dbdd20aSAndroid Build Coastguard Worker #include <array> 21*6dbdd20aSAndroid Build Coastguard Worker #include <atomic> 22*6dbdd20aSAndroid Build Coastguard Worker 23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h" 24*6dbdd20aSAndroid Build Coastguard Worker 25*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto { 26*6dbdd20aSAndroid Build Coastguard Worker namespace profiling { 27*6dbdd20aSAndroid Build Coastguard Worker 28*6dbdd20aSAndroid Build Coastguard Worker struct WriteView { 29*6dbdd20aSAndroid Build Coastguard Worker bool valid; // if false: buffer is full, and |write_pos| is invalid 30*6dbdd20aSAndroid Build Coastguard Worker uint64_t write_pos; 31*6dbdd20aSAndroid Build Coastguard Worker }; 32*6dbdd20aSAndroid Build Coastguard Worker 33*6dbdd20aSAndroid Build Coastguard Worker struct ReadView { 34*6dbdd20aSAndroid Build Coastguard Worker uint64_t read_pos; 35*6dbdd20aSAndroid Build Coastguard Worker uint64_t write_pos; 36*6dbdd20aSAndroid Build Coastguard Worker }; 37*6dbdd20aSAndroid Build Coastguard Worker 38*6dbdd20aSAndroid Build Coastguard Worker // Single-writer, single-reader ring buffer of fixed-size entries (of any 39*6dbdd20aSAndroid Build Coastguard Worker // default-constructible type). Size of the buffer is static for the lifetime of 40*6dbdd20aSAndroid Build Coastguard Worker // UnwindQueue, and must be a power of two. 41*6dbdd20aSAndroid Build Coastguard Worker // Writer side appends entries one at a time, and must stop if there 42*6dbdd20aSAndroid Build Coastguard Worker // is no available capacity. 43*6dbdd20aSAndroid Build Coastguard Worker // Reader side sees all unconsumed entries, and can advance the reader position 44*6dbdd20aSAndroid Build Coastguard Worker // by any amount. 45*6dbdd20aSAndroid Build Coastguard Worker template <typename T, uint32_t QueueSize> 46*6dbdd20aSAndroid Build Coastguard Worker class UnwindQueue { 47*6dbdd20aSAndroid Build Coastguard Worker public: UnwindQueue()48*6dbdd20aSAndroid Build Coastguard Worker UnwindQueue() { 49*6dbdd20aSAndroid Build Coastguard Worker static_assert(QueueSize != 0 && ((QueueSize & (QueueSize - 1)) == 0), 50*6dbdd20aSAndroid Build Coastguard Worker "not a power of two"); 51*6dbdd20aSAndroid Build Coastguard Worker } 52*6dbdd20aSAndroid Build Coastguard Worker 53*6dbdd20aSAndroid Build Coastguard Worker UnwindQueue(const UnwindQueue&) = delete; 54*6dbdd20aSAndroid Build Coastguard Worker UnwindQueue& operator=(const UnwindQueue&) = delete; 55*6dbdd20aSAndroid Build Coastguard Worker UnwindQueue(UnwindQueue&&) = delete; 56*6dbdd20aSAndroid Build Coastguard Worker UnwindQueue& operator=(UnwindQueue&&) = delete; 57*6dbdd20aSAndroid Build Coastguard Worker at(uint64_t pos)58*6dbdd20aSAndroid Build Coastguard Worker T& at(uint64_t pos) { return data_[pos % QueueSize]; } 59*6dbdd20aSAndroid Build Coastguard Worker BeginWrite()60*6dbdd20aSAndroid Build Coastguard Worker WriteView BeginWrite() { 61*6dbdd20aSAndroid Build Coastguard Worker uint64_t rd = rd_pos_.load(std::memory_order_acquire); 62*6dbdd20aSAndroid Build Coastguard Worker uint64_t wr = wr_pos_.load(std::memory_order_relaxed); 63*6dbdd20aSAndroid Build Coastguard Worker 64*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(wr >= rd); 65*6dbdd20aSAndroid Build Coastguard Worker if (wr - rd >= QueueSize) 66*6dbdd20aSAndroid Build Coastguard Worker return WriteView{false, 0}; // buffer fully occupied 67*6dbdd20aSAndroid Build Coastguard Worker 68*6dbdd20aSAndroid Build Coastguard Worker return WriteView{true, wr}; 69*6dbdd20aSAndroid Build Coastguard Worker } 70*6dbdd20aSAndroid Build Coastguard Worker CommitWrite()71*6dbdd20aSAndroid Build Coastguard Worker void CommitWrite() { wr_pos_.fetch_add(1u, std::memory_order_release); } 72*6dbdd20aSAndroid Build Coastguard Worker BeginRead()73*6dbdd20aSAndroid Build Coastguard Worker ReadView BeginRead() { 74*6dbdd20aSAndroid Build Coastguard Worker uint64_t wr = wr_pos_.load(std::memory_order_acquire); 75*6dbdd20aSAndroid Build Coastguard Worker uint64_t rd = rd_pos_.load(std::memory_order_relaxed); 76*6dbdd20aSAndroid Build Coastguard Worker 77*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(wr >= rd && wr - rd <= QueueSize); 78*6dbdd20aSAndroid Build Coastguard Worker return ReadView{rd, wr}; 79*6dbdd20aSAndroid Build Coastguard Worker } 80*6dbdd20aSAndroid Build Coastguard Worker CommitNewReadPosition(uint64_t pos)81*6dbdd20aSAndroid Build Coastguard Worker void CommitNewReadPosition(uint64_t pos) { 82*6dbdd20aSAndroid Build Coastguard Worker rd_pos_.store(pos, std::memory_order_release); 83*6dbdd20aSAndroid Build Coastguard Worker } 84*6dbdd20aSAndroid Build Coastguard Worker 85*6dbdd20aSAndroid Build Coastguard Worker private: 86*6dbdd20aSAndroid Build Coastguard Worker std::array<T, QueueSize> data_; 87*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint64_t> wr_pos_{0}; 88*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint64_t> rd_pos_{0}; 89*6dbdd20aSAndroid Build Coastguard Worker }; 90*6dbdd20aSAndroid Build Coastguard Worker 91*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling 92*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto 93*6dbdd20aSAndroid Build Coastguard Worker 94*6dbdd20aSAndroid Build Coastguard Worker #endif // SRC_PROFILING_PERF_UNWIND_QUEUE_H_ 95