1 /* 2 //@HEADER 3 // ************************************************************************ 4 // 5 // Kokkos v. 3.0 6 // Copyright (2020) National Technology & Engineering 7 // Solutions of Sandia, LLC (NTESS). 8 // 9 // Under the terms of Contract DE-NA0003525 with NTESS, 10 // the U.S. Government retains certain rights in this software. 11 // 12 // Redistribution and use in source and binary forms, with or without 13 // modification, are permitted provided that the following conditions are 14 // met: 15 // 16 // 1. Redistributions of source code must retain the above copyright 17 // notice, this list of conditions and the following disclaimer. 18 // 19 // 2. Redistributions in binary form must reproduce the above copyright 20 // notice, this list of conditions and the following disclaimer in the 21 // documentation and/or other materials provided with the distribution. 22 // 23 // 3. Neither the name of the Corporation nor the names of the 24 // contributors may be used to endorse or promote products derived from 25 // this software without specific prior written permission. 26 // 27 // THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY 28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE 31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 // 39 // Questions? Contact Christian R. Trott (crtrott@sandia.gov) 40 // 41 // ************************************************************************ 42 //@HEADER 43 */ 44 45 #ifndef KOKKOS_UNORDERED_MAP_IMPL_HPP 46 #define KOKKOS_UNORDERED_MAP_IMPL_HPP 47 48 #include <Kokkos_Core_fwd.hpp> 49 #include <cstdint> 50 51 #include <cstdio> 52 #include <climits> 53 #include <iostream> 54 #include <iomanip> 55 56 namespace Kokkos { 57 namespace Impl { 58 59 uint32_t find_hash_size(uint32_t size); 60 61 template <typename Map> 62 struct UnorderedMapRehash { 63 using map_type = Map; 64 using const_map_type = typename map_type::const_map_type; 65 using execution_space = typename map_type::execution_space; 66 using size_type = typename map_type::size_type; 67 68 map_type m_dst; 69 const_map_type m_src; 70 UnorderedMapRehashKokkos::Impl::UnorderedMapRehash71 UnorderedMapRehash(map_type const& dst, const_map_type const& src) 72 : m_dst(dst), m_src(src) {} 73 applyKokkos::Impl::UnorderedMapRehash74 void apply() const { 75 parallel_for("Kokkos::Impl::UnorderedMapRehash::apply", m_src.capacity(), 76 *this); 77 } 78 79 KOKKOS_INLINE_FUNCTION operator ()Kokkos::Impl::UnorderedMapRehash80 void operator()(size_type i) const { 81 if (m_src.valid_at(i)) m_dst.insert(m_src.key_at(i), m_src.value_at(i)); 82 } 83 }; 84 85 template <typename UMap> 86 struct UnorderedMapErase { 87 using map_type = UMap; 88 using execution_space = typename map_type::execution_space; 89 using size_type = typename map_type::size_type; 90 using key_type = typename map_type::key_type; 91 using value_type = typename map_type::impl_value_type; 92 93 map_type m_map; 94 UnorderedMapEraseKokkos::Impl::UnorderedMapErase95 UnorderedMapErase(map_type const& map) : m_map(map) {} 96 applyKokkos::Impl::UnorderedMapErase97 void apply() const { 98 parallel_for("Kokkos::Impl::UnorderedMapErase::apply", 99 m_map.m_hash_lists.extent(0), *this); 100 } 101 102 KOKKOS_INLINE_FUNCTION operator ()Kokkos::Impl::UnorderedMapErase103 void operator()(size_type i) const { 104 const size_type invalid_index = map_type::invalid_index; 105 106 size_type curr = m_map.m_hash_lists(i); 107 size_type next = invalid_index; 108 109 // remove erased head of the linked-list 110 while (curr != invalid_index && !m_map.valid_at(curr)) { 111 next = m_map.m_next_index[curr]; 112 m_map.m_next_index[curr] = invalid_index; 113 m_map.m_keys[curr] = key_type(); 114 if (m_map.is_set) m_map.m_values[curr] = value_type(); 115 curr = next; 116 m_map.m_hash_lists(i) = next; 117 } 118 119 // if the list is non-empty and the head is valid 120 if (curr != invalid_index && m_map.valid_at(curr)) { 121 size_type prev = curr; 122 curr = m_map.m_next_index[prev]; 123 124 while (curr != invalid_index) { 125 next = m_map.m_next_index[curr]; 126 if (m_map.valid_at(curr)) { 127 prev = curr; 128 } else { 129 // remove curr from list 130 m_map.m_next_index[prev] = next; 131 m_map.m_next_index[curr] = invalid_index; 132 m_map.m_keys[curr] = key_type(); 133 if (map_type::is_set) m_map.m_values[curr] = value_type(); 134 } 135 curr = next; 136 } 137 } 138 } 139 }; 140 141 template <typename UMap> 142 struct UnorderedMapHistogram { 143 using map_type = UMap; 144 using execution_space = typename map_type::execution_space; 145 using size_type = typename map_type::size_type; 146 147 using histogram_view = View<int[100], execution_space>; 148 using host_histogram_view = typename histogram_view::HostMirror; 149 150 map_type m_map; 151 histogram_view m_length; 152 histogram_view m_distance; 153 histogram_view m_block_distance; 154 UnorderedMapHistogramKokkos::Impl::UnorderedMapHistogram155 UnorderedMapHistogram(map_type const& map) 156 : m_map(map), 157 m_length("UnorderedMap Histogram"), 158 m_distance("UnorderedMap Histogram"), 159 m_block_distance("UnorderedMap Histogram") {} 160 calculateKokkos::Impl::UnorderedMapHistogram161 void calculate() { 162 parallel_for("Kokkos::Impl::UnorderedMapHistogram::calculate", 163 m_map.m_hash_lists.extent(0), *this); 164 } 165 clearKokkos::Impl::UnorderedMapHistogram166 void clear() { 167 Kokkos::deep_copy(m_length, 0); 168 Kokkos::deep_copy(m_distance, 0); 169 Kokkos::deep_copy(m_block_distance, 0); 170 } 171 print_lengthKokkos::Impl::UnorderedMapHistogram172 void print_length(std::ostream& out) { 173 host_histogram_view host_copy = create_mirror_view(m_length); 174 Kokkos::deep_copy(host_copy, m_length); 175 176 for (int i = 0, size = host_copy.extent(0); i < size; ++i) { 177 out << host_copy[i] << " , "; 178 } 179 out << "\b\b\b " << std::endl; 180 } 181 print_distanceKokkos::Impl::UnorderedMapHistogram182 void print_distance(std::ostream& out) { 183 host_histogram_view host_copy = create_mirror_view(m_distance); 184 Kokkos::deep_copy(host_copy, m_distance); 185 186 for (int i = 0, size = host_copy.extent(0); i < size; ++i) { 187 out << host_copy[i] << " , "; 188 } 189 out << "\b\b\b " << std::endl; 190 } 191 print_block_distanceKokkos::Impl::UnorderedMapHistogram192 void print_block_distance(std::ostream& out) { 193 host_histogram_view host_copy = create_mirror_view(m_block_distance); 194 Kokkos::deep_copy(host_copy, m_block_distance); 195 196 for (int i = 0, size = host_copy.extent(0); i < size; ++i) { 197 out << host_copy[i] << " , "; 198 } 199 out << "\b\b\b " << std::endl; 200 } 201 202 KOKKOS_INLINE_FUNCTION operator ()Kokkos::Impl::UnorderedMapHistogram203 void operator()(size_type i) const { 204 const size_type invalid_index = map_type::invalid_index; 205 206 uint32_t length = 0; 207 size_type min_index = ~0u, max_index = 0; 208 for (size_type curr = m_map.m_hash_lists(i); curr != invalid_index; 209 curr = m_map.m_next_index[curr]) { 210 ++length; 211 min_index = (curr < min_index) ? curr : min_index; 212 max_index = (max_index < curr) ? curr : max_index; 213 } 214 215 size_type distance = (0u < length) ? max_index - min_index : 0u; 216 size_type blocks = (0u < length) ? max_index / 32u - min_index / 32u : 0u; 217 218 // normalize data 219 length = length < 100u ? length : 99u; 220 distance = distance < 100u ? distance : 99u; 221 blocks = blocks < 100u ? blocks : 99u; 222 223 if (0u < length) { 224 atomic_fetch_add(&m_length(length), 1); 225 atomic_fetch_add(&m_distance(distance), 1); 226 atomic_fetch_add(&m_block_distance(blocks), 1); 227 } 228 } 229 }; 230 231 template <typename UMap> 232 struct UnorderedMapPrint { 233 using map_type = UMap; 234 using execution_space = typename map_type::execution_space; 235 using size_type = typename map_type::size_type; 236 237 map_type m_map; 238 UnorderedMapPrintKokkos::Impl::UnorderedMapPrint239 UnorderedMapPrint(map_type const& map) : m_map(map) {} 240 applyKokkos::Impl::UnorderedMapPrint241 void apply() { 242 parallel_for("Kokkos::Impl::UnorderedMapPrint::apply", 243 m_map.m_hash_lists.extent(0), *this); 244 } 245 246 KOKKOS_INLINE_FUNCTION operator ()Kokkos::Impl::UnorderedMapPrint247 void operator()(size_type i) const { 248 const size_type invalid_index = map_type::invalid_index; 249 250 uint32_t list = m_map.m_hash_lists(i); 251 for (size_type curr = list, ii = 0; curr != invalid_index; 252 curr = m_map.m_next_index[curr], ++ii) { 253 KOKKOS_IMPL_DO_NOT_USE_PRINTF("%d[%d]: %d->%d\n", list, ii, 254 m_map.key_at(curr), m_map.value_at(curr)); 255 } 256 } 257 }; 258 259 template <typename DKey, typename DValue, typename SKey, typename SValue> 260 struct UnorderedMapCanAssign : public std::false_type {}; 261 262 template <typename Key, typename Value> 263 struct UnorderedMapCanAssign<Key, Value, Key, Value> : public std::true_type {}; 264 265 template <typename Key, typename Value> 266 struct UnorderedMapCanAssign<const Key, Value, Key, Value> 267 : public std::true_type {}; 268 269 template <typename Key, typename Value> 270 struct UnorderedMapCanAssign<const Key, const Value, Key, Value> 271 : public std::true_type {}; 272 273 template <typename Key, typename Value> 274 struct UnorderedMapCanAssign<const Key, const Value, const Key, Value> 275 : public std::true_type {}; 276 277 } // namespace Impl 278 } // namespace Kokkos 279 280 #endif // KOKKOS_UNORDERED_MAP_IMPL_HPP 281