cuda::experimental::coop::coalesced_group#
namespace cuda::experimental::coop {
template <typename Hierarchy>
class coalesced_group : public /*group-interface-for*/<coalesced_group>
{
public:
using unit_type = thread_level;
using level_type = warp_level;
using hierarchy_type = Hierarchy;
coalesced_group() = delete;
template <typename HierarchyLike>
requires cuda::std::same_as<Hierarchy, /*hierarchy-type-of*/<HierarchyLike>>
__device__ explicit coalesced_group(const HierarchyLike& hierarchy_like) noexcept;
coalesced_group(const coalesced_group&) = delete;
coalesced_group(coalesced_group&&) = delete;
coalesced_group& operator=(const coalesced_group&) = delete;
coalesced_group& operator=(coalesced_group&&) = delete;
};
template </*hierarchy-like-type*/ HierarchyLike>
coalesced_group(const HierarchyLike&) -> coalesced_group</*hierarchy-type-of*/<HierarchyLike>>;
} // namespace cuda::experimental::coop
Overview#
cuda::experimental::coop::coalesced_group is a predefined group that groups all currently active threads within a warp. It is useful for opportunistic programming. The mapping result is determined based on the lane mask returned by the __activemask() intrinsic. The group can be explicitly constructed from a hierarchy-like object.
A coalesced group is not always contiguous.
A coalesced group uses the cuda::experimental::coop::lane_synchronizer synchronizer for synchronization.
Queries#
Sub-unit queries work as with any other group type; however, since the coalesced group doesn’t have a parent group, a native hierarchy level must be used in the super-level queries as the upper bound. For example, cuda::experimental::coop::coalesced_group{...}.count(cuda::block) queries the number of coalesced groups within a block. It is equivalent to the number of warps within a block.
Examples#
#include <cuda/devices>
#include <cuda/stream>
#include <cuda/hierarchy>
#include <cuda/launch>
#include <cuda/std/cassert>
#include <cuda/experimental/coop/group>
namespace cudax = cuda::experimental;
__device__ void demo(auto config)
{
cudax::coop::this_warp warp{config};
// When the whole warp takes the same path, coalesced_group and this_warp contain the same threads in the same order.
{
cudax::coop::coalesced_group coalesced{config};
assert(cuda::gpu_thread.count(coalesced) == cuda::gpu_thread.count(warp));
assert(cuda::gpu_thread.rank(coalesced) == cuda::gpu_thread.rank(warp));
coalesced.sync();
warp.sync();
}
// When we split the warp in half, the coalesced group shall contain only half of the threads.
if (cuda::gpu_thread.rank(warp) < 16)
{
cudax::coop::coalesced_group coalesced{config};
assert(cuda::gpu_thread.count(coalesced) == 16);
assert(cuda::gpu_thread.rank(coalesced) < 16);
coalesced.sync();
}
}
struct Kernel
{
__device__ void operator()(auto config) const
{
demo(config);
}
};
int main()
{
// Select a device and create a stream for it.
const auto device = cuda::devices[0];
cuda::stream stream{device};
// Launch the test kernel on the stream.
const auto config = cuda::make_config(cuda::grid_dims(1), cuda::block_dims<32>());
cuda::launch(stream, config, Kernel{});
// Wait until the kernel finishes.
stream.sync();
}