27 (
void)snprintf(
buf,
sizeof(
buf),
"Reached set memory limit (attempted: %zu, used: %zu, max: %zu)", attempted, used,
max);
29 (
void)snprintf(
buf,
sizeof(
buf),
"New set maximum below current used (newMax: %zu, used: %zu)",
max, used);
41 static std::pmr::synchronized_pool_resource pool{std::pmr::get_default_resource()};
46 : mMaxMemory(maxBytes), mUpstream(upstream != nullptr ? upstream :
cachingUpstream())
51 : mMaxMemory(maxBytes), mOwnedUpstream(
std::move(upstream)), mUpstream(mOwnedUpstream.
get())
55void* BoundedMemoryResource::do_allocate(
size_t bytes,
size_t alignment)
58 size_t currentUsed{mUsedMemory.load(std::memory_order_relaxed)};
60 newUsed = currentUsed + bytes;
61 if (newUsed > mMaxMemory.load(std::memory_order_relaxed)) {
62 mCountThrow.fetch_add(1, std::memory_order_relaxed);
63 throw MemoryLimitExceeded(newUsed, currentUsed, mMaxMemory.load(std::memory_order_relaxed));
65 }
while (!mUsedMemory.compare_exchange_weak(currentUsed, newUsed, std::memory_order_acq_rel, std::memory_order_relaxed));
69 p = mUpstream->allocate(bytes, alignment);
71 mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed);
72#ifdef BOUNDED_MR_STATS
73 mStats.upstreamFailures.fetch_add(1, std::memory_order_relaxed);
78 size_t peak = mPeakUsedMemory.load(std::memory_order_relaxed);
79 while (newUsed > peak && !mPeakUsedMemory.compare_exchange_weak(peak, newUsed, std::memory_order_relaxed)) {
82#ifdef BOUNDED_MR_STATS
83 size_t statsPeak = mStats.peak.load(std::memory_order_relaxed);
84 while (newUsed > statsPeak && !mStats.peak.compare_exchange_weak(statsPeak, newUsed, std::memory_order_relaxed)) {
86 mStats.live.fetch_add(1, std::memory_order_relaxed);
87 mStats.nAlloc.fetch_add(1, std::memory_order_relaxed);
88 mStats.totalAlloc.fetch_add(bytes, std::memory_order_relaxed);
90 size_t maxAlignment = mStats.maxAlign.load(std::memory_order_relaxed);
91 while (alignment > maxAlignment && !mStats.maxAlign.compare_exchange_weak(maxAlignment, alignment, std::memory_order_relaxed)) {
97void BoundedMemoryResource::do_deallocate(
void* p,
size_t bytes,
size_t alignment)
99 mUpstream->deallocate(p, bytes, alignment);
100 mUsedMemory.fetch_sub(bytes, std::memory_order_relaxed);
101#ifdef BOUNDED_MR_STATS
102 mStats.live.fetch_sub(1, std::memory_order_relaxed);
103 mStats.nFree.fetch_add(1, std::memory_order_relaxed);
104 mStats.totalFreed.fetch_add(bytes, std::memory_order_relaxed);
110 return this == &
other;
115 return mUsedMemory.load(std::memory_order_relaxed);
120 return mMaxMemory.load(std::memory_order_relaxed);
125 return mCountThrow.load(std::memory_order_relaxed);
130 return mPeakUsedMemory.load(std::memory_order_relaxed);
135 const size_t peak = mPeakUsedMemory.load(std::memory_order_relaxed);
136 const size_t baseline = mPeakBaselineMemory.load(std::memory_order_relaxed);
137 return peak > baseline ? peak - baseline : 0;
142 const size_t used = mUsedMemory.load(std::memory_order_acquire);
143 mPeakBaselineMemory.store(used, std::memory_order_release);
144 mPeakUsedMemory.store(used, std::memory_order_release);
149 size_t current = mMaxMemory.load(std::memory_order_relaxed);
150 if (
max == current) {
154 const size_t used = mUsedMemory.load(std::memory_order_acquire);
156 mCountThrow.fetch_add(1, std::memory_order_relaxed);
159 if (mMaxMemory.compare_exchange_weak(current,
max, std::memory_order_release, std::memory_order_relaxed)) {
162 if (current ==
max) {
170 const auto throwCount = mCountThrow.load(std::memory_order_relaxed);
171 const auto used =
static_cast<double>(mUsedMemory.load(std::memory_order_relaxed));
172 const auto peak =
static_cast<double>(mPeakUsedMemory.load(std::memory_order_relaxed));
174 const auto maxMemory = mMaxMemory.load(std::memory_order_relaxed);
176 if (maxMemory == std::numeric_limits<size_t>::max()) {
181#ifdef BOUNDED_MR_STATS
182 result += std::format(
" peak={:.2f} GB live={} nAlloc={} nFree={} totalAlloc={:.2f} GB totalFreed={:.2f} GB maxAlign={} upstreamFail={}",
184 mStats.live.load(std::memory_order_relaxed),
185 mStats.nAlloc.load(std::memory_order_relaxed),
186 mStats.nFree.load(std::memory_order_relaxed),
189 mStats.maxAlign.load(std::memory_order_relaxed),
190 mStats.upstreamFailures.load(std::memory_order_relaxed));
MemoryLimitExceeded(size_t attempted, size_t used, size_t max)
const char * what() const noexcept final
size_t getThrowCount() const noexcept
std::string asString() const
void resetPeakMemory() noexcept
size_t getUsedMemory() const noexcept
void setMaxMemory(size_t max)
static std::pmr::memory_resource * cachingUpstream()
size_t getMaxMemory() const noexcept
BoundedMemoryResource(size_t maxBytes=std::numeric_limits< size_t >::max(), std::pmr::memory_resource *upstream=nullptr)
size_t getPeakMemory() const noexcept
size_t getPeakMemoryDelta() const noexcept
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLenum GLuint GLenum GLsizei const GLchar * buf
VectorOfTObjectPtrs other