19 #include <rmm/detail/error.hpp>
20 #include <rmm/detail/export.hpp>
21 #include <rmm/detail/format.hpp>
22 #include <rmm/detail/logging_assert.hpp>
23 #include <rmm/logger.hpp>
24 #include <rmm/mr/device/detail/arena.hpp>
28 #include <cuda_runtime_api.h>
32 #include <shared_mutex>
35 namespace RMM_NAMESPACE {
82 template <
typename Upstream>
95 std::optional<std::size_t> arena_size = std::nullopt,
96 bool dump_log_on_failure =
false)
97 : global_arena_{upstream_mr, arena_size}, dump_log_on_failure_{dump_log_on_failure}
99 if (dump_log_on_failure_) {
101 std::make_shared<rapids_logger::logger>(
"arena_memory_dump",
"rmm_arena_memory_dump.log");
103 logger_->set_level(rapids_logger::level_enum::info);
118 std::optional<std::size_t> arena_size = std::nullopt,
119 bool dump_log_on_failure =
false)
134 using global_arena = rmm::mr::detail::arena::global_arena;
135 using arena = rmm::mr::detail::arena::arena;
150 if (bytes <= 0) {
return nullptr; }
151 #ifdef RMM_ARENA_USE_SIZE_CLASSES
152 bytes = rmm::mr::detail::arena::align_to_size_class(bytes);
156 auto& arena = get_arena(stream);
159 std::shared_lock lock(mtx_);
160 void* pointer = arena.allocate(bytes);
161 if (pointer !=
nullptr) {
return pointer; }
165 std::unique_lock lock(mtx_);
167 void* pointer = arena.allocate(bytes);
168 if (pointer ==
nullptr) {
169 if (dump_log_on_failure_) { dump_memory_log(bytes); }
170 auto const msg = std::string(
"超出最大池大小(分配失败") +
171 rmm::detail::format_bytes(bytes) +
"): 竞技场中没有空间。";
183 RMM_CUDA_TRY(cudaDeviceSynchronize());
184 for (
auto& thread_arena : thread_arenas_) {
185 thread_arena.second->clean();
187 for (
auto& stream_arena : stream_arenas_) {
188 stream_arena.second.clean();
200 void do_deallocate(
void* ptr, std::size_t bytes, cuda_stream_view stream)
override
202 if (ptr ==
nullptr || bytes <= 0) {
return; }
203 #ifdef RMM_ARENA_USE_SIZE_CLASSES
204 bytes = rmm::mr::detail::arena::align_to_size_class(bytes);
208 auto& arena = get_arena(stream);
211 std::shared_lock lock(mtx_);
213 if (arena.deallocate(ptr, bytes, stream)) {
return; }
219 stream.synchronize_no_throw();
221 std::unique_lock lock(mtx_);
222 deallocate_from_other_arena(ptr, bytes, stream);
234 void deallocate_from_other_arena(
void* ptr, std::size_t bytes, cuda_stream_view stream)
236 if (use_per_thread_arena(stream)) {
237 for (
auto const& thread_arena : thread_arenas_) {
238 if (thread_arena.second->deallocate(ptr, bytes)) {
return; }
241 for (
auto& stream_arena : stream_arenas_) {
242 if (stream_arena.second.deallocate(ptr, bytes)) {
return; }
246 if (!global_arena_.deallocate(ptr, bytes)) {
255 if (use_per_thread_arena(stream)) {
256 for (
auto& stream_arena : stream_arenas_) {
257 if (stream_arena.second.deallocate(ptr, bytes)) {
return; }
260 for (
auto const& thread_arena : thread_arenas_) {
261 if (thread_arena.second->deallocate(ptr, bytes)) {
return; }
274 arena& get_arena(cuda_stream_view stream)
276 if (use_per_thread_arena(stream)) {
return get_thread_arena(); }
277 return get_stream_arena(stream);
285 arena& get_thread_arena()
287 auto const thread_id = std::this_thread::get_id();
289 std::shared_lock lock(map_mtx_);
290 auto const iter = thread_arenas_.find(thread_id);
291 if (iter != thread_arenas_.end()) {
return *iter->second; }
294 std::unique_lock lock(map_mtx_);
295 auto thread_arena = std::make_shared<arena>(global_arena_);
296 thread_arenas_.emplace(thread_id, thread_arena);
297 thread_local detail::arena::arena_cleaner cleaner{thread_arena};
298 return *thread_arena;
307 arena& get_stream_arena(cuda_stream_view stream)
309 RMM_LOGGING_ASSERT(!use_per_thread_arena(stream));
311 std::shared_lock lock(map_mtx_);
312 auto const iter = stream_arenas_.find(stream.value());
313 if (iter != stream_arenas_.end()) {
return iter->second; }
316 std::unique_lock lock(map_mtx_);
317 stream_arenas_.emplace(stream.value(), global_arena_);
318 return stream_arenas_.at(stream.value());
327 void dump_memory_log(
size_t bytes)
329 logger_->info(
"**************************************************");
330 logger_->info(
"尝试分配 %s 时内存不足。", rmm::detail::format_bytes(bytes));
331 logger_->info(
"**************************************************");
332 logger_->info(
"全局竞技场:");
333 global_arena_.dump_memory_log(logger_);
343 static bool use_per_thread_arena(cuda_stream_view stream)
345 return stream.is_per_thread_default();
带默认构造函数的 CUDA 流的强类型非拥有包装器。
定义: cuda_stream_view.hpp:39
一种强调避免碎片和可扩展并发支持的子分配器。
定义: arena_memory_resource.hpp:83
arena_memory_resource(Upstream *upstream_mr, std::optional< std::size_t > arena_size=std::nullopt, bool dump_log_on_failure=false)
构造 arena_memory_resource。
定义: arena_memory_resource.hpp:116
arena_memory_resource(device_async_resource_ref upstream_mr, std::optional< std::size_t > arena_size=std::nullopt, bool dump_log_on_failure=false)
构造 arena_memory_resource。
定义: arena_memory_resource.hpp:93
所有 librmm 设备内存分配的基类。
定义: device_memory_resource.hpp:92
RMM 内存不足时抛出的异常。
定义: error.hpp:87
cuda::mr::async_resource_ref< cuda::mr::device_accessible > device_async_resource_ref
具有属性 cuda::mr::device_accessible 的 cuda::mr::async_resource_ref 的别名。
定义: resource_ref.hpp:40
device_async_resource_ref to_device_async_resource_ref_checked(Resource *res)
将内存资源指针转换为 device_async_resource_ref,并检查是否为 nullptr
定义: resource_ref.hpp:78
static constexpr std::size_t CUDA_ALLOCATION_ALIGNMENT
用于 CUDA 内存分配的默认对齐方式。
定义: aligned.hpp:43
constexpr std::size_t align_up(std::size_t value, std::size_t alignment) noexcept
向上对齐到指定 2 的幂的最近倍数。
定义: aligned.hpp:77