NVIDIA DeepStream SDK API Reference

9.2 Release
9.2/includes/opentelemetry/sdk/common/circular_buffer.h
Go to the documentation of this file.
1 // Copyright The OpenTelemetry Authors
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include <atomic>
7 #include <cassert>
8 #include <cstddef>
9 #include <cstdint>
10 #include <functional>
11 #include <memory>
12 
13 #include "opentelemetry/nostd/span.h"
14 #include "opentelemetry/sdk/common/atomic_unique_ptr.h"
15 #include "opentelemetry/sdk/common/circular_buffer_range.h"
16 #include "opentelemetry/version.h"
17 
19 namespace sdk
20 {
21 namespace common
22 {
23 /*
24  * A lock-free circular buffer that supports multiple concurrent producers
25  * and a single consumer.
26  */
27 template <class T>
28 class CircularBuffer
29 {
30 public:
31  explicit CircularBuffer(size_t max_size)
32  : data_{new AtomicUniquePtr<T>[max_size + 1]}, capacity_{max_size + 1}
33  {}
34 
41  {
42  return const_cast<CircularBuffer *>(this)->PeekImpl();
43  }
44 
55  template <class Callback>
56  void Consume(size_t n, Callback callback) noexcept
57  {
58  assert(n <= static_cast<size_t>(head_ - tail_));
59  auto range = PeekImpl().Take(n);
60  static_assert(noexcept(callback(range)), "callback not allowed to throw");
61  tail_ += n;
62  callback(range);
63  }
64 
71  void Consume(size_t n) noexcept
72  {
73  Consume(n, [](CircularBufferRange<AtomicUniquePtr<T>> &range) noexcept {
74  range.ForEach([](AtomicUniquePtr<T> &ptr) noexcept {
75  ptr.Reset();
76  return true;
77  });
78  });
79  }
80 
86  bool Add(std::unique_ptr<T> &ptr) noexcept
87  {
88  while (true)
89  {
90  uint64_t tail = tail_;
91  uint64_t head = head_;
92 
93  // The circular buffer is full, so return false.
94  if (head - tail >= capacity_ - 1)
95  {
96  return false;
97  }
98 
99  uint64_t head_index = head % capacity_;
100  if (data_[head_index].SwapIfNull(ptr))
101  {
102  auto new_head = head + 1;
103  auto expected_head = head;
104  if (head_.compare_exchange_weak(expected_head, new_head, std::memory_order_release,
105  std::memory_order_relaxed))
106  {
107  // free the swapped out value
108  ptr.reset();
109 
110  return true;
111  }
112 
113  // If we reached this point (unlikely), it means that between the last
114  // iteration elements were added and then consumed from the circular
115  // buffer, so we undo the swap and attempt to add again.
116  data_[head_index].Swap(ptr);
117  }
118  }
119  }
120 
121  bool Add(std::unique_ptr<T> &&ptr) noexcept
122  {
123  // rvalue to lvalue reference
124  bool result = Add(std::ref(ptr));
125  ptr.reset();
126  return result;
127  }
128 
134  void Clear() noexcept { Consume(size()); }
135 
139  size_t max_size() const noexcept { return capacity_ - 1; }
140 
144  bool empty() const noexcept { return head_ == tail_; }
145 
152  size_t size() const noexcept
153  {
154  uint64_t tail = tail_;
155  uint64_t head = head_;
156  assert(tail <= head);
157  return head - tail;
158  }
159 
163  uint64_t consumption_count() const noexcept { return tail_; }
164 
168  uint64_t production_count() const noexcept { return head_; }
169 
170 private:
171  std::unique_ptr<AtomicUniquePtr<T>[]> data_;
172  size_t capacity_;
173  std::atomic<uint64_t> head_{0};
174  std::atomic<uint64_t> tail_{0};
175 
176  CircularBufferRange<AtomicUniquePtr<T>> PeekImpl() noexcept
177  {
178  uint64_t tail_index = tail_ % capacity_;
179  uint64_t head_index = head_ % capacity_;
180  if (head_index == tail_index)
181  {
182  return {};
183  }
184  AtomicUniquePtr<T> *data = data_.get();
185  if (tail_index < head_index)
186  {
187  return CircularBufferRange<AtomicUniquePtr<T>>{nostd::span<AtomicUniquePtr<T>>{
188  data + tail_index, static_cast<std::size_t>(head_index - tail_index)}};
189  }
190  return {nostd::span<AtomicUniquePtr<T>>{data + tail_index,
191  static_cast<std::size_t>(capacity_ - tail_index)},
192  nostd::span<AtomicUniquePtr<T>>{data, static_cast<std::size_t>(head_index)}};
193  }
194 };
195 } // namespace common
196 } // namespace sdk
sdk::common::AtomicUniquePtr::Reset
void Reset(T *ptr=nullptr) noexcept
Set the pointer to a new value and delete the current value if non-null.
Definition: includes/opentelemetry/sdk/common/atomic_unique_ptr.h:72
sdk::common::CircularBuffer::max_size
size_t max_size() const noexcept
Definition: includes/opentelemetry/sdk/common/circular_buffer.h:139
sdk::common::CircularBuffer::size
size_t size() const noexcept
Definition: includes/opentelemetry/sdk/common/circular_buffer.h:152
sdk::common::CircularBuffer::Add
bool Add(std::unique_ptr< T > &&ptr) noexcept
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:121
sdk::common::CircularBuffer::Consume
void Consume(size_t n, Callback callback) noexcept
Consume elements from the circular buffer's tail.
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:56
sdk::common::CircularBuffer::Peek
CircularBufferRange< const AtomicUniquePtr< T > > Peek() const noexcept
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:40
OPENTELEMETRY_BEGIN_NAMESPACE
#define OPENTELEMETRY_BEGIN_NAMESPACE
Definition: includes/opentelemetry/version.h:21
sdk::common::CircularBuffer::Consume
void Consume(size_t n) noexcept
Consume elements from the circular buffer's tail.
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:71
nostd::span
Back port of std::span.
Definition: includes/opentelemetry/nostd/span.h:51
sdk::common::CircularBuffer::CircularBuffer
CircularBuffer(size_t max_size)
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:31
sdk::common::CircularBuffer::Clear
void Clear() noexcept
Clear the circular buffer.
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:134
OPENTELEMETRY_END_NAMESPACE
#define OPENTELEMETRY_END_NAMESPACE
Definition: includes/opentelemetry/version.h:24
sdk::common::AtomicUniquePtr
An owning pointer similar to std::unique_ptr but with methods for atomic operations.
Definition: includes/opentelemetry/sdk/common/atomic_unique_ptr.h:21
sdk::common::CircularBuffer::empty
bool empty() const noexcept
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:144
sdk::common::CircularBuffer::consumption_count
uint64_t consumption_count() const noexcept
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:163
sdk::common::CircularBuffer::Add
bool Add(std::unique_ptr< T > &ptr) noexcept
Adds an element into the circular buffer.
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:86
sdk
Definition: includes/opentelemetry/sdk/common/atomic_shared_ptr.h:13
data
JSAMPIMAGE data
Definition: sources/libs/nvll_batch_jpeg_encode/oss/jpeglib.h:967
sdk::common::CircularBuffer::production_count
uint64_t production_count() const noexcept
Definition: 9.2/includes/opentelemetry/sdk/common/circular_buffer.h:168
sdk::common::CircularBuffer
Definition: includes/opentelemetry/sdk/common/circular_buffer.h:28
common
Definition: includes/opentelemetry/common/attribute_value.h:14
sdk::common::CircularBufferRange
A non-owning view into a range of elements in a circular buffer.
Definition: includes/opentelemetry/sdk/common/circular_buffer_range.h:22