// Copyright 2021 gRPC authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef GRPC_SRC_CORE_LIB_RESOURCE_QUOTA_MEMORY_QUOTA_H #define GRPC_SRC_CORE_LIB_RESOURCE_QUOTA_MEMORY_QUOTA_H #include <grpc/support/port_platform.h> #include <stdint.h> #include <array> #include <atomic> #include <cstddef> #include <limits> #include <memory> #include <string> #include <utility> #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_set.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/types/optional.h" #include <grpc/event_engine/memory_allocator.h> #include <grpc/event_engine/memory_request.h> #include <grpc/support/log.h> #include "src/core/lib/debug/trace.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/ref_counted_ptr.h" #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/gprpp/time.h" #include "src/core/lib/promise/activity.h" #include "src/core/lib/promise/poll.h" #include "src/core/lib/resource_quota/periodic_update.h" #include "src/core/lib/resource_quota/trace.h" namespace grpc_core { class BasicMemoryQuota; class MemoryQuota; class GrpcMemoryAllocatorImpl; MemoryRequest; // Pull in impl under a different name to keep the gRPC/EventEngine separation // clear. EventEngineMemoryAllocatorImpl; MemoryAllocator; Vector; // Reclamation passes. // When memory is tight, we start trying to claim some back from memory // reclaimers. We do this in multiple passes: if there is a less destructive // operation available, we do that, otherwise we do something more destructive. enum class ReclamationPass { … }; static constexpr size_t kNumReclamationPasses = …; // For each reclamation function run we construct a ReclamationSweep. // When this object is finally destroyed (it may be moved several times first), // then that reclamation is complete and we may continue the reclamation loop. class ReclamationSweep { … }; class ReclaimerQueue { … }; namespace memory_quota_detail { // Controller: tries to adjust a control variable up or down to get memory // pressure to some target. We use the control variable to size buffers // throughout the stack. class PressureController { … }; // Utility to track memory pressure. // Tries to be conservative (returns a higher pressure than there may actually // be) but to be eventually accurate. class PressureTracker { … }; } // namespace memory_quota_detail // Minimum number of free bytes in order for allocator to move to big bucket. static constexpr size_t kBigAllocatorThreshold = …; // Maximum number of free bytes in order for allocator to move to small // bucket. static constexpr size_t kSmallAllocatorThreshold = …; class BasicMemoryQuota final : public std::enable_shared_from_this<BasicMemoryQuota> { … }; // MemoryAllocatorImpl grants the owner the ability to allocate memory from an // underlying resource quota. class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl { … }; // MemoryOwner is an enhanced MemoryAllocator that can also reclaim memory, and // be rebound to a different memory quota. // Different modules should not share a MemoryOwner between themselves, instead // each module that requires a MemoryOwner should create one from a resource // quota. This is because the MemoryOwner reclaimers are tied to the // MemoryOwner's lifetime, and are not queryable, so passing a MemoryOwner to a // new owning module means that module cannot reason about which reclaimers are // active, nor what they might do. class MemoryOwner final : public MemoryAllocator { … }; // MemoryQuota tracks the amount of memory available as part of a ResourceQuota. class MemoryQuota final : public grpc_event_engine::experimental::MemoryAllocatorFactory { … }; MemoryQuotaRefPtr; inline MemoryQuotaRefPtr MakeMemoryQuota(std::string name) { … } } // namespace grpc_core #endif // GRPC_SRC_CORE_LIB_RESOURCE_QUOTA_MEMORY_QUOTA_H