tracking_resource_adaptor.hpp
前往此文件的文档。
1 /*
2  * Copyright (c) 2020-2025, NVIDIA CORPORATION.
3  *
4  * 根据 Apache 许可证 2.0 版(以下简称“许可证”)获得许可;
5  * 除非符合许可证的规定,否则您不得使用此文件。
6  * 您可以在以下网址获取许可证的副本:
7  *
8  * https://apache.ac.cn/licenses/LICENSE-2.0
9  *
10  * 除非适用法律要求或书面同意,根据许可证分发的软件
11  * 按“现状”分发,不附带任何明示或暗示的担保或条件。
12  * 有关管理权限和
13  * 许可证下的限制,请参阅许可证。
14  */
15 
16 #pragma once
17 
18 #include <rmm/detail/error.hpp>
19 #include <rmm/detail/export.hpp>
20 #include <rmm/detail/stack_trace.hpp>
21 #include <rmm/logger.hpp>
24 #include <rmm/resource_ref.hpp>
25 
26 #include <atomic>
27 #include <cstddef>
28 #include <map>
29 #include <mutex>
30 #include <shared_mutex>
31 #include <sstream>
32 
33 namespace RMM_NAMESPACE {
34 namespace mr {
55 template <typename Upstream>
57  public
58  using read_lock_t =
59  std::shared_lock<std::shared_mutex>;
60  using write_lock_t =
61  std::unique_lock<std::shared_mutex>;
68  struct allocation_info {
69  std::unique_ptr<rmm::detail::stack_trace> strace;
70  std::size_t allocation_size;
71 
72  allocation_info() = delete;
79  allocation_info(std::size_t size, bool capture_stack)
80  : strace{[&]() {
81  return capture_stack ? std::make_unique<rmm::detail::stack_trace>() : nullptr;
82  }()},
83  allocation_size{size} {};
84  };
85 
93  tracking_resource_adaptor(device_async_resource_ref upstream, bool capture_stacks = false)
94  : capture_stacks_{capture_stacks}, allocated_bytes_{0}, upstream_{upstream}
95  {
96  }
97 
107  tracking_resource_adaptor(Upstream* upstream, bool capture_stacks = false)
108  : capture_stacks_{capture_stacks},
109  allocated_bytes_{0},
110  upstream_{to_device_async_resource_ref_checked(upstream)}
111  {
112  }
113 
114  tracking_resource_adaptor() = delete;
115  ~tracking_resource_adaptor() override = default;
118  default;
119  tracking_resource_adaptor& operator=(tracking_resource_adaptor const&) = delete;
121  default;
122 
126  [[nodiscard]] rmm::device_async_resource_ref get_upstream_resource() const noexcept
127  {
128  return upstream_;
129  }
130 
138  std::map<void*, allocation_info> const& get_outstanding_allocations() const noexcept
139  {
140  return allocations_;
141  }
142 
152  std::size_t get_allocated_bytes() const noexcept { return allocated_bytes_; }
153 
165  {
166  read_lock_t lock(mtx_);
167 
168  std::ostringstream oss;
169 
170  if (!allocations_.empty()) {
171  for (auto const& alloc : allocations_) {
172  oss << alloc.first << ": " << alloc.second.allocation_size << " B";
173  if (alloc.second.strace != nullptr) {
174  oss << " : callstack:" << std::endl << *alloc.second.strace;
175  }
176  oss << std::endl;
177  }
178  }
179 
180  return oss.str();
181  }
182 
188  {
189 #if RMM_LOG_ACTIVE_LEVEL <= RMM_LOG_LEVEL_DEBUG
190  RMM_LOG_DEBUG("Outstanding Allocations: %s", get_outstanding_allocations_str());
191 #endif // RMM_LOG_ACTIVE_LEVEL <= RMM_LOG_LEVEL_DEBUG
192  }
193 
194  private
208  void* do_allocate(std::size_t bytes, cuda_stream_view stream) override
209  {
210  void* ptr = get_upstream_resource().allocate_async(bytes, stream);
211  // 追踪它。
212  {
213  write_lock_t lock(mtx_);
214  allocations_.emplace(ptr, allocation_info{bytes, capture_stacks_});
215  }
216  allocated_bytes_ += bytes;
217 
218  return ptr;
219  }
220 
228  void do_deallocate(void* ptr, std::size_t bytes, cuda_stream_view stream) override
229  {
230  get_upstream_resource().deallocate_async(ptr, bytes, stream);
231  {
232  write_lock_t lock(mtx_);
233 
234  const auto found = allocations_.find(ptr);
235 
236  // 确保找到了分配,并且字节数匹配
237  if (found == allocations_.end()) {
238  // 不要抛出异常,而是记录错误。在析构函数(或任何 noexcept)中抛出异常将调用
239  // std::terminate
240  RMM_LOG_ERROR(
241  "Deallocating a pointer that was not tracked. Ptr: %p [%zuB], Current Num. Allocations: "
242  "%zu",
243  ptr,
244  bytes,
245  this->allocations_.size());
246  } else {
247  allocations_.erase(found);
248 
249  auto allocated_bytes = found->second.allocation_size;
250 
251  if (allocated_bytes != bytes) {
252  // 不要抛出异常,而是记录错误。在析构函数(或任何 noexcept)中抛出异常将调用
253  // std::terminate
254  RMM_LOG_ERROR(
255  "Alloc bytes (%zu) and Dealloc bytes (%zu) do not match", allocated_bytes, bytes);
256 
257  bytes = allocated_bytes;
258  }
259  }
260  }
261  allocated_bytes_ -= bytes;
262  }
263 
271  bool do_is_equal(device_memory_resource const& other) const noexcept override
272  {
273  if (this == &other) { return true; }
274  auto cast = dynamic_cast<tracking_resource_adaptor<Upstream> const*>(&other);
275  if (cast == nullptr) { return false; }
276  return get_upstream_resource() == cast->get_upstream_resource();
277  }
278 
279  bool capture_stacks_; // 是否捕获调用栈
280  std::map<void*, allocation_info> allocations_; // 活跃分配的映射
281  std::atomic<std::size_t> allocated_bytes_; // 当前分配的字节数
282  std::shared_mutex mutable mtx_; // 用于线程安全访问 allocations_ 的互斥锁
283  device_async_resource_ref upstream_; // 用于满足
284  // 分配请求的上游资源
285 };
286  // 组结束
288 } // 命名空间 mr
289 } // 命名空间 RMM_NAMESPACE
CUDA 流的强类型非拥有包装器,带默认构造函数。
定义: cuda_stream_view.hpp:39
所有 librmm 设备内存分配的基类。
定义: device_memory_resource.hpp:92
使用 Upstream 分配内存并跟踪分配的资源。
定义: tracking_resource_adaptor.hpp:56
tracking_resource_adaptor(Upstream *upstream, bool capture_stacks=false)
构造一个新的跟踪资源适配器,使用 upstream 来满足分配请求。
定义: tracking_resource_adaptor.hpp:107
tracking_resource_adaptor(device_async_resource_ref upstream, bool capture_stacks=false)
构造一个新的跟踪资源适配器,使用 upstream 来满足分配请求。
定义: tracking_resource_adaptor.hpp:93
std::size_t get_allocated_bytes() const noexcept
查询已分配的字节数。请注意,这不能用于了解有多大...
定义: tracking_resource_adaptor.hpp:152
std::unique_lock< std::shared_mutex > write_lock_t
用于同步写访问的锁类型。
定义: tracking_resource_adaptor.hpp:61
tracking_resource_adaptor(tracking_resource_adaptor &&) noexcept=default
默认移动构造函数。
std::string get_outstanding_allocations_str() const
获取一个字符串,其中包含未完成的分配指针、它们的大小以及可选的调用栈...
定义: tracking_resource_adaptor.hpp:164
std::map< void *, allocation_info > const & get_outstanding_allocations() const noexcept
获取未完成的分配映射。
定义: tracking_resource_adaptor.hpp:138
void log_outstanding_allocations() const
通过 RMM_LOG_DEBUG 记录任何未完成的分配。
定义: tracking_resource_adaptor.hpp:187
std::shared_lock< std::shared_mutex > read_lock_t
用于同步读访问的锁类型。
定义: tracking_resource_adaptor.hpp:59
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
管理每设备的 device_memory_resource。
关于分配存储的信息。包括大小以及如果跟踪资源启用了捕获调用栈,则还包括调用栈。
定义: tracking_resource_adaptor.hpp:68
std::unique_ptr< rmm::detail::stack_trace > strace
分配的调用栈。
定义: tracking_resource_adaptor.hpp:69
std::size_t allocation_size
分配的大小。
定义: tracking_resource_adaptor.hpp:70
allocation_info(std::size_t size, bool capture_stack)
构造一个新的 allocation info 对象。
定义: tracking_resource_adaptor.hpp:79