|
|
@ -19,7 +19,6 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include <stdint.h> |
|
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
|
|
|
|
#include <array> |
|
|
|
|
|
|
|
#include <atomic> |
|
|
|
#include <atomic> |
|
|
|
#include <cstddef> |
|
|
|
#include <cstddef> |
|
|
|
#include <limits> |
|
|
|
#include <limits> |
|
|
@ -28,7 +27,6 @@ |
|
|
|
#include <utility> |
|
|
|
#include <utility> |
|
|
|
|
|
|
|
|
|
|
|
#include "absl/base/thread_annotations.h" |
|
|
|
#include "absl/base/thread_annotations.h" |
|
|
|
#include "absl/container/flat_hash_set.h" |
|
|
|
|
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
#include "absl/types/optional.h" |
|
|
|
#include "absl/types/optional.h" |
|
|
|
|
|
|
|
|
|
|
@ -37,7 +35,6 @@ |
|
|
|
#include <grpc/support/log.h> |
|
|
|
#include <grpc/support/log.h> |
|
|
|
|
|
|
|
|
|
|
|
#include "src/core/lib/experiments/experiments.h" |
|
|
|
#include "src/core/lib/experiments/experiments.h" |
|
|
|
#include "src/core/lib/gpr/useful.h" |
|
|
|
|
|
|
|
#include "src/core/lib/gprpp/orphanable.h" |
|
|
|
#include "src/core/lib/gprpp/orphanable.h" |
|
|
|
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
|
|
|
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
|
|
|
#include "src/core/lib/gprpp/sync.h" |
|
|
|
#include "src/core/lib/gprpp/sync.h" |
|
|
@ -45,13 +42,11 @@ |
|
|
|
#include "src/core/lib/promise/activity.h" |
|
|
|
#include "src/core/lib/promise/activity.h" |
|
|
|
#include "src/core/lib/promise/poll.h" |
|
|
|
#include "src/core/lib/promise/poll.h" |
|
|
|
#include "src/core/lib/resource_quota/periodic_update.h" |
|
|
|
#include "src/core/lib/resource_quota/periodic_update.h" |
|
|
|
#include "src/core/lib/resource_quota/trace.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
|
|
class BasicMemoryQuota; |
|
|
|
class BasicMemoryQuota; |
|
|
|
class MemoryQuota; |
|
|
|
class MemoryQuota; |
|
|
|
class GrpcMemoryAllocatorImpl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using grpc_event_engine::experimental::MemoryRequest; |
|
|
|
using grpc_event_engine::experimental::MemoryRequest; |
|
|
|
|
|
|
|
|
|
|
@ -279,12 +274,6 @@ class PressureTracker { |
|
|
|
}; |
|
|
|
}; |
|
|
|
} // namespace memory_quota_detail
|
|
|
|
} // namespace memory_quota_detail
|
|
|
|
|
|
|
|
|
|
|
|
// Minimum number of free bytes in order for allocator to move to big bucket.
|
|
|
|
|
|
|
|
static constexpr size_t kBigAllocatorThreshold = 0.5 * 1024 * 1024; |
|
|
|
|
|
|
|
// Maximum number of free bytes in order for allocator to move to small
|
|
|
|
|
|
|
|
// bucket.
|
|
|
|
|
|
|
|
static constexpr size_t kSmallAllocatorThreshold = 0.1 * 1024 * 1024; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BasicMemoryQuota final |
|
|
|
class BasicMemoryQuota final |
|
|
|
: public std::enable_shared_from_this<BasicMemoryQuota> { |
|
|
|
: public std::enable_shared_from_this<BasicMemoryQuota> { |
|
|
|
public: |
|
|
|
public: |
|
|
@ -318,13 +307,6 @@ class BasicMemoryQuota final |
|
|
|
void FinishReclamation(uint64_t token, Waker waker); |
|
|
|
void FinishReclamation(uint64_t token, Waker waker); |
|
|
|
// Return some memory to the quota.
|
|
|
|
// Return some memory to the quota.
|
|
|
|
void Return(size_t amount); |
|
|
|
void Return(size_t amount); |
|
|
|
// Add allocator to list of allocators in small bucket. Returns allocator id.
|
|
|
|
|
|
|
|
void AddNewAllocator(GrpcMemoryAllocatorImpl* allocator); |
|
|
|
|
|
|
|
// Remove allocator from list of allocators.
|
|
|
|
|
|
|
|
void RemoveAllocator(GrpcMemoryAllocatorImpl* allocator); |
|
|
|
|
|
|
|
// Determine whether to move allocator to different bucket and if so, move.
|
|
|
|
|
|
|
|
void MaybeMoveAllocator(GrpcMemoryAllocatorImpl* allocator, |
|
|
|
|
|
|
|
size_t old_free_bytes, size_t new_free_bytes); |
|
|
|
|
|
|
|
// Instantaneous memory pressure approximation.
|
|
|
|
// Instantaneous memory pressure approximation.
|
|
|
|
PressureInfo GetPressureInfo(); |
|
|
|
PressureInfo GetPressureInfo(); |
|
|
|
// Get a reclamation queue
|
|
|
|
// Get a reclamation queue
|
|
|
@ -337,29 +319,8 @@ class BasicMemoryQuota final |
|
|
|
friend class ReclamationSweep; |
|
|
|
friend class ReclamationSweep; |
|
|
|
class WaitForSweepPromise; |
|
|
|
class WaitForSweepPromise; |
|
|
|
|
|
|
|
|
|
|
|
class AllocatorBucket { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
struct Shard { |
|
|
|
|
|
|
|
absl::flat_hash_set<GrpcMemoryAllocatorImpl*> allocators |
|
|
|
|
|
|
|
ABSL_GUARDED_BY(shard_mu); |
|
|
|
|
|
|
|
absl::Mutex shard_mu; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Shard& SelectShard(void* key) { |
|
|
|
|
|
|
|
const size_t hash = HashPointer(key, shards.size()); |
|
|
|
|
|
|
|
return shards[hash % shards.size()]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::array<Shard, 16> shards; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr intptr_t kInitialSize = std::numeric_limits<intptr_t>::max(); |
|
|
|
static constexpr intptr_t kInitialSize = std::numeric_limits<intptr_t>::max(); |
|
|
|
|
|
|
|
|
|
|
|
// Move allocator from big bucket to small bucket.
|
|
|
|
|
|
|
|
void MaybeMoveAllocatorBigToSmall(GrpcMemoryAllocatorImpl* allocator); |
|
|
|
|
|
|
|
// Move allocator from small bucket to big bucket.
|
|
|
|
|
|
|
|
void MaybeMoveAllocatorSmallToBig(GrpcMemoryAllocatorImpl* allocator); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The amount of memory that's free in this quota.
|
|
|
|
// The amount of memory that's free in this quota.
|
|
|
|
// We use intptr_t as a reasonable proxy for ssize_t that's portable.
|
|
|
|
// We use intptr_t as a reasonable proxy for ssize_t that's portable.
|
|
|
|
// We allow arbitrary overcommit and so this must allow negative values.
|
|
|
|
// We allow arbitrary overcommit and so this must allow negative values.
|
|
|
@ -369,10 +330,6 @@ class BasicMemoryQuota final |
|
|
|
|
|
|
|
|
|
|
|
// Reclaimer queues.
|
|
|
|
// Reclaimer queues.
|
|
|
|
ReclaimerQueue reclaimers_[kNumReclamationPasses]; |
|
|
|
ReclaimerQueue reclaimers_[kNumReclamationPasses]; |
|
|
|
// List of all allocators sorted into 2 buckets, small (<100 KB free bytes)
|
|
|
|
|
|
|
|
// and large (>500 KB free bytes).
|
|
|
|
|
|
|
|
AllocatorBucket small_allocators_; |
|
|
|
|
|
|
|
AllocatorBucket big_allocators_; |
|
|
|
|
|
|
|
// The reclaimer activity consumes reclaimers whenever we are in overcommit to
|
|
|
|
// The reclaimer activity consumes reclaimers whenever we are in overcommit to
|
|
|
|
// try and get back under memory limits.
|
|
|
|
// try and get back under memory limits.
|
|
|
|
ActivityPtr reclaimer_activity_; |
|
|
|
ActivityPtr reclaimer_activity_; |
|
|
@ -414,25 +371,10 @@ class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl { |
|
|
|
// Try to immediately return some free'ed memory back to the total quota.
|
|
|
|
// Try to immediately return some free'ed memory back to the total quota.
|
|
|
|
MaybeDonateBack(); |
|
|
|
MaybeDonateBack(); |
|
|
|
} |
|
|
|
} |
|
|
|
size_t new_free = free_bytes_.load(std::memory_order_relaxed); |
|
|
|
|
|
|
|
memory_quota_->MaybeMoveAllocator(this, prev_free, new_free); |
|
|
|
|
|
|
|
if (prev_free != 0) return; |
|
|
|
if (prev_free != 0) return; |
|
|
|
MaybeRegisterReclaimer(); |
|
|
|
MaybeRegisterReclaimer(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Return all free bytes to quota.
|
|
|
|
|
|
|
|
void ReturnFree() { |
|
|
|
|
|
|
|
size_t ret = free_bytes_.exchange(0, std::memory_order_acq_rel); |
|
|
|
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "Allocator %p returning %zu bytes to quota", this, ret); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (ret == 0) return; |
|
|
|
|
|
|
|
memory_quota_->MaybeMoveAllocator(this, /*old_free_bytes=*/ret, |
|
|
|
|
|
|
|
/*new_free_bytes=*/0); |
|
|
|
|
|
|
|
taken_bytes_.fetch_sub(ret, std::memory_order_relaxed); |
|
|
|
|
|
|
|
memory_quota_->Return(ret); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Post a reclamation function.
|
|
|
|
// Post a reclamation function.
|
|
|
|
template <typename F> |
|
|
|
template <typename F> |
|
|
|
void PostReclaimer(ReclamationPass pass, F fn) { |
|
|
|
void PostReclaimer(ReclamationPass pass, F fn) { |
|
|
@ -452,13 +394,8 @@ class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl { |
|
|
|
// Name of this allocator
|
|
|
|
// Name of this allocator
|
|
|
|
absl::string_view name() const { return name_; } |
|
|
|
absl::string_view name() const { return name_; } |
|
|
|
|
|
|
|
|
|
|
|
size_t GetFreeBytes() const { |
|
|
|
|
|
|
|
return free_bytes_.load(std::memory_order_relaxed); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
static constexpr size_t kMaxQuotaBufferSize = 1024 * 1024; |
|
|
|
static constexpr size_t kMaxQuotaBufferSize = 1024 * 1024; |
|
|
|
|
|
|
|
|
|
|
|
// Primitive reservation function.
|
|
|
|
// Primitive reservation function.
|
|
|
|
absl::optional<size_t> TryReserve(MemoryRequest request) GRPC_MUST_USE_RESULT; |
|
|
|
absl::optional<size_t> TryReserve(MemoryRequest request) GRPC_MUST_USE_RESULT; |
|
|
|
// This function may be invoked during a memory release operation.
|
|
|
|
// This function may be invoked during a memory release operation.
|
|
|
@ -496,7 +433,6 @@ class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl { |
|
|
|
OrphanablePtr<ReclaimerQueue::Handle> |
|
|
|
OrphanablePtr<ReclaimerQueue::Handle> |
|
|
|
reclamation_handles_[kNumReclamationPasses] ABSL_GUARDED_BY( |
|
|
|
reclamation_handles_[kNumReclamationPasses] ABSL_GUARDED_BY( |
|
|
|
reclaimer_mu_); |
|
|
|
reclaimer_mu_); |
|
|
|
|
|
|
|
|
|
|
|
// Name of this allocator.
|
|
|
|
// Name of this allocator.
|
|
|
|
std::string name_; |
|
|
|
std::string name_; |
|
|
|
}; |
|
|
|
}; |
|
|
|