xref: /aosp_15_r20/external/perfetto/src/profiling/perf/unwind_queue.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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