[CCCL] 瘦身 + 补全: 移除 cudax/python/libcudacxx-tests 冗余文件, 新增 c2h 测试助手 + cmake 构建系统 + 8 个 CUDA thrust examples
变更摘要:
- 删除: cudax/ (783 files, 7.2M) — 实验性组件,竞赛不需要
- 删除: python/ (226 files, 2.0M) — Python 绑定,竞赛不需要
- 删除: libcudacxx/{test,benchmarks,codegen,cmake,share} (4432 files, 31M)
保留: libcudacxx/include/ (1463 headers, cuda::std 编译依赖)
- 新增: c2h/ (27 files) — CUB Catch2 测试辅助头文件,编译 243 个测试必需
- 新增: cmake/ (29 files) — CCCL 原生 CMake 构建系统
- 新增: thrust/examples/cuda/ (7 files) + cpp_integration/ (1 file)
async_reduce, custom_temporary_allocation, explicit_cuda_stream,
global_device_vector, range_view, unwrap_pointer, wrap_pointer, device
结果: cccl_upstream 从 74M→35M (瘦身 53%), 核心内容 100% 保留:
27/27 tuning headers, 78 benchmarks, 243 tests,
60 thrust examples, 18 CUB examples, 全部编译头文件
This commit is contained in:
@@ -1,222 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of CUDASTF in CUDA C++ Core Libraries,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//! \file
|
||||
//! \brief Test ctx_resource management with different context types
|
||||
|
||||
#include <cuda/experimental/__stf/internal/context.cuh>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
using namespace cuda::experimental::stf;
|
||||
|
||||
namespace
|
||||
{
|
||||
// Counters for tracking resource lifecycle
|
||||
std::atomic<int> stream_resource_construct_count{0};
|
||||
std::atomic<int> stream_resource_release_count{0};
|
||||
std::atomic<int> callback_resource_construct_count{0};
|
||||
std::atomic<int> callback_resource_release_count{0};
|
||||
|
||||
// Test resource that requires a stream for release
|
||||
class test_stream_resource : public ctx_resource
|
||||
{
|
||||
public:
|
||||
test_stream_resource()
|
||||
{
|
||||
stream_resource_construct_count.fetch_add(1);
|
||||
}
|
||||
|
||||
~test_stream_resource() override = default;
|
||||
|
||||
void release(cudaStream_t stream) noexcept override
|
||||
{
|
||||
// Simulate async resource release that needs a stream
|
||||
cudaEvent_t event;
|
||||
cuda_safe_call(cudaEventCreate(&event));
|
||||
cuda_safe_call(cudaEventRecord(event, stream));
|
||||
cuda_safe_call(cudaEventSynchronize(event)); // Wait for completion
|
||||
cuda_safe_call(cudaEventDestroy(event));
|
||||
|
||||
stream_resource_release_count.fetch_add(1);
|
||||
}
|
||||
|
||||
bool can_release_in_callback() const noexcept override
|
||||
{
|
||||
return false; // This resource needs a stream
|
||||
}
|
||||
};
|
||||
|
||||
// Test resource that can be released in a host callback
|
||||
class test_callback_resource : public ctx_resource
|
||||
{
|
||||
public:
|
||||
test_callback_resource()
|
||||
{
|
||||
callback_resource_construct_count.fetch_add(1);
|
||||
}
|
||||
|
||||
~test_callback_resource() override = default;
|
||||
|
||||
void release(cudaStream_t /*stream*/) noexcept override
|
||||
{
|
||||
// Should not be called for callback resources
|
||||
assert(false && "release() should not be called for callback resources");
|
||||
}
|
||||
|
||||
bool can_release_in_callback() const noexcept override
|
||||
{
|
||||
return true; // This resource can be released in a callback
|
||||
}
|
||||
|
||||
void release_in_callback() noexcept override
|
||||
{
|
||||
// Simulate host-side resource cleanup
|
||||
callback_resource_release_count.fetch_add(1);
|
||||
}
|
||||
};
|
||||
|
||||
void reset_counters()
|
||||
{
|
||||
stream_resource_construct_count.store(0);
|
||||
stream_resource_release_count.store(0);
|
||||
callback_resource_construct_count.store(0);
|
||||
callback_resource_release_count.store(0);
|
||||
}
|
||||
|
||||
void check_all_resources_released()
|
||||
{
|
||||
// Verify all constructed resources were properly released
|
||||
EXPECT(stream_resource_construct_count.load() == stream_resource_release_count.load());
|
||||
EXPECT(callback_resource_construct_count.load() == callback_resource_release_count.load());
|
||||
}
|
||||
|
||||
template <typename CtxType>
|
||||
void test_context_resources()
|
||||
{
|
||||
reset_counters();
|
||||
|
||||
CtxType ctx;
|
||||
|
||||
// Add a simple host launch to ensure context has some work
|
||||
ctx.host_launch()->*[]() {
|
||||
// Trivial workload - just increment a counter
|
||||
static std::atomic<int> work_counter{0};
|
||||
work_counter.fetch_add(1);
|
||||
};
|
||||
|
||||
// Add various types of resources
|
||||
const int num_stream_resources = 3;
|
||||
const int num_callback_resources = 2;
|
||||
|
||||
// Add stream-dependent resources
|
||||
for (int i = 0; i < num_stream_resources; ++i)
|
||||
{
|
||||
auto resource = ::std::make_shared<test_stream_resource>();
|
||||
ctx.add_resource(resource);
|
||||
}
|
||||
|
||||
// Add callback resources
|
||||
for (int i = 0; i < num_callback_resources; ++i)
|
||||
{
|
||||
auto resource = ::std::make_shared<test_callback_resource>();
|
||||
ctx.add_resource(resource);
|
||||
}
|
||||
|
||||
// Verify resources were constructed
|
||||
EXPECT(stream_resource_construct_count.load() == num_stream_resources);
|
||||
EXPECT(callback_resource_construct_count.load() == num_callback_resources);
|
||||
EXPECT(stream_resource_release_count.load() == 0); // Not released yet
|
||||
EXPECT(callback_resource_release_count.load() == 0); // Not released yet
|
||||
|
||||
// Finalize the context - this should release resources automatically
|
||||
ctx.finalize();
|
||||
|
||||
// Verify all resources were released
|
||||
EXPECT(stream_resource_release_count.load() == num_stream_resources);
|
||||
EXPECT(callback_resource_release_count.load() == num_callback_resources);
|
||||
|
||||
check_all_resources_released();
|
||||
}
|
||||
|
||||
void test_graph_ctx_manual_resource_release()
|
||||
{
|
||||
reset_counters();
|
||||
|
||||
graph_ctx ctx;
|
||||
|
||||
// Add a simple host launch with work counter
|
||||
std::atomic<int> work_counter{0};
|
||||
ctx.host_launch()->*[&work_counter]() {
|
||||
work_counter.fetch_add(1);
|
||||
};
|
||||
|
||||
// Add resources
|
||||
const int num_resources = 2;
|
||||
for (int i = 0; i < num_resources; ++i)
|
||||
{
|
||||
ctx.add_resource(std::make_shared<test_stream_resource>());
|
||||
ctx.add_resource(std::make_shared<test_callback_resource>());
|
||||
}
|
||||
|
||||
EXPECT(stream_resource_construct_count.load() == num_resources);
|
||||
EXPECT(callback_resource_construct_count.load() == num_resources);
|
||||
|
||||
// Resources should not be released yet
|
||||
EXPECT(stream_resource_release_count.load() == 0);
|
||||
EXPECT(callback_resource_release_count.load() == 0);
|
||||
|
||||
// Generate the graph using finalize_as_graph
|
||||
::std::shared_ptr<cudaGraph_t> graph = ctx.finalize_as_graph();
|
||||
|
||||
// Create stream and instantiate graph for multiple launches
|
||||
cudaStream_t test_stream;
|
||||
cuda_safe_call(cudaStreamCreate(&test_stream));
|
||||
|
||||
cudaGraphExec_t graphExec;
|
||||
cuda_safe_call(cudaGraphInstantiate(&graphExec, *graph, nullptr, nullptr, 0));
|
||||
|
||||
// Launch the graph multiple times
|
||||
const int num_launches = 3;
|
||||
for (int i = 0; i < num_launches; i++)
|
||||
{
|
||||
cuda_safe_call(cudaGraphLaunch(graphExec, test_stream));
|
||||
}
|
||||
|
||||
// Manually release resources after graph executions
|
||||
ctx.release_resources(test_stream);
|
||||
cuda_safe_call(cudaStreamSynchronize(test_stream));
|
||||
|
||||
// Verify the work was executed
|
||||
EXPECT(work_counter.load() == num_launches);
|
||||
|
||||
// Now resources should be released
|
||||
EXPECT(stream_resource_release_count.load() == num_resources);
|
||||
EXPECT(callback_resource_release_count.load() == num_resources);
|
||||
|
||||
// Clean up
|
||||
cuda_safe_call(cudaGraphExecDestroy(graphExec));
|
||||
cuda_safe_call(cudaStreamDestroy(test_stream));
|
||||
|
||||
check_all_resources_released();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test with different context types
|
||||
test_context_resources<context>();
|
||||
test_context_resources<stream_ctx>();
|
||||
test_context_resources<graph_ctx>();
|
||||
|
||||
// Test manual resource release (graph_ctx only for the sake of simplicity)
|
||||
test_graph_ctx_manual_resource_release();
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of CUDASTF in CUDA C++ Core Libraries,
|
||||
// under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//! \file
|
||||
//! \brief Simple test demonstrating ctx_resource management with generic context
|
||||
|
||||
#include <cuda/experimental/__stf/internal/context.cuh>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
using namespace cuda::experimental::stf;
|
||||
|
||||
// Simple test resource that tracks its lifecycle
|
||||
class simple_test_resource : public ctx_resource
|
||||
{
|
||||
static ::std::atomic<int> alive_count;
|
||||
|
||||
public:
|
||||
simple_test_resource()
|
||||
{
|
||||
alive_count.fetch_add(1);
|
||||
}
|
||||
|
||||
~simple_test_resource() override
|
||||
{
|
||||
alive_count.fetch_sub(1);
|
||||
}
|
||||
|
||||
void release(cudaStream_t /*stream*/) noexcept override
|
||||
{
|
||||
// No special release action needed for this test
|
||||
}
|
||||
|
||||
bool can_release_in_callback() const noexcept override
|
||||
{
|
||||
return true; // Can be released in a host callback
|
||||
}
|
||||
|
||||
void release_in_callback() noexcept override
|
||||
{
|
||||
// Host-side cleanup - nothing to do for this simple test
|
||||
}
|
||||
|
||||
static int get_alive_count()
|
||||
{
|
||||
return alive_count.load();
|
||||
}
|
||||
};
|
||||
|
||||
::std::atomic<int> simple_test_resource::alive_count{0};
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test with generic context (defaults to stream_ctx)
|
||||
{
|
||||
context ctx; // Default initialization as stream_ctx
|
||||
|
||||
EXPECT(simple_test_resource::get_alive_count() == 0);
|
||||
|
||||
// Add a simple host launch with some work
|
||||
ctx.host_launch()->*[]() {
|
||||
// Trivial workload
|
||||
};
|
||||
|
||||
// Add some resources to the context
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
auto resource = ::std::make_shared<simple_test_resource>();
|
||||
ctx.add_resource(resource);
|
||||
}
|
||||
|
||||
// Verify resources are alive
|
||||
EXPECT(simple_test_resource::get_alive_count() == 5);
|
||||
|
||||
// Finalize the context - this should release all resources
|
||||
ctx.finalize();
|
||||
} // Context goes out of scope
|
||||
|
||||
// All resources should have been cleaned up
|
||||
EXPECT(simple_test_resource::get_alive_count() == 0);
|
||||
|
||||
// Test with graph context through generic interface
|
||||
{
|
||||
context ctx = graph_ctx(); // Explicitly use graph backend
|
||||
|
||||
EXPECT(simple_test_resource::get_alive_count() == 0);
|
||||
|
||||
ctx.host_launch()->*[]() {
|
||||
// Trivial workload
|
||||
};
|
||||
|
||||
// Add resources
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
ctx.add_resource(::std::make_shared<simple_test_resource>());
|
||||
}
|
||||
|
||||
EXPECT(simple_test_resource::get_alive_count() == 3);
|
||||
|
||||
ctx.finalize();
|
||||
}
|
||||
|
||||
EXPECT(simple_test_resource::get_alive_count() == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user