PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
pdu_buffer_pool.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
17#pragma once
18
19#include "pdu_types.h"
20#include "pdu_decoder.h"
21
22#include <kcenon/common/utils/object_pool.h>
23
24#include <atomic>
25#include <cstddef>
26#include <cstdint>
27#include <functional>
28#include <memory>
29#include <vector>
30
31namespace kcenon::pacs::network {
32
37 std::atomic<uint64_t> total_acquisitions{0};
38 std::atomic<uint64_t> pool_hits{0};
39 std::atomic<uint64_t> pool_misses{0};
40 std::atomic<uint64_t> total_releases{0};
41 std::atomic<uint64_t> total_bytes_allocated{0};
42
47 [[nodiscard]] auto hit_ratio() const noexcept -> double {
48 const uint64_t total = total_acquisitions.load(std::memory_order_relaxed);
49 if (total == 0) {
50 return 0.0;
51 }
52 return static_cast<double>(pool_hits.load(std::memory_order_relaxed))
53 / static_cast<double>(total);
54 }
55
59 void reset() noexcept {
60 total_acquisitions.store(0, std::memory_order_relaxed);
61 pool_hits.store(0, std::memory_order_relaxed);
62 pool_misses.store(0, std::memory_order_relaxed);
63 total_releases.store(0, std::memory_order_relaxed);
64 total_bytes_allocated.store(0, std::memory_order_relaxed);
65 }
66};
67
76public:
77 pooled_buffer() = default;
78
82 void clear() noexcept { data_.clear(); }
83
88 void resize(std::size_t new_size) { data_.resize(new_size); }
89
94 void reserve(std::size_t capacity) { data_.reserve(capacity); }
95
100 [[nodiscard]] auto size() const noexcept -> std::size_t {
101 return data_.size();
102 }
103
108 [[nodiscard]] auto capacity() const noexcept -> std::size_t {
109 return data_.capacity();
110 }
111
116 [[nodiscard]] auto data() noexcept -> uint8_t* { return data_.data(); }
117
122 [[nodiscard]] auto data() const noexcept -> const uint8_t* {
123 return data_.data();
124 }
125
130 [[nodiscard]] auto vector() noexcept -> std::vector<uint8_t>& {
131 return data_;
132 }
133
138 [[nodiscard]] auto vector() const noexcept -> const std::vector<uint8_t>& {
139 return data_;
140 }
141
145 [[nodiscard]] auto operator[](std::size_t index) -> uint8_t& {
146 return data_[index];
147 }
148
152 [[nodiscard]] auto operator[](std::size_t index) const -> const uint8_t& {
153 return data_[index];
154 }
155
156private:
157 std::vector<uint8_t> data_;
158};
159
164template <typename T>
166public:
167 using pool_type = kcenon::common::utils::ObjectPool<T>;
168 using unique_ptr_type = std::unique_ptr<T, std::function<void(T*)>>;
169
170 explicit tracked_pdu_pool(std::size_t initial_size = 64)
171 : pool_(initial_size) {
172 pool_.reserve(initial_size);
173 }
174
180 template <typename... Args>
181 auto acquire(Args&&... args) -> unique_ptr_type {
182 bool reused = false;
183 auto ptr = pool_.acquire(&reused, std::forward<Args>(args)...);
184
185 stats_.total_acquisitions.fetch_add(1, std::memory_order_relaxed);
186 if (reused) {
187 stats_.pool_hits.fetch_add(1, std::memory_order_relaxed);
188 } else {
189 stats_.pool_misses.fetch_add(1, std::memory_order_relaxed);
190 }
191
192 return ptr;
193 }
194
199 [[nodiscard]] auto statistics() const noexcept -> const pdu_pool_statistics& {
200 return stats_;
201 }
202
207 [[nodiscard]] auto available() const -> std::size_t {
208 return pool_.available();
209 }
210
215 void reserve(std::size_t count) {
216 pool_.reserve(count);
217 }
218
222 void clear() {
223 pool_.clear();
224 }
225
226private:
229};
230
250public:
252 static constexpr std::size_t DEFAULT_BUFFER_POOL_SIZE = 256;
253 static constexpr std::size_t DEFAULT_PDV_POOL_SIZE = 128;
254 static constexpr std::size_t DEFAULT_PDATA_POOL_SIZE = 64;
255
260 static auto get() noexcept -> pdu_buffer_pool&;
261
266 auto acquire_buffer()
267 -> tracked_pdu_pool<pooled_buffer>::unique_ptr_type;
268
276 auto acquire_pdv(uint8_t context_id = 0, bool is_command = false,
277 bool is_last = true)
278 -> tracked_pdu_pool<presentation_data_value>::unique_ptr_type;
279
284 auto acquire_p_data_tf()
285 -> tracked_pdu_pool<p_data_tf_pdu>::unique_ptr_type;
286
291 [[nodiscard]] auto buffer_statistics() const noexcept
292 -> const pdu_pool_statistics&;
293
298 [[nodiscard]] auto pdv_statistics() const noexcept
299 -> const pdu_pool_statistics&;
300
305 [[nodiscard]] auto p_data_statistics() const noexcept
306 -> const pdu_pool_statistics&;
307
312 void reserve_buffers(std::size_t count);
313
318 void reserve_pdvs(std::size_t count);
319
323 void clear_all();
324
328 void reset_statistics();
329
330 // Non-copyable, non-movable
333 auto operator=(const pdu_buffer_pool&) -> pdu_buffer_pool& = delete;
334 auto operator=(pdu_buffer_pool&&) -> pdu_buffer_pool& = delete;
335
336private:
338 ~pdu_buffer_pool() = default;
339
343};
344
345// ============================================================================
346// Convenience Factory Functions
347// ============================================================================
348
353[[nodiscard]] inline auto make_pooled_pdu_buffer()
354 -> tracked_pdu_pool<pooled_buffer>::unique_ptr_type {
355 return pdu_buffer_pool::get().acquire_buffer();
356}
357
363[[nodiscard]] inline auto make_pooled_pdu_buffer(std::size_t size)
365 auto buffer = pdu_buffer_pool::get().acquire_buffer();
366 buffer->resize(size);
367 return buffer;
368}
369
377[[nodiscard]] inline auto make_pooled_pdv(uint8_t context_id = 0,
378 bool is_command = false,
379 bool is_last = true)
381 return pdu_buffer_pool::get().acquire_pdv(context_id, is_command, is_last);
382}
383
388[[nodiscard]] inline auto make_pooled_p_data_tf()
390 return pdu_buffer_pool::get().acquire_p_data_tf();
391}
392
393} // namespace kcenon::pacs::network
tracked_pdu_pool< p_data_tf_pdu > p_data_pool_
auto acquire_p_data_tf() -> tracked_pdu_pool< p_data_tf_pdu >::unique_ptr_type
Acquire a p_data_tf_pdu from the pool.
void reserve_buffers(std::size_t count)
Reserve capacity in buffer pool.
tracked_pdu_pool< presentation_data_value > pdv_pool_
static constexpr std::size_t DEFAULT_PDV_POOL_SIZE
static constexpr std::size_t DEFAULT_PDATA_POOL_SIZE
auto pdv_statistics() const noexcept -> const pdu_pool_statistics &
Get PDV pool statistics.
auto acquire_buffer() -> tracked_pdu_pool< pooled_buffer >::unique_ptr_type
Acquire a byte buffer from the pool.
static constexpr std::size_t DEFAULT_BUFFER_POOL_SIZE
Default pool sizes.
auto buffer_statistics() const noexcept -> const pdu_pool_statistics &
Get buffer pool statistics.
void reset_statistics()
Reset all statistics.
tracked_pdu_pool< pooled_buffer > buffer_pool_
void reserve_pdvs(std::size_t count)
Reserve capacity in PDV pool.
static auto get() noexcept -> pdu_buffer_pool &
Get the global PDU buffer pool instance.
auto acquire_pdv(uint8_t context_id=0, bool is_command=false, bool is_last=true) -> tracked_pdu_pool< presentation_data_value >::unique_ptr_type
Acquire a presentation_data_value from the pool.
auto p_data_statistics() const noexcept -> const pdu_pool_statistics &
Get P-DATA-TF pool statistics.
Pooled byte buffer for PDU data.
void clear() noexcept
Clear the buffer contents (keeps capacity)
auto vector() const noexcept -> const std::vector< uint8_t > &
Get const reference to underlying vector.
auto data() noexcept -> uint8_t *
Get raw pointer to data.
auto data() const noexcept -> const uint8_t *
Get const raw pointer to data.
auto operator[](std::size_t index) const -> const uint8_t &
Const array access operator.
auto size() const noexcept -> std::size_t
Get the current size.
void reserve(std::size_t capacity)
Reserve capacity.
auto vector() noexcept -> std::vector< uint8_t > &
Get reference to underlying vector.
auto operator[](std::size_t index) -> uint8_t &
Array access operator.
void resize(std::size_t new_size)
Resize the buffer.
auto capacity() const noexcept -> std::size_t
Get the current capacity.
Pool wrapper with statistics tracking for PDU buffers.
std::unique_ptr< T, std::function< void(T *)> > unique_ptr_type
void clear()
Clear the pool and release all memory.
auto statistics() const noexcept -> const pdu_pool_statistics &
Get the pool statistics.
auto available() const -> std::size_t
Get the number of available objects in the pool.
auto acquire(Args &&... args) -> unique_ptr_type
Acquire an object from the pool.
void reserve(std::size_t count)
Reserve additional capacity in the pool.
kcenon::common::utils::ObjectPool< T > pool_type
tracked_pdu_pool(std::size_t initial_size=64)
auto make_pooled_pdu_buffer() -> tracked_pdu_pool< pooled_buffer >::unique_ptr_type
Create a pooled byte buffer.
auto make_pooled_p_data_tf() -> tracked_pdu_pool< p_data_tf_pdu >::unique_ptr_type
Create a pooled p_data_tf_pdu.
auto make_pooled_pdv(uint8_t context_id=0, bool is_command=false, bool is_last=true) -> tracked_pdu_pool< presentation_data_value >::unique_ptr_type
Create a pooled presentation_data_value.
Statistics for PDU buffer pool usage monitoring.
auto hit_ratio() const noexcept -> double
Calculate hit ratio (0.0 to 1.0)
void reset() noexcept
Reset all statistics.
Presentation Data Value (PDV) item for P-DATA-TF.
Definition pdu_types.h:135