Skip to content
8 changes: 8 additions & 0 deletions include/cuco/detail/pair/helpers.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ struct packed {
using type = void; ///< `void` type by default
};

/**
* @brief Denotes the packed type when the size of the object is 2.
*/
template <>
struct packed<sizeof(uint16_t)> {
using type = uint16_t; ///< Packed type as `uint16_t` if the size of the object is 2
};
Comment on lines +53 to +56
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we add a 2B key-value pair in the map unit test to exercise this code path? One test case is sufficient.


/**
* @brief Denotes the packed type when the size of the object is 8.
*/
Expand Down
2 changes: 2 additions & 0 deletions include/cuco/static_map.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class static_map {
Allocator,
Storage>;

static_assert(sizeof(Key) > 1, "cuCollections does not support single-byte keys.");

public:
static constexpr auto cg_size = impl_type::cg_size; ///< CG size used for probing
static constexpr auto bucket_size = impl_type::bucket_size; ///< Bucket size used for probing
Expand Down
2 changes: 2 additions & 0 deletions include/cuco/static_set.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class static_set {
using impl_type = detail::
open_addressing_impl<Key, Key, Extent, Scope, KeyEqual, ProbingScheme, Allocator, Storage>;

static_assert(sizeof(Key) > 1, "cuCollections does not support single-byte keys.");

public:
static constexpr auto cg_size = impl_type::cg_size; ///< CG size used for probing
static constexpr auto bucket_size = impl_type::bucket_size; ///< Bucket size used for probing
Expand Down
1 change: 1 addition & 0 deletions tests/static_map/contains_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ TEMPLATE_TEST_CASE_SIG(
Value,
Probe,
CGSize),
(int16_t, int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int32_t, cuco::test::probe_sequence::double_hashing, 2),
(int64_t, int64_t, cuco::test::probe_sequence::double_hashing, 1),
Expand Down
30 changes: 30 additions & 0 deletions tests/static_map/find_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,33 @@ TEMPLATE_TEST_CASE_SIG(

test_unique_sequence(map, num_keys);
}

TEMPLATE_TEST_CASE_SIG(
"static_map: find tests (small types)",
"",
((typename Key, typename Value, cuco::test::probe_sequence Probe, int CGSize),
Key,
Value,
Probe,
CGSize),
(int16_t, int16_t, cuco::test::probe_sequence::double_hashing, 1))
{
constexpr size_type num_keys{100};

using extent_type = cuco::extent<size_type, num_keys>;
using probe = cuco::double_hashing<CGSize, cuco::murmurhash3_32<Key>, cuco::murmurhash3_32<Key>>;

auto map =
cuco::static_map<Key,
Value,
extent_type,
cuda::thread_scope_device,
cuda::std::equal_to<Key>,
probe,
cuco::cuda_allocator<cuda::std::byte>,
cuco::storage<2>>{extent_type{},
cuco::empty_key<Key>{static_cast<Key>(SENTINEL)},
cuco::empty_value<Value>{static_cast<Value>(SENTINEL)}};

test_unique_sequence(map, num_keys);
}
1 change: 1 addition & 0 deletions tests/static_map/insert_and_find_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ TEMPLATE_TEST_CASE_SIG(
Value,
Probe,
CGSize),
(int16_t, int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int64_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int32_t, cuco::test::probe_sequence::double_hashing, 2),
Expand Down
1 change: 1 addition & 0 deletions tests/static_map/retrieve_if_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ __global__ void test_retrieve_if_all_true_kernel(
TEMPLATE_TEST_CASE_SIG("static_map retrieve_if",
"",
((typename Key, typename T), Key, T),
(int16_t, int16_t),
(int32_t, int32_t),
(int64_t, int64_t)
#if defined(CUCO_HAS_128BIT_ATOMICS)
Expand Down
1 change: 1 addition & 0 deletions tests/static_map/retrieve_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ TEMPLATE_TEST_CASE_SIG(
Value,
Probe,
CGSize),
(int16_t, int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int64_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, int32_t, cuco::test::probe_sequence::double_hashing, 2),
Expand Down
11 changes: 7 additions & 4 deletions tests/static_map/shared_memory_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ __global__ void shared_memory_test_kernel(Ref* maps,
TEMPLATE_TEST_CASE_SIG("static_map shared memory tests",
"",
((typename Key, typename Value), Key, Value),
(int16_t, int16_t),
(int32_t, int32_t),
(int32_t, int64_t),
(int64_t, int32_t),
Expand All @@ -80,8 +81,9 @@ TEMPLATE_TEST_CASE_SIG("static_map shared memory tests",
#endif
)
{
constexpr std::size_t number_of_maps = 1000;
constexpr std::size_t elements_in_map = 500;
// For small types, use smaller set count and element count
constexpr std::size_t number_of_maps = (sizeof(Key) + sizeof(Value) <= 2) ? 100 : 1000;
constexpr std::size_t elements_in_map = (sizeof(Key) + sizeof(Value) <= 2) ? 100 : 500;
constexpr std::size_t map_capacity = 2 * elements_in_map;

using extent_type = cuco::extent<std::size_t, map_capacity>;
Expand All @@ -104,8 +106,9 @@ TEMPLATE_TEST_CASE_SIG("static_map shared memory tests",
// operator yet
std::vector<std::unique_ptr<map_type>> maps;
for (std::size_t map_id = 0; map_id < number_of_maps; ++map_id) {
maps.push_back(std::make_unique<map_type>(
extent_type{}, cuco::empty_key<Key>{-1}, cuco::empty_value<Value>{-1}));
maps.push_back(std::make_unique<map_type>(extent_type{},
cuco::empty_key<Key>{static_cast<Key>(-1)},
cuco::empty_value<Value>{static_cast<Value>(-1)}));
}

thrust::device_vector<bool> d_keys_exist(number_of_maps * elements_in_map);
Expand Down
17 changes: 9 additions & 8 deletions tests/static_map/stream_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
TEMPLATE_TEST_CASE_SIG("static_map: unique sequence of keys on given stream",
"",
((typename Key, typename Value), Key, Value),
(int16_t, int16_t),
(int32_t, int32_t),
(int32_t, int64_t),
(int64_t, int32_t),
Expand All @@ -46,15 +47,15 @@ TEMPLATE_TEST_CASE_SIG("static_map: unique sequence of keys on given stream",
CUCO_CUDA_TRY(cudaStreamCreate(&stream));

{ // Scope ensures map is destroyed before stream
constexpr std::size_t num_keys{500'000};
auto map = cuco::static_map{num_keys * 2,
cuco::empty_key<Key>{-1},
cuco::empty_value<Value>{-1},
{},
const std::size_t num_keys = (sizeof(Key) == 1) ? 100 : 500'000;
auto map = cuco::static_map{num_keys * 2,
cuco::empty_key<Key>{static_cast<Key>(-1)},
cuco::empty_value<Value>{static_cast<Value>(-1)},
{},
cuco::linear_probing<1, cuco::default_hash_function<Key>>{},
{},
{},
{},
{},
{},
{},
stream};

thrust::device_vector<Key> d_keys(num_keys);
Expand Down
26 changes: 20 additions & 6 deletions tests/static_set/for_each_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@

#include <catch2/catch_template_test_macros.hpp>

#include <cstdint>

using size_type = std::size_t;

template <typename Set>
void test_for_each(Set& set, size_type num_keys)
void test_for_each(Set& set, size_type num_keys, size_type expected_evens, size_type expected_odds)
{
using Key = typename Set::key_type;

Expand All @@ -40,7 +42,7 @@ void test_for_each(Set& set, size_type num_keys)
// Insert keys
auto keys_begin = cuda::make_transform_iterator(
cuda::counting_iterator<size_type>{0}, cuda::proclaim_return_type<Key>([] __device__(auto i) {
// generates a sequence of 1, 2, 1, 2, ...
// generates a sequence of 0, 1, 2, ...
return static_cast<Key>(i);
}));
set.insert(keys_begin, keys_begin + num_keys, stream);
Expand All @@ -56,7 +58,7 @@ void test_for_each(Set& set, size_type num_keys)
if (slot % 2 == 0) { counter->fetch_add(slot, cuda::memory_order_relaxed); }
},
stream);
REQUIRE(counter_storage.load_to_host(stream) == 249'500);
REQUIRE(counter_storage.load_to_host(stream) == expected_evens);

counter_storage.reset(stream);

Expand All @@ -68,13 +70,18 @@ void test_for_each(Set& set, size_type num_keys)
if (!(slot % 2 == 0)) { counter->fetch_add(slot, cuda::memory_order_relaxed); }
},
stream);
REQUIRE(counter_storage.load_to_host(stream) == 250'000);
REQUIRE(counter_storage.load_to_host(stream) == expected_odds);
}

TEMPLATE_TEST_CASE_SIG(
"static_set for_each tests",
"",
((typename Key, cuco::test::probe_sequence Probe, int CGSize), Key, Probe, CGSize),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 2),
(int16_t, cuco::test::probe_sequence::linear_probing, 1),
(int16_t, cuco::test::probe_sequence::linear_probing, 2),
(int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, cuco::test::probe_sequence::double_hashing, 2),
(int64_t, cuco::test::probe_sequence::double_hashing, 1),
Expand All @@ -92,7 +99,14 @@ TEMPLATE_TEST_CASE_SIG(
#endif
)
{
constexpr size_type num_keys{1'000};
// Limit key count for small types: leave room for the -1 sentinel.
// Expected sums are pre-computed per type class:
// int16_t (num_keys=100): sum of evens 0..98 = 2450, sum of odds 1..99 = 2500
// int16_t+ (num_keys=1000): sum of evens 0..998 = 249'500, sum of odds 1..999 = 250'000
constexpr size_type num_keys = (sizeof(Key) == 1) ? 100 : 1'000;
constexpr size_type expected_evens = (sizeof(Key) == 1) ? 2'450 : 249'500;
constexpr size_type expected_odds = (sizeof(Key) == 1) ? 2'500 : 250'000;

using probe = std::conditional_t<
Probe == cuco::test::probe_sequence::linear_probing,
cuco::linear_probing<CGSize, cuco::murmurhash3_32<Key>>,
Expand All @@ -107,5 +121,5 @@ TEMPLATE_TEST_CASE_SIG(
cuco::storage<2>>;

auto set = set_t{num_keys, cuco::empty_key<Key>{static_cast<Key>(-1)}};
test_for_each(set, num_keys);
test_for_each(set, num_keys, expected_evens, expected_odds);
}
10 changes: 9 additions & 1 deletion tests/static_set/insert_and_find_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

#include <catch2/catch_template_test_macros.hpp>

#include <cstdint>

template <typename Set>
void test_insert_and_find(Set& set, std::size_t num_keys)
{
Expand Down Expand Up @@ -56,6 +58,11 @@ TEMPLATE_TEST_CASE_SIG(
"static_set Insert and find",
"",
((typename Key, cuco::test::probe_sequence Probe, int CGSize), Key, Probe, CGSize),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 2),
(int16_t, cuco::test::probe_sequence::linear_probing, 1),
(int16_t, cuco::test::probe_sequence::linear_probing, 2),
(int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, cuco::test::probe_sequence::double_hashing, 2),
(int64_t, cuco::test::probe_sequence::double_hashing, 1),
Expand All @@ -73,7 +80,8 @@ TEMPLATE_TEST_CASE_SIG(
#endif
)
{
constexpr std::size_t num_keys{400};
// Limit key count for small types: leave room for the -1 sentinel
constexpr std::size_t num_keys = (sizeof(Key) == 1) ? 100 : 400;

using probe = std::conditional_t<Probe == cuco::test::probe_sequence::linear_probing,
cuco::linear_probing<CGSize, cuco::default_hash_function<Key>>,
Expand Down
21 changes: 17 additions & 4 deletions tests/static_set/retrieve_all_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include <catch2/catch_template_test_macros.hpp>

#include <cstdint>

template <typename Set>
void test_unique_sequence(Set& set, std::size_t num_keys)
{
Expand Down Expand Up @@ -61,6 +63,11 @@ TEMPLATE_TEST_CASE_SIG(
"static_set::retrieve_all tests",
"",
((typename Key, cuco::test::probe_sequence Probe, int CGSize), Key, Probe, CGSize),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 2),
(int16_t, cuco::test::probe_sequence::linear_probing, 1),
(int16_t, cuco::test::probe_sequence::linear_probing, 2),
(int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, cuco::test::probe_sequence::double_hashing, 2),
(int64_t, cuco::test::probe_sequence::double_hashing, 1),
Expand All @@ -78,7 +85,8 @@ TEMPLATE_TEST_CASE_SIG(
#endif
)
{
constexpr std::size_t num_keys{400};
// Limit key count for small types: leave room for the -1 sentinel
constexpr std::size_t num_keys = (sizeof(Key) == 1) ? 100 : 400;
constexpr double desired_load_factor = 1.;

using probe = std::conditional_t<Probe == cuco::test::probe_sequence::linear_probing,
Expand All @@ -87,10 +95,15 @@ TEMPLATE_TEST_CASE_SIG(

constexpr std::size_t gold_capacity = [&]() {
if constexpr (cuco::is_double_hashing<probe>::value) {
return (CGSize == 1) ? 401 // 401 x 1 x 1
: 422; // 211 x 2 x 1
if constexpr (num_keys == 100) {
return (CGSize == 1) ? 101 // 101 x 1 x 1
: 106; // 53 x 2 x 1
} else {
return (CGSize == 1) ? 401 // 401 x 1 x 1
: 422; // 211 x 2 x 1
}
} else {
return 400;
return num_keys;
}
}();

Expand Down
6 changes: 5 additions & 1 deletion tests/static_set/retrieve_if_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include <catch2/catch_template_test_macros.hpp>

#include <cstdint>

using size_type = std::size_t;

template <class Container>
Expand Down Expand Up @@ -110,6 +112,7 @@ __global__ void test_retrieve_if_all_true_kernel(
TEMPLATE_TEST_CASE_SIG("static_set retrieve_if",
"",
((typename Key), Key),
(int16_t),
(int32_t),
(int64_t)
#if defined(CUCO_HAS_128BIT_ATOMICS)
Expand All @@ -118,7 +121,8 @@ TEMPLATE_TEST_CASE_SIG("static_set retrieve_if",
#endif
)
{
constexpr size_type num_keys{400};
// Limit key count for small types: keys start at 1, sentinel is -1
constexpr size_type num_keys = (sizeof(Key) == 1) ? 100 : 400;

using container_type = cuco::static_set<Key>;

Expand Down
10 changes: 9 additions & 1 deletion tests/static_set/retrieve_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#include <catch2/catch_template_test_macros.hpp>

#include <cstdint>

static constexpr int key_sentinel = -1;

template <typename Set>
Expand Down Expand Up @@ -75,6 +77,11 @@ TEMPLATE_TEST_CASE_SIG(
"static_set retrieve tests",
"",
((typename Key, cuco::test::probe_sequence Probe, int CGSize), Key, Probe, CGSize),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 1),
(int16_t, cuco::test::probe_sequence::double_hashing, 2),
(int16_t, cuco::test::probe_sequence::linear_probing, 1),
(int16_t, cuco::test::probe_sequence::linear_probing, 2),
(int32_t, cuco::test::probe_sequence::double_hashing, 1),
(int32_t, cuco::test::probe_sequence::double_hashing, 2),
(int64_t, cuco::test::probe_sequence::double_hashing, 1),
Expand All @@ -92,7 +99,8 @@ TEMPLATE_TEST_CASE_SIG(
#endif
)
{
constexpr std::size_t num_keys{400};
// Limit key count for small types: leave room for the -1 sentinel
constexpr std::size_t num_keys = (sizeof(Key) == 1) ? 100 : 400;
constexpr double desired_load_factor = 1.;

using probe = std::conditional_t<Probe == cuco::test::probe_sequence::linear_probing,
Expand Down
Loading