/* * Copyright 2008-2013 NVIDIA Corporation * Modifications Copyright© 2019-2025 Advanced Micro Devices, Inc. All rights reserved. * * 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. */ #include #include #include #include "test_param_fixtures.hpp" #include "test_utils.hpp" template struct reference { using type = T&; }; template <> struct reference { using type = void; }; struct unit {}; template struct tracked_pointer : thrust::iterator_facade, T, thrust::host_system_tag, thrust::random_access_traversal_tag, typename reference::type, std::ptrdiff_t> { using raw_pointer = T*; std::size_t id; std::size_t size; std::size_t alignment; std::size_t offset; void* ptr; __host__ __device__ explicit tracked_pointer(T* ptr = nullptr) : id() , size() , alignment() , offset() , ptr(ptr) {} __host__ __device__ ~tracked_pointer() {} template operator tracked_pointer() const { tracked_pointer ret; ret.id = id; ret.size = size; ret.alignment = alignment; ret.offset = offset; ret.ptr = ptr; return ret; } __host__ __device__ std::ptrdiff_t distance_to(const tracked_pointer& other) const { return static_cast(other.ptr) - static_cast(ptr); } __host__ __device__ T* get() const { return static_cast(ptr); } // globally qualified, because MSVC somehow prefers the name from the dependent base // of this class over the `reference` template that's visible in the global namespace of this file... __host__ __device__ typename ::reference::type dereference() const { return *get(); } __host__ __device__ void increment() { advance(1); } __host__ __device__ void decrement() { advance(-1); } __host__ __device__ void advance(std::ptrdiff_t diff) { ptr = get() + diff; offset += diff * sizeof(T); } __host__ __device__ bool equal(const tracked_pointer& other) const { return id == other.id && size == other.size && alignment == other.alignment && offset == other.offset && ptr == other.ptr; } }; class tracked_resource final : public thrust::mr::memory_resource> { public: tracked_resource() : id_to_allocate(0) , id_to_deallocate(0) {} ~tracked_resource() { EXPECT_EQ(id_to_allocate, 0u); EXPECT_EQ(id_to_deallocate, 0u); } virtual tracked_pointer do_allocate(std::size_t n, std::size_t alignment = THRUST_MR_DEFAULT_ALIGNMENT) override { EXPECT_EQ(static_cast(id_to_allocate), true); void* raw = upstream.do_allocate(n, alignment); tracked_pointer ret(raw); ret.id = id_to_allocate; ret.size = n; ret.alignment = alignment; id_to_allocate = 0; return ret; } virtual void do_deallocate(tracked_pointer p, std::size_t n, std::size_t alignment = THRUST_MR_DEFAULT_ALIGNMENT) override { ASSERT_EQ(p.size, n); ASSERT_EQ(p.alignment, alignment); if (id_to_deallocate != 0) { ASSERT_EQ(p.id, id_to_deallocate); id_to_deallocate = 0; } upstream.do_deallocate(p.ptr, n, alignment); } std::size_t id_to_allocate; std::size_t id_to_deallocate; private: thrust::mr::new_delete_resource upstream; }; template