Skip to content

Commit c63ac89

Browse files
make murmurhash3_x64_128 compatible with existing cuco data structures (#501)
1 parent 057d3e0 commit c63ac89

4 files changed

Lines changed: 119 additions & 5 deletions

File tree

include/cuco/detail/probing_scheme_impl.inl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ __host__ __device__ constexpr auto linear_probing<CGSize, Hash>::operator()(
121121
{
122122
using size_type = typename Extent::value_type;
123123
return detail::probing_iterator<Extent>{
124-
cuco::detail::sanitize_hash<size_type>(hash_(probe_key) + g.thread_rank()) % upper_bound,
124+
cuco::detail::sanitize_hash<size_type>(g, hash_(probe_key)) % upper_bound,
125125
cg_size,
126126
upper_bound};
127127
}
@@ -164,7 +164,7 @@ __host__ __device__ constexpr auto double_hashing<CGSize, Hash1, Hash2>::operato
164164
{
165165
using size_type = typename Extent::value_type;
166166
return detail::probing_iterator<Extent>{
167-
cuco::detail::sanitize_hash<size_type>(hash1_(probe_key) + g.thread_rank()) % upper_bound,
167+
cuco::detail::sanitize_hash<size_type>(g, hash1_(probe_key)) % upper_bound,
168168
static_cast<size_type>(
169169
(cuco::detail::sanitize_hash<size_type>(hash2_(probe_key)) % (upper_bound / cg_size - 1) +
170170
1) *

include/cuco/detail/utils.cuh

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717

1818
#include <cuco/detail/bitwise_compare.cuh>
1919

20+
#include <cuda/std/array>
2021
#include <cuda/std/bit>
2122
#include <cuda/std/cmath>
23+
#include <cuda/std/limits>
2224
#include <cuda/std/type_traits>
2325
#include <thrust/tuple.h>
2426

27+
#include <cstddef>
28+
2529
namespace cuco {
2630
namespace detail {
2731

@@ -81,6 +85,16 @@ struct slot_is_filled {
8185
}
8286
};
8387

88+
template <typename SizeType, typename HashType>
89+
__host__ __device__ constexpr SizeType to_positive(HashType hash)
90+
{
91+
if constexpr (cuda::std::is_signed_v<SizeType>) {
92+
return cuda::std::abs(static_cast<SizeType>(hash));
93+
} else {
94+
return static_cast<SizeType>(hash);
95+
}
96+
}
97+
8498
/**
8599
* @brief Converts a given hash value into a valid (positive) size type.
86100
*
@@ -92,12 +106,39 @@ struct slot_is_filled {
92106
template <typename SizeType, typename HashType>
93107
__host__ __device__ constexpr SizeType sanitize_hash(HashType hash) noexcept
94108
{
95-
if constexpr (cuda::std::is_signed_v<SizeType>) {
96-
return cuda::std::abs(static_cast<SizeType>(hash));
109+
if constexpr (cuda::std::is_same_v<HashType, cuda::std::array<std::uint64_t, 2>>) {
110+
#if !defined(CUCO_HAS_INT128)
111+
static_assert(false,
112+
"CUCO_HAS_INT128 undefined. Need unsigned __int128 type when sanitizing "
113+
"cuda::std::array<std::uint64_t, 2>");
114+
#endif
115+
unsigned __int128 ret{};
116+
memcpy(&ret, &hash, sizeof(unsigned __int128));
117+
return to_positive<SizeType>(static_cast<SizeType>(ret));
97118
} else {
98-
return static_cast<SizeType>(hash);
119+
return to_positive<SizeType>(hash);
99120
}
100121
}
101122

123+
/**
124+
* @brief Converts a given hash value and cg_rank, into a valid (positive) size type.
125+
*
126+
* @tparam SizeType The target type
127+
* @tparam CG Cooperative group type
128+
* @tparam HashType The input type
129+
*
130+
* @return Converted hash value
131+
*/
132+
template <typename SizeType, typename CG, typename HashType>
133+
__device__ constexpr SizeType sanitize_hash(CG const& group, HashType hash) noexcept
134+
{
135+
auto const base_hash = sanitize_hash<SizeType>(hash);
136+
auto const max_size = cuda::std::numeric_limits<SizeType>::max();
137+
auto const cg_rank = static_cast<SizeType>(group.thread_rank());
138+
139+
if (base_hash > (max_size - cg_rank)) { return cg_rank - (max_size - base_hash); }
140+
return base_hash + cg_rank;
141+
}
142+
102143
} // namespace detail
103144
} // namespace cuco

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ ConfigureTest(STATIC_MAP_TEST
7676
static_map/custom_type_test.cu
7777
static_map/duplicate_keys_test.cu
7878
static_map/erase_test.cu
79+
static_map/hash_test.cu
7980
static_map/heterogeneous_lookup_test.cu
8081
static_map/insert_and_find_test.cu
8182
static_map/insert_or_assign_test.cu

tests/static_map/hash_test.cu

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2024, NVIDIA CORPORATION.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <test_utils.hpp>
18+
19+
#include <cuco/hash_functions.cuh>
20+
#include <cuco/static_map.cuh>
21+
22+
#include <thrust/device_vector.h>
23+
#include <thrust/functional.h>
24+
#include <thrust/iterator/counting_iterator.h>
25+
#include <thrust/iterator/transform_iterator.h>
26+
27+
#include <catch2/catch_template_test_macros.hpp>
28+
29+
using size_type = std::size_t;
30+
31+
template <typename Key, typename Hash>
32+
void test_hash_function()
33+
{
34+
using Value = int64_t;
35+
36+
constexpr size_type num_keys{400};
37+
38+
auto map = cuco::static_map<Key,
39+
Value,
40+
cuco::extent<size_type>,
41+
cuda::thread_scope_device,
42+
thrust::equal_to<Key>,
43+
cuco::linear_probing<1, Hash>,
44+
cuco::cuda_allocator<std::byte>,
45+
cuco::storage<2>>{
46+
num_keys, cuco::empty_key<Key>{-1}, cuco::empty_value<Value>{-1}};
47+
48+
auto keys_begin = thrust::counting_iterator<Key>(1);
49+
50+
auto pairs_begin = thrust::make_transform_iterator(
51+
keys_begin, cuda::proclaim_return_type<cuco::pair<Key, Value>>([] __device__(auto i) {
52+
return cuco::pair<Key, Value>(i, i);
53+
}));
54+
55+
thrust::device_vector<bool> d_keys_exist(num_keys);
56+
57+
map.insert(pairs_begin, pairs_begin + num_keys);
58+
59+
REQUIRE(map.size() == num_keys);
60+
61+
map.contains(keys_begin, keys_begin + num_keys, d_keys_exist.begin());
62+
63+
REQUIRE(cuco::test::all_of(d_keys_exist.begin(), d_keys_exist.end(), thrust::identity{}));
64+
}
65+
66+
TEMPLATE_TEST_CASE_SIG("static_map hash tests", "", ((typename Key)), (int32_t), (int64_t))
67+
{
68+
test_hash_function<Key, cuco::murmurhash3_32<Key>>();
69+
test_hash_function<Key, cuco::murmurhash3_x64_128<Key>>();
70+
test_hash_function<Key, cuco::xxhash_32<Key>>();
71+
test_hash_function<Key, cuco::xxhash_64<Key>>();
72+
}

0 commit comments

Comments
 (0)