Skip to content

Commit e64e4b1

Browse files
daxmawaltretre91
andauthored
Add dump support for empty views (#34)
* Add dump support for empty views * Fix reported error by asan and ubsan Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * Add replay test for view without explicit size Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * make empty view test usable with other backends Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * fix: make HIP allocation range query compile Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * add TODO comments Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * update doc and add comment Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * remove todo Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * Fix GPU allocation range queries * Limit allocation range queries Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * remove kernel_replayer namespace Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * pre-commit Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * Handle zero-byte allocations before backend checks Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * Add comments Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * Remove test Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * Update src/krepe/capture/kokkos_hooks.cpp Co-authored-by: Trévis Morvany <63788850+tretre91@users.noreply.github.com> * remove ci test Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> * ci: retrigger checks Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> --------- Signed-off-by: daxmawal <jeanfrancoismanutea@gmail.com> Co-authored-by: Trévis Morvany <63788850+tretre91@users.noreply.github.com>
1 parent a46ca81 commit e64e4b1

19 files changed

Lines changed: 519 additions & 17 deletions

docs/hdf5-dumps.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,22 @@ kernel_label # Kokkos label of the matched kernel
2323
kernel_id # tool-local id assigned to this kernel invocation
2424
kernel_invocation # allow dumping a specific kernel invocation
2525
active_allocations # tracked user allocations alive at dump time
26-
active_bytes # total size, in bytes, of those active allocations
26+
active_bytes # total bounded user-data bytes for those active allocations
2727
```
2828

2929
The `/views` group contains one subgroup per active allocation. Each allocation
3030
group stores:
3131

3232
```text
33-
label # Kokkos allocation label
34-
space # Kokkos memory space name reported by the profiling hook
35-
ptr # allocation pointer value, stored as text
36-
p_data # user data pointer after the Kokkos allocation header
37-
size # allocation size in bytes
38-
bytes_dumped
33+
label # Kokkos allocation label
34+
space # Kokkos memory space name reported by the profiling hook
35+
ptr # allocation pointer value, stored as text
36+
p_data # user data pointer after the Kokkos allocation header
37+
size # bounded user-data bytes, 0 for empty or unbounded allocations
38+
reported_size # size reported by the Kokkos profiling allocation hook
39+
bytes_dumped # 1 when the bytes dataset was written, 0 when it was skipped
40+
skip_reason # present only when bytes_dumped is 0
41+
bytes # byte dataset, present when bytes_dumped is 1
3942
```
4043

4144
The `/metadata` group contains user specified metadata

src/krepe/capture/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ target_compile_definitions(
3535
if(Kokkos_ENABLE_CUDA)
3636
find_package(CUDAToolkit REQUIRED)
3737
target_compile_definitions(krepe_kokkos_hooks PRIVATE KREPE_ENABLE_CUDA_DUMP)
38-
target_link_libraries(krepe_kokkos_hooks PRIVATE CUDA::cudart)
38+
target_link_libraries(krepe_kokkos_hooks PRIVATE CUDA::cudart CUDA::cuda_driver)
3939
endif()
4040
if(Kokkos_ENABLE_HIP)
4141
target_compile_definitions(krepe_kokkos_hooks PRIVATE KREPE_ENABLE_HIP_DUMP)

src/krepe/capture/allocation_tracker.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ namespace krepe {
66

77
void AllocationTracker::record_allocation(std::string label, std::string space,
88
const void* ptr, const void* p_data,
9-
const std::uint64_t size) {
9+
const std::uint64_t size,
10+
const std::uint64_t reported_size,
11+
const bool data_size_known) {
1012
if (ptr == nullptr) {
1113
return;
1214
}
1315

14-
AllocationRecord record{std::move(label), space, p_data, size};
16+
AllocationRecord record{std::move(label), space, p_data, size,
17+
reported_size, data_size_known};
1518
std::lock_guard<std::mutex> lock(mutex_);
1619
active_allocations_[space].insert_or_assign(ptr, std::move(record));
1720
}

src/krepe/capture/allocation_tracker.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ struct AllocationRecord {
1414
std::string space;
1515
const void* p_data;
1616
std::uint64_t size;
17+
std::uint64_t reported_size;
18+
bool data_size_known;
1719
};
1820

1921
struct ActiveAllocation {
@@ -29,7 +31,8 @@ struct AllocationSnapshot {
2931
class AllocationTracker {
3032
public:
3133
void record_allocation(std::string label, std::string space, const void* ptr,
32-
const void* p_data, std::uint64_t size);
34+
const void* p_data, std::uint64_t size,
35+
std::uint64_t reported_size, bool data_size_known);
3336
void record_deallocation(std::string space, const void* ptr);
3437

3538
AllocationSnapshot snapshot() const;

src/krepe/capture/kokkos_hooks.cpp

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@
3131
#include <variant>
3232
#include <vector>
3333

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+
3447
#define KOKKOS_HOOKS_EXPORT __attribute__((visibility("default")))
3548

3649
#if !defined(KREPE_KOKKOS_ALLOCATION_HEADER_SIZE)
@@ -89,6 +102,20 @@ bool is_internal_label(std::string_view label) {
89102
label.starts_with("KOKKOS_") || label.starts_with("kokkos.");
90103
}
91104

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+
92119
std::string bounded_string(const char* value, std::size_t max_size) {
93120
if (value == nullptr) {
94121
return "<null>";
@@ -166,6 +193,93 @@ const void* allocation_data_pointer(const void* ptr) {
166193
KREPE_KOKKOS_ALLOCATION_HEADER_SIZE;
167194
}
168195

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+
169283
void begin_kernel(const char* label, const std::uint32_t device_id,
170284
std::uint64_t* kernel_id) {
171285
const std::uint64_t id = next_kernel_id.fetch_add(1);
@@ -353,11 +467,16 @@ KOKKOS_HOOKS_EXPORT void kokkosp_allocate_data(
353467
const void* ptr, const std::uint64_t size) {
354468
const std::string allocation_label = label_or_unknown(label);
355469
const std::string allocation_space = space_name(space);
356-
const void* p_data = ptr != nullptr ? allocation_data_pointer(ptr) : nullptr;
357470

358471
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+
359477
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());
361480
}
362481
}
363482

src/krepe/capture/memory_copy.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ std::string allocate_staging_buffer(const ActiveAllocation& allocation,
4444

4545
std::string copy_allocation_bytes(const ActiveAllocation& allocation,
4646
std::vector<unsigned char>& bytes) {
47+
if (!allocation.record.data_size_known) {
48+
return "allocation data size could not be bounded safely";
49+
}
50+
if (allocation.record.size == 0) {
51+
bytes.clear();
52+
return {};
53+
}
54+
4755
const std::string& space = allocation.record.space;
4856
const bool host_accessible = is_host_accessible_space(space);
4957
const bool cuda_device = is_cuda_device_space(space);

src/krepe/capture/view_dump.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ void write_allocation_group(hid_t views_group,
204204
write_string_attribute(group.get(), "p_data",
205205
pointer_to_string(allocation.record.p_data));
206206
write_uint64_attribute(group.get(), "size", allocation.record.size);
207+
write_uint64_attribute(group.get(), "reported_size",
208+
allocation.record.reported_size);
207209

208210
std::vector<unsigned char> bytes;
209211
const std::string skip_reason = copy_allocation_bytes(allocation, bytes);

src/krepe/replay/kernel_replayer.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ herr_t get_hdf5_dataset_alloc_info(hid_t group, const char* name,
299299

300300
std::size_t buffer_size =
301301
std::reduce(dims.begin(), dims.end(), 1, std::multiplies<>{});
302+
if (buffer_size == 0) {
303+
return 0;
304+
}
302305

303306
auto allocations = reinterpret_cast<std::set<std::pair<char*, std::size_t>>*>(
304307
allocation_set);
@@ -340,6 +343,11 @@ herr_t allocate_hdf5_dataset(hid_t group, const char* name, const H5L_info_t*,
340343

341344
std::size_t buffer_size =
342345
std::reduce(dims.begin(), dims.end(), 1, std::multiplies<>{});
346+
if (buffer_size == 0) {
347+
(*reinterpret_cast<hdf5_iterate_fun_t*>(allocate_fun))(label, space,
348+
nullptr, nullptr, 0);
349+
return 0;
350+
}
343351

344352
MemorySpaceType memory_space = memory_space_type_from_string(space);
345353
auto free_buffer = [memory_space](char* ptr) {
@@ -667,6 +675,17 @@ ScopeGuard::ScopeGuard(int& argc, char* argv[]) {
667675
char* data, std::size_t size) {
668676
impl::MemorySpaceType space =
669677
impl::memory_space_type_from_string(memory_space);
678+
if (size == 0) {
679+
if (space == impl::MemorySpaceType::HOST) {
680+
host_allocations[label] = nullptr;
681+
} else {
682+
#if defined(KERNEL_REPLAYER_HAS_DEVICE_SPACE)
683+
device_allocations[label] = nullptr;
684+
#endif
685+
}
686+
return;
687+
}
688+
670689
impl::copy_data(space, address, data, size);
671690
if (space == impl::MemorySpaceType::HOST) {
672691
host_allocations[label] = address;
@@ -750,17 +769,21 @@ void ScopeGuard::allocate(impl::MemorySpaceType memory_space, char* address,
750769
void ScopeGuard::allocate_output(std::string label,
751770
std::string_view memory_space, char* data,
752771
std::size_t size) {
772+
if (size == 0) {
773+
return;
774+
}
775+
753776
if (impl::memory_space_type_from_string(memory_space) ==
754777
impl::MemorySpaceType::HOST) {
755-
host_output_allocations.insert(
756-
{label, impl::regular_host_allocate(size, data)});
778+
host_output_allocations.insert_or_assign(
779+
label, impl::regular_host_allocate(size, data));
757780
} else {
758781
#if !defined(KERNEL_REPLAYER_HAS_DEVICE_SPACE)
759782
throw std::runtime_error(
760783
"Trying to access device allocations but no device space is enabled");
761784
#else
762-
device_output_allocations.insert(
763-
{label, impl::regular_device_allocate(size, data)});
785+
device_output_allocations.insert_or_assign(
786+
label, impl::regular_device_allocate(size, data));
764787
#endif
765788
}
766789
}

tests/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,8 @@ add_subdirectory(mdrange_iteration_pattern)
5252
add_subdirectory(team_policy)
5353
add_subdirectory(non_default_execution_space)
5454
add_subdirectory(index_type)
55+
add_subdirectory(empty_view)
56+
57+
if(Kokkos_ENABLE_CUDA OR Kokkos_ENABLE_HIP)
58+
add_subdirectory(gpu_memory_spaces)
59+
endif()

tests/empty_view/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
add_executable(empty_view main.cpp)
2+
target_link_libraries(empty_view PRIVATE krepe_warnings krepe_sanitizers Kokkos::kokkos kernel_extractor)
3+
4+
add_executable(empty_view_replay replay_main.cpp)
5+
target_link_libraries(
6+
empty_view_replay PRIVATE krepe_warnings krepe_sanitizers Kokkos::kokkos kernel_replayer_sanitized
7+
)
8+
9+
add_replay_test(empty_view FALSE)
10+
11+
add_executable(empty_view_without_extent without_extent_main.cpp)
12+
target_link_libraries(empty_view_without_extent PRIVATE krepe_warnings krepe_sanitizers Kokkos::kokkos kernel_extractor)
13+
14+
add_executable(empty_view_without_extent_replay without_extent_replay_main.cpp)
15+
target_link_libraries(
16+
empty_view_without_extent_replay PRIVATE krepe_warnings krepe_sanitizers Kokkos::kokkos kernel_replayer_sanitized
17+
)
18+
19+
add_replay_test(empty_view_without_extent FALSE)

0 commit comments

Comments
 (0)