|
31 | 31 | #include <variant> |
32 | 32 | #include <vector> |
33 | 33 |
|
| 34 | +#if defined(__linux__) |
| 35 | +#include <malloc.h> |
| 36 | +#endif |
| 37 | + |
| 38 | +#if defined(KREPE_ENABLE_CUDA_DUMP) |
| 39 | +#include <cuda.h> |
| 40 | +#include <cuda_runtime_api.h> |
| 41 | +#endif |
| 42 | + |
| 43 | +#if defined(KREPE_ENABLE_HIP_DUMP) |
| 44 | +#include <hip/hip_runtime_api.h> |
| 45 | +#endif |
| 46 | + |
34 | 47 | #define KOKKOS_HOOKS_EXPORT __attribute__((visibility("default"))) |
35 | 48 |
|
36 | 49 | #if !defined(KREPE_KOKKOS_ALLOCATION_HEADER_SIZE) |
@@ -89,6 +102,20 @@ bool is_internal_label(std::string_view label) { |
89 | 102 | label.starts_with("KOKKOS_") || label.starts_with("kokkos."); |
90 | 103 | } |
91 | 104 |
|
| 105 | +#if defined(KREPE_ENABLE_CUDA_DUMP) |
| 106 | +bool is_cuda_pointer_attribute_space(const std::string& space) { |
| 107 | + return space == "Cuda" || space == "CudaUVM" || space == "CudaHostPinned"; |
| 108 | +} |
| 109 | +#endif |
| 110 | + |
| 111 | +#if defined(KREPE_ENABLE_HIP_DUMP) |
| 112 | +bool is_hip_pointer_attribute_space(const std::string& space) { |
| 113 | + return space == "HIP" || space == "HIPManaged" || space == "HIPHostPinned"; |
| 114 | +} |
| 115 | +#endif |
| 116 | + |
| 117 | +bool is_host_space(const std::string& space) { return space == "Host"; } |
| 118 | + |
92 | 119 | std::string bounded_string(const char* value, std::size_t max_size) { |
93 | 120 | if (value == nullptr) { |
94 | 121 | return "<null>"; |
@@ -166,6 +193,93 @@ const void* allocation_data_pointer(const void* ptr) { |
166 | 193 | KREPE_KOKKOS_ALLOCATION_HEADER_SIZE; |
167 | 194 | } |
168 | 195 |
|
| 196 | +std::size_t host_allocation_size(const void* ptr) { |
| 197 | +#if defined(__linux__) |
| 198 | + // The allocator may reserve more memory than Kokkos requested, so |
| 199 | + // malloc_usable_size(ptr) can return a larger size than the requested one. |
| 200 | + return malloc_usable_size(const_cast<void*>(ptr)); |
| 201 | +#else |
| 202 | + (void)ptr; |
| 203 | + return 0; |
| 204 | +#endif |
| 205 | +} |
| 206 | + |
| 207 | +std::optional<std::uint64_t> validated_data_size( |
| 208 | + const void* allocation_base, const std::size_t allocation_size, |
| 209 | + const void* data_ptr, const std::uint64_t reported_size) { |
| 210 | + const auto base = reinterpret_cast<std::uintptr_t>(allocation_base); |
| 211 | + const auto data = reinterpret_cast<std::uintptr_t>(data_ptr); |
| 212 | + if (data < base) { |
| 213 | + return std::nullopt; |
| 214 | + } |
| 215 | + |
| 216 | + const auto offset = data - base; |
| 217 | + if (offset > allocation_size) { |
| 218 | + return std::nullopt; |
| 219 | + } |
| 220 | + |
| 221 | + if (offset == allocation_size) { |
| 222 | + return 0; |
| 223 | + } |
| 224 | + |
| 225 | + const auto available = static_cast<std::uint64_t>(allocation_size - offset); |
| 226 | + return available >= reported_size ? reported_size : 0; |
| 227 | +} |
| 228 | + |
| 229 | +std::optional<std::uint64_t> allocation_data_size( |
| 230 | + const std::string& space, const void* ptr, const void* data_ptr, |
| 231 | + const std::uint64_t reported_size) { |
| 232 | + // Kokkos <= 5.2.0 reports the SharedAllocationHeader size instead of zero |
| 233 | + // for empty Views (kokkos/kokkos#9337). Disambiguate that legacy value using |
| 234 | + // the physical allocation bounds below. |
| 235 | + if (reported_size != KREPE_KOKKOS_ALLOCATION_HEADER_SIZE) { |
| 236 | + return reported_size; |
| 237 | + } |
| 238 | + |
| 239 | +#if defined(KREPE_ENABLE_CUDA_DUMP) |
| 240 | + if (is_cuda_pointer_attribute_space(space)) { |
| 241 | + CUdeviceptr allocation_base = 0; |
| 242 | + std::size_t allocation_size = 0; |
| 243 | + const CUdeviceptr queried_pointer = reinterpret_cast<CUdeviceptr>(ptr); |
| 244 | + const CUresult base_error = cuPointerGetAttribute( |
| 245 | + &allocation_base, CU_POINTER_ATTRIBUTE_RANGE_START_ADDR, |
| 246 | + queried_pointer); |
| 247 | + const CUresult size_error = cuPointerGetAttribute( |
| 248 | + &allocation_size, CU_POINTER_ATTRIBUTE_RANGE_SIZE, queried_pointer); |
| 249 | + if (base_error == CUDA_SUCCESS && size_error == CUDA_SUCCESS) { |
| 250 | + return validated_data_size(reinterpret_cast<const void*>(allocation_base), |
| 251 | + allocation_size, data_ptr, reported_size); |
| 252 | + } |
| 253 | + } |
| 254 | +#endif |
| 255 | + |
| 256 | +#if defined(KREPE_ENABLE_HIP_DUMP) |
| 257 | + if (is_hip_pointer_attribute_space(space)) { |
| 258 | + hipDeviceptr_t allocation_base = nullptr; |
| 259 | + std::size_t allocation_size = 0; |
| 260 | + const hipDeviceptr_t queried_pointer = const_cast<void*>(ptr); |
| 261 | + const hipError_t base_error = hipPointerGetAttribute( |
| 262 | + &allocation_base, HIP_POINTER_ATTRIBUTE_RANGE_START_ADDR, |
| 263 | + queried_pointer); |
| 264 | + const hipError_t size_error = hipPointerGetAttribute( |
| 265 | + &allocation_size, HIP_POINTER_ATTRIBUTE_RANGE_SIZE, queried_pointer); |
| 266 | + if (base_error == hipSuccess && size_error == hipSuccess) { |
| 267 | + return validated_data_size(allocation_base, allocation_size, data_ptr, |
| 268 | + reported_size); |
| 269 | + } |
| 270 | + } |
| 271 | +#endif |
| 272 | + |
| 273 | + if (is_host_space(space)) { |
| 274 | + const std::size_t allocation_size = host_allocation_size(ptr); |
| 275 | + if (allocation_size != 0) { |
| 276 | + return validated_data_size(ptr, allocation_size, data_ptr, reported_size); |
| 277 | + } |
| 278 | + } |
| 279 | + |
| 280 | + return std::nullopt; |
| 281 | +} |
| 282 | + |
169 | 283 | void begin_kernel(const char* label, const std::uint32_t device_id, |
170 | 284 | std::uint64_t* kernel_id) { |
171 | 285 | const std::uint64_t id = next_kernel_id.fetch_add(1); |
@@ -353,11 +467,16 @@ KOKKOS_HOOKS_EXPORT void kokkosp_allocate_data( |
353 | 467 | const void* ptr, const std::uint64_t size) { |
354 | 468 | const std::string allocation_label = label_or_unknown(label); |
355 | 469 | const std::string allocation_space = space_name(space); |
356 | | - const void* p_data = ptr != nullptr ? allocation_data_pointer(ptr) : nullptr; |
357 | 470 |
|
358 | 471 | if (should_track_allocation(label, ptr)) { |
| 472 | + const void* p_data = allocation_data_pointer(ptr); |
| 473 | + const std::optional<std::uint64_t> data_size = |
| 474 | + allocation_data_size(allocation_space, ptr, p_data, size); |
| 475 | + const std::uint64_t tracked_size = data_size.value_or(0); |
| 476 | + |
359 | 477 | allocation_tracker.record_allocation(allocation_label, allocation_space, |
360 | | - ptr, p_data, size); |
| 478 | + ptr, p_data, tracked_size, size, |
| 479 | + data_size.has_value()); |
361 | 480 | } |
362 | 481 | } |
363 | 482 |
|
|
0 commit comments