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