annotate libcilkrts/runtime/reducer_impl.cpp @ 136:4627f235cf2a

fix c-next example
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Thu, 08 Nov 2018 14:11:56 +0900
parents 04ced10e8804
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* reducer_impl.cpp -*-C++-*-
kono
parents:
diff changeset
2 *
kono
parents:
diff changeset
3 *************************************************************************
kono
parents:
diff changeset
4 *
kono
parents:
diff changeset
5 * Copyright (C) 2009-2016, Intel Corporation
kono
parents:
diff changeset
6 * All rights reserved.
kono
parents:
diff changeset
7 *
kono
parents:
diff changeset
8 * Redistribution and use in source and binary forms, with or without
kono
parents:
diff changeset
9 * modification, are permitted provided that the following conditions
kono
parents:
diff changeset
10 * are met:
kono
parents:
diff changeset
11 *
kono
parents:
diff changeset
12 * * Redistributions of source code must retain the above copyright
kono
parents:
diff changeset
13 * notice, this list of conditions and the following disclaimer.
kono
parents:
diff changeset
14 * * Redistributions in binary form must reproduce the above copyright
kono
parents:
diff changeset
15 * notice, this list of conditions and the following disclaimer in
kono
parents:
diff changeset
16 * the documentation and/or other materials provided with the
kono
parents:
diff changeset
17 * distribution.
kono
parents:
diff changeset
18 * * Neither the name of Intel Corporation nor the names of its
kono
parents:
diff changeset
19 * contributors may be used to endorse or promote products derived
kono
parents:
diff changeset
20 * from this software without specific prior written permission.
kono
parents:
diff changeset
21 *
kono
parents:
diff changeset
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
kono
parents:
diff changeset
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
kono
parents:
diff changeset
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
kono
parents:
diff changeset
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
kono
parents:
diff changeset
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
kono
parents:
diff changeset
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
kono
parents:
diff changeset
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
kono
parents:
diff changeset
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
kono
parents:
diff changeset
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
kono
parents:
diff changeset
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
kono
parents:
diff changeset
32 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
kono
parents:
diff changeset
33 * POSSIBILITY OF SUCH DAMAGE.
kono
parents:
diff changeset
34 *
kono
parents:
diff changeset
35 * *********************************************************************
kono
parents:
diff changeset
36 *
kono
parents:
diff changeset
37 * PLEASE NOTE: This file is a downstream copy of a file mainitained in
kono
parents:
diff changeset
38 * a repository at cilkplus.org. Changes made to this file that are not
kono
parents:
diff changeset
39 * submitted through the contribution process detailed at
kono
parents:
diff changeset
40 * http://www.cilkplus.org/submit-cilk-contribution will be lost the next
kono
parents:
diff changeset
41 * time that a new version is released. Changes only submitted to the
kono
parents:
diff changeset
42 * GNU compiler collection or posted to the git repository at
kono
parents:
diff changeset
43 * https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
kono
parents:
diff changeset
44 * not tracked.
kono
parents:
diff changeset
45 *
kono
parents:
diff changeset
46 * We welcome your contributions to this open source project. Thank you
kono
parents:
diff changeset
47 * for your assistance in helping us improve Cilk Plus.
kono
parents:
diff changeset
48 *
kono
parents:
diff changeset
49 * Patents Pending, Intel Corporation.
kono
parents:
diff changeset
50 **************************************************************************/
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 /**
kono
parents:
diff changeset
53 * Support for reducers
kono
parents:
diff changeset
54 */
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 // ICL: Don't complain about conversion from pointer to same-sized integral type
kono
parents:
diff changeset
57 // in hashfun. That's why we're using size_t
kono
parents:
diff changeset
58 #ifdef _WIN32
kono
parents:
diff changeset
59 # pragma warning(disable: 1684)
kono
parents:
diff changeset
60 #endif
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 #include "reducer_impl.h"
kono
parents:
diff changeset
63 #include "scheduler.h"
kono
parents:
diff changeset
64 #include "bug.h"
kono
parents:
diff changeset
65 #include "os.h"
kono
parents:
diff changeset
66 #include "global_state.h"
kono
parents:
diff changeset
67 #include "frame_malloc.h"
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 #include "cilk/hyperobject_base.h"
kono
parents:
diff changeset
70 #include "cilktools/cilkscreen.h"
kono
parents:
diff changeset
71 #include "internal/abi.h"
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 #if REDPAR_DEBUG > 0
kono
parents:
diff changeset
74 #include <stdio.h>
kono
parents:
diff changeset
75 #include <stdlib.h>
kono
parents:
diff changeset
76 #endif
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78
kono
parents:
diff changeset
79 #define DBG if(0) // if(1) enables some internal checks
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 // Check that w is the currently executing worker. This method is a
kono
parents:
diff changeset
82 // no-op unless the debug level is set high enough.
kono
parents:
diff changeset
83 static inline void verify_current_wkr(__cilkrts_worker *w)
kono
parents:
diff changeset
84 {
kono
parents:
diff changeset
85 #if REDPAR_DEBUG >= 5
kono
parents:
diff changeset
86 __cilkrts_worker* tmp = __cilkrts_get_tls_worker();
kono
parents:
diff changeset
87 if (w != tmp) {
kono
parents:
diff changeset
88 fprintf(stderr, "W=%d, actual=%d... missing a refresh....\n",
kono
parents:
diff changeset
89 w->self,
kono
parents:
diff changeset
90 tmp->self);
kono
parents:
diff changeset
91 }
kono
parents:
diff changeset
92 CILK_ASSERT(w == tmp); // __cilkrts_get_tls_worker());
kono
parents:
diff changeset
93 #endif
kono
parents:
diff changeset
94 }
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96 // Suppress clang warning that the expression result is unused
kono
parents:
diff changeset
97 #if defined(__clang__) && (! defined(__INTEL_COMPILER))
kono
parents:
diff changeset
98 # pragma clang diagnostic push
kono
parents:
diff changeset
99 # pragma clang diagnostic ignored "-Wunused-value"
kono
parents:
diff changeset
100 #endif // __clang__
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 /// Helper class to disable and re-enable Cilkscreen
kono
parents:
diff changeset
103 struct DisableCilkscreen
kono
parents:
diff changeset
104 {
kono
parents:
diff changeset
105 DisableCilkscreen () { __cilkscreen_disable_checking(); }
kono
parents:
diff changeset
106 ~DisableCilkscreen () { __cilkscreen_enable_checking(); }
kono
parents:
diff changeset
107 };
kono
parents:
diff changeset
108
kono
parents:
diff changeset
109 /// Helper class to enable and re-disable Cilkscreen
kono
parents:
diff changeset
110 struct EnableCilkscreen
kono
parents:
diff changeset
111 {
kono
parents:
diff changeset
112 EnableCilkscreen () { __cilkscreen_enable_checking(); }
kono
parents:
diff changeset
113 ~EnableCilkscreen () { __cilkscreen_disable_checking(); }
kono
parents:
diff changeset
114 };
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 #if defined(__clang__) && (! defined(__INTEL_COMPILER))
kono
parents:
diff changeset
117 # pragma clang diagnostic pop
kono
parents:
diff changeset
118 #endif // __clang__
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 /**
kono
parents:
diff changeset
121 * @brief Element for a hyperobject
kono
parents:
diff changeset
122 */
kono
parents:
diff changeset
123 struct elem {
kono
parents:
diff changeset
124 void *key; ///< Shared key for this hyperobject
kono
parents:
diff changeset
125 __cilkrts_hyperobject_base *hb; ///< Base of the hyperobject.
kono
parents:
diff changeset
126 void *view; ///< Strand-private view of this hyperobject
kono
parents:
diff changeset
127 /// Destroy and deallocate the view object for this element and set view to
kono
parents:
diff changeset
128 /// null.
kono
parents:
diff changeset
129 void destroy();
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 /// Returns true if this element contains a leftmost view.
kono
parents:
diff changeset
132 bool is_leftmost() const;
kono
parents:
diff changeset
133 };
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 /** Bucket containing at most NMAX elements */
kono
parents:
diff changeset
136 struct bucket {
kono
parents:
diff changeset
137 /// Size of the array of elements for this bucket
kono
parents:
diff changeset
138 size_t nmax;
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 /**
kono
parents:
diff changeset
141 * We use the ``struct hack'' to allocate an array of variable
kono
parents:
diff changeset
142 * dimension at the end of the struct. However, we allocate a
kono
parents:
diff changeset
143 * total of NMAX+1 elements instead of NMAX. The last one always
kono
parents:
diff changeset
144 * has key == 0, which we use as a termination criterion
kono
parents:
diff changeset
145 */
kono
parents:
diff changeset
146 elem el[1];
kono
parents:
diff changeset
147 };
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 /**
kono
parents:
diff changeset
150 * Class that implements the map for reducers so we can find the
kono
parents:
diff changeset
151 * view for a strand.
kono
parents:
diff changeset
152 */
kono
parents:
diff changeset
153 struct cilkred_map {
kono
parents:
diff changeset
154 /** Handy pointer to the global state */
kono
parents:
diff changeset
155 global_state_t *g;
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 /** Number of elements in table */
kono
parents:
diff changeset
158 size_t nelem;
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 /** Number of buckets */
kono
parents:
diff changeset
161 size_t nbuckets;
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 /** Array of pointers to buckets */
kono
parents:
diff changeset
164 bucket **buckets;
kono
parents:
diff changeset
165
kono
parents:
diff changeset
166 /** Set true if merging (for debugging purposes) */
kono
parents:
diff changeset
167 bool merging;
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169 /** Set true for leftmost reducer map */
kono
parents:
diff changeset
170 bool is_leftmost;
kono
parents:
diff changeset
171
kono
parents:
diff changeset
172 /** @brief Return element mapped to 'key' or null if not found. */
kono
parents:
diff changeset
173 elem *lookup(void *key);
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 /**
kono
parents:
diff changeset
176 * @brief Insert key/value element into hash map without rehashing.
kono
parents:
diff changeset
177 * Does not check for duplicate key.
kono
parents:
diff changeset
178 */
kono
parents:
diff changeset
179 elem *insert_no_rehash(__cilkrts_worker *w,
kono
parents:
diff changeset
180 void *key,
kono
parents:
diff changeset
181 __cilkrts_hyperobject_base *hb,
kono
parents:
diff changeset
182 void *value);
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 /**
kono
parents:
diff changeset
185 * @brief Insert key/value element into hash map, rehashing if necessary.
kono
parents:
diff changeset
186 * Does not check for duplicate key.
kono
parents:
diff changeset
187 */
kono
parents:
diff changeset
188 inline elem *rehash_and_insert(__cilkrts_worker *w,
kono
parents:
diff changeset
189 void *key,
kono
parents:
diff changeset
190 __cilkrts_hyperobject_base *hb,
kono
parents:
diff changeset
191 void *value);
kono
parents:
diff changeset
192
kono
parents:
diff changeset
193 /** @brief Grow bucket by one element, reallocating bucket if necessary */
kono
parents:
diff changeset
194 static elem *grow(__cilkrts_worker *w, bucket **bp);
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 /** @brief Rehash a worker's reducer map */
kono
parents:
diff changeset
197 void rehash(__cilkrts_worker *);
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 /**
kono
parents:
diff changeset
200 * @brief Returns true if a rehash is needed due to the number of elements that
kono
parents:
diff changeset
201 * have been inserted.
kono
parents:
diff changeset
202 */
kono
parents:
diff changeset
203 inline bool need_rehash_p() const;
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 /** @brief Allocate and initialize the buckets */
kono
parents:
diff changeset
206 void make_buckets(__cilkrts_worker *w, size_t nbuckets);
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 /**
kono
parents:
diff changeset
209 * Specify behavior when the same key is present in both maps passed
kono
parents:
diff changeset
210 * into merge().
kono
parents:
diff changeset
211 */
kono
parents:
diff changeset
212 enum merge_kind
kono
parents:
diff changeset
213 {
kono
parents:
diff changeset
214 MERGE_UNORDERED, ///< Assertion fails
kono
parents:
diff changeset
215 MERGE_INTO_LEFT, ///< Merges the argument from the right into the left
kono
parents:
diff changeset
216 MERGE_INTO_RIGHT ///< Merges the argument from the left into the right
kono
parents:
diff changeset
217 };
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 /**
kono
parents:
diff changeset
220 * @brief Merge another reducer map into this one, destroying the other map in
kono
parents:
diff changeset
221 * the process.
kono
parents:
diff changeset
222 */
kono
parents:
diff changeset
223 __cilkrts_worker* merge(__cilkrts_worker *current_wkr,
kono
parents:
diff changeset
224 cilkred_map *other_map,
kono
parents:
diff changeset
225 enum merge_kind kind);
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 /** @brief check consistency of a reducer map */
kono
parents:
diff changeset
228 void check(bool allow_null_view);
kono
parents:
diff changeset
229
kono
parents:
diff changeset
230 /** @brief Test whether the cilkred_map is empty */
kono
parents:
diff changeset
231 bool is_empty() { return nelem == 0; }
kono
parents:
diff changeset
232 };
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 static inline struct cilkred_map* install_new_reducer_map(__cilkrts_worker *w) {
kono
parents:
diff changeset
235 cilkred_map *h;
kono
parents:
diff changeset
236 h = __cilkrts_make_reducer_map(w);
kono
parents:
diff changeset
237 w->reducer_map = h;
kono
parents:
diff changeset
238 return h;
kono
parents:
diff changeset
239 }
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 static size_t sizeof_bucket(size_t nmax)
kono
parents:
diff changeset
242 {
kono
parents:
diff changeset
243 bucket *b = 0;
kono
parents:
diff changeset
244 return (sizeof(*b) + nmax * sizeof(b->el[0]));
kono
parents:
diff changeset
245 }
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 static bucket *alloc_bucket(__cilkrts_worker *w, size_t nmax)
kono
parents:
diff changeset
248 {
kono
parents:
diff changeset
249 bucket *b = (bucket *)
kono
parents:
diff changeset
250 __cilkrts_frame_malloc(w, sizeof_bucket(nmax));
kono
parents:
diff changeset
251 b->nmax = nmax;
kono
parents:
diff changeset
252 return b;
kono
parents:
diff changeset
253 }
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 static void free_bucket(__cilkrts_worker *w, bucket **bp)
kono
parents:
diff changeset
256 {
kono
parents:
diff changeset
257 bucket *b = *bp;
kono
parents:
diff changeset
258 if (b) {
kono
parents:
diff changeset
259 __cilkrts_frame_free(w, b, sizeof_bucket(b->nmax));
kono
parents:
diff changeset
260 *bp = 0;
kono
parents:
diff changeset
261 }
kono
parents:
diff changeset
262 }
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 /* round up nmax to fill a memory allocator block completely */
kono
parents:
diff changeset
265 static size_t roundup(size_t nmax)
kono
parents:
diff changeset
266 {
kono
parents:
diff changeset
267 size_t sz = sizeof_bucket(nmax);
kono
parents:
diff changeset
268
kono
parents:
diff changeset
269 /* round up size to a full malloc block */
kono
parents:
diff changeset
270 sz = __cilkrts_frame_malloc_roundup(sz);
kono
parents:
diff changeset
271
kono
parents:
diff changeset
272 /* invert sizeof_bucket() */
kono
parents:
diff changeset
273 nmax = ((sz - sizeof(bucket)) / sizeof(elem));
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 return nmax;
kono
parents:
diff changeset
276 }
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 static bool is_power_of_2(size_t n)
kono
parents:
diff changeset
279 {
kono
parents:
diff changeset
280 return (n & (n - 1)) == 0;
kono
parents:
diff changeset
281 }
kono
parents:
diff changeset
282
kono
parents:
diff changeset
283 void cilkred_map::make_buckets(__cilkrts_worker *w,
kono
parents:
diff changeset
284 size_t new_nbuckets)
kono
parents:
diff changeset
285 {
kono
parents:
diff changeset
286 nbuckets = new_nbuckets;
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 CILK_ASSERT(is_power_of_2(nbuckets));
kono
parents:
diff changeset
289 #if defined __GNUC__ && defined __ICC
kono
parents:
diff changeset
290 /* bug workaround -- suppress calls to _intel_fast_memset */
kono
parents:
diff changeset
291 bucket *volatile*new_buckets = (bucket *volatile*)
kono
parents:
diff changeset
292 #else
kono
parents:
diff changeset
293 bucket **new_buckets = (bucket **)
kono
parents:
diff changeset
294 #endif
kono
parents:
diff changeset
295 __cilkrts_frame_malloc(w, nbuckets * sizeof(*(buckets)));
kono
parents:
diff changeset
296
kono
parents:
diff changeset
297 #if REDPAR_DEBUG >= 1
kono
parents:
diff changeset
298 fprintf(stderr, "W=%d, desc=make_buckets, new_buckets=%p, new_nbuckets=%zd\n",
kono
parents:
diff changeset
299 w->self, new_buckets, new_nbuckets);
kono
parents:
diff changeset
300 #endif
kono
parents:
diff changeset
301
kono
parents:
diff changeset
302 for (size_t i = 0; i < new_nbuckets; ++i)
kono
parents:
diff changeset
303 new_buckets[i] = 0;
kono
parents:
diff changeset
304 #if defined __GNUC__ && defined __ICC
kono
parents:
diff changeset
305 buckets = (bucket **)new_buckets;
kono
parents:
diff changeset
306 #else
kono
parents:
diff changeset
307 buckets = new_buckets;
kono
parents:
diff changeset
308 #endif
kono
parents:
diff changeset
309 nelem = 0;
kono
parents:
diff changeset
310 }
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 static void free_buckets(__cilkrts_worker *w,
kono
parents:
diff changeset
313 bucket **buckets,
kono
parents:
diff changeset
314 size_t nbuckets)
kono
parents:
diff changeset
315 {
kono
parents:
diff changeset
316 size_t i;
kono
parents:
diff changeset
317
kono
parents:
diff changeset
318 #if REDPAR_DEBUG >= 1
kono
parents:
diff changeset
319 verify_current_wkr(w);
kono
parents:
diff changeset
320 fprintf(stderr, "W=%d, desc=free_buckets, buckets=%p, size=%zd\n",
kono
parents:
diff changeset
321 w->self, buckets,
kono
parents:
diff changeset
322 nbuckets * sizeof(*buckets));
kono
parents:
diff changeset
323 #endif
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 for (i = 0; i < nbuckets; ++i)
kono
parents:
diff changeset
326 free_bucket(w, buckets + i);
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 __cilkrts_frame_free(w, buckets, nbuckets * sizeof(*buckets));
kono
parents:
diff changeset
329 }
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 static size_t minsz(size_t nelem)
kono
parents:
diff changeset
332 {
kono
parents:
diff changeset
333 return 1U + nelem + nelem / 8U;
kono
parents:
diff changeset
334 }
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 static size_t nextsz(size_t nelem)
kono
parents:
diff changeset
337 {
kono
parents:
diff changeset
338 return 2 * nelem;
kono
parents:
diff changeset
339 }
kono
parents:
diff changeset
340
kono
parents:
diff changeset
341 bool cilkred_map::need_rehash_p() const
kono
parents:
diff changeset
342 {
kono
parents:
diff changeset
343 return minsz(nelem) > nbuckets;
kono
parents:
diff changeset
344 }
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 static inline size_t hashfun(const cilkred_map *h, void *key)
kono
parents:
diff changeset
347 {
kono
parents:
diff changeset
348 size_t k = (size_t) key;
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 k ^= k >> 21;
kono
parents:
diff changeset
351 k ^= k >> 8;
kono
parents:
diff changeset
352 k ^= k >> 3;
kono
parents:
diff changeset
353
kono
parents:
diff changeset
354 return k & (h->nbuckets - 1);
kono
parents:
diff changeset
355 }
kono
parents:
diff changeset
356
kono
parents:
diff changeset
357 // Given a __cilkrts_hyperobject_base, return the key to that hyperobject in
kono
parents:
diff changeset
358 // the reducer map.
kono
parents:
diff changeset
359 static inline void* get_hyperobject_key(__cilkrts_hyperobject_base *hb)
kono
parents:
diff changeset
360 {
kono
parents:
diff changeset
361 // The current implementation uses the address of the lefmost view as the
kono
parents:
diff changeset
362 // key.
kono
parents:
diff changeset
363 return reinterpret_cast<char*>(hb) + hb->__view_offset;
kono
parents:
diff changeset
364 }
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 // Given a hyperobject key, return a pointer to the leftmost object. In the
kono
parents:
diff changeset
367 // current implementation, the address of the leftmost object IS the key, so
kono
parents:
diff changeset
368 // this function is an effective noop.
kono
parents:
diff changeset
369 static inline void* get_leftmost_view(void *key)
kono
parents:
diff changeset
370 {
kono
parents:
diff changeset
371 return key;
kono
parents:
diff changeset
372 }
kono
parents:
diff changeset
373
kono
parents:
diff changeset
374 /* debugging support: check consistency of a reducer map */
kono
parents:
diff changeset
375 void cilkred_map::check(bool allow_null_view)
kono
parents:
diff changeset
376 {
kono
parents:
diff changeset
377 size_t count = 0;
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 CILK_ASSERT(buckets);
kono
parents:
diff changeset
380 for (size_t i = 0; i < nbuckets; ++i) {
kono
parents:
diff changeset
381 bucket *b = buckets[i];
kono
parents:
diff changeset
382 if (b)
kono
parents:
diff changeset
383 for (elem *el = b->el; el->key; ++el) {
kono
parents:
diff changeset
384 CILK_ASSERT(allow_null_view || el->view);
kono
parents:
diff changeset
385 ++count;
kono
parents:
diff changeset
386 }
kono
parents:
diff changeset
387 }
kono
parents:
diff changeset
388 CILK_ASSERT(nelem == count);
kono
parents:
diff changeset
389 /*global_reducer_map::check();*/
kono
parents:
diff changeset
390 }
kono
parents:
diff changeset
391
kono
parents:
diff changeset
392 /* grow bucket by one element, reallocating bucket if necessary */
kono
parents:
diff changeset
393 elem *cilkred_map::grow(__cilkrts_worker *w,
kono
parents:
diff changeset
394 bucket **bp)
kono
parents:
diff changeset
395 {
kono
parents:
diff changeset
396 size_t i, nmax, nnmax;
kono
parents:
diff changeset
397 bucket *b, *nb;
kono
parents:
diff changeset
398
kono
parents:
diff changeset
399 b = *bp;
kono
parents:
diff changeset
400 if (b) {
kono
parents:
diff changeset
401 nmax = b->nmax;
kono
parents:
diff changeset
402 /* find empty element if any */
kono
parents:
diff changeset
403 for (i = 0; i < nmax; ++i)
kono
parents:
diff changeset
404 if (b->el[i].key == 0)
kono
parents:
diff changeset
405 return &(b->el[i]);
kono
parents:
diff changeset
406 /* do not use the last one even if empty */
kono
parents:
diff changeset
407 } else {
kono
parents:
diff changeset
408 nmax = 0;
kono
parents:
diff changeset
409 }
kono
parents:
diff changeset
410
kono
parents:
diff changeset
411 verify_current_wkr(w);
kono
parents:
diff changeset
412 /* allocate a new bucket */
kono
parents:
diff changeset
413 nnmax = roundup(2 * nmax);
kono
parents:
diff changeset
414 nb = alloc_bucket(w, nnmax);
kono
parents:
diff changeset
415
kono
parents:
diff changeset
416
kono
parents:
diff changeset
417 /* copy old bucket into new */
kono
parents:
diff changeset
418 for (i = 0; i < nmax; ++i)
kono
parents:
diff changeset
419 nb->el[i] = b->el[i];
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 free_bucket(w, bp); *bp = nb;
kono
parents:
diff changeset
422
kono
parents:
diff changeset
423 /* zero out extra elements */
kono
parents:
diff changeset
424 for (; i < nnmax; ++i)
kono
parents:
diff changeset
425 nb->el[i].key = 0;
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 /* zero out the last one */
kono
parents:
diff changeset
428 nb->el[i].key = 0;
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 return &(nb->el[nmax]);
kono
parents:
diff changeset
431 }
kono
parents:
diff changeset
432
kono
parents:
diff changeset
433 elem *cilkred_map::insert_no_rehash(__cilkrts_worker *w,
kono
parents:
diff changeset
434 void *key,
kono
parents:
diff changeset
435 __cilkrts_hyperobject_base *hb,
kono
parents:
diff changeset
436 void *view)
kono
parents:
diff changeset
437 {
kono
parents:
diff changeset
438
kono
parents:
diff changeset
439 #if REDPAR_DEBUG >= 2
kono
parents:
diff changeset
440 fprintf(stderr, "[W=%d, desc=insert_no_rehash, this_map=%p]\n",
kono
parents:
diff changeset
441 w->self, this);
kono
parents:
diff changeset
442 verify_current_wkr(w);
kono
parents:
diff changeset
443 #endif
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 CILK_ASSERT((w == 0 && g == 0) || w->g == g);
kono
parents:
diff changeset
446 CILK_ASSERT(key != 0);
kono
parents:
diff changeset
447 CILK_ASSERT(view != 0);
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 elem *el = grow(w, &(buckets[hashfun(this, key)]));
kono
parents:
diff changeset
450
kono
parents:
diff changeset
451 #if REDPAR_DEBUG >= 3
kono
parents:
diff changeset
452 fprintf(stderr, "[W=%d, this=%p, inserting key=%p, view=%p, el = %p]\n",
kono
parents:
diff changeset
453 w->self, this, key, view, el);
kono
parents:
diff changeset
454 #endif
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 el->key = key;
kono
parents:
diff changeset
457 el->hb = hb;
kono
parents:
diff changeset
458 el->view = view;
kono
parents:
diff changeset
459 ++nelem;
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 return el;
kono
parents:
diff changeset
462 }
kono
parents:
diff changeset
463
kono
parents:
diff changeset
464 void cilkred_map::rehash(__cilkrts_worker *w)
kono
parents:
diff changeset
465 {
kono
parents:
diff changeset
466 #if REDPAR_DEBUG >= 1
kono
parents:
diff changeset
467 fprintf(stderr, "[W=%d, desc=rehash, this_map=%p, g=%p, w->g=%p]\n",
kono
parents:
diff changeset
468 w->self, this, g, w->g);
kono
parents:
diff changeset
469 verify_current_wkr(w);
kono
parents:
diff changeset
470 #endif
kono
parents:
diff changeset
471 CILK_ASSERT((w == 0 && g == 0) || w->g == g);
kono
parents:
diff changeset
472
kono
parents:
diff changeset
473 size_t onbuckets = nbuckets;
kono
parents:
diff changeset
474 size_t onelem = nelem;
kono
parents:
diff changeset
475 bucket **obuckets = buckets;
kono
parents:
diff changeset
476 size_t i;
kono
parents:
diff changeset
477 bucket *b;
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 make_buckets(w, nextsz(nbuckets));
kono
parents:
diff changeset
480
kono
parents:
diff changeset
481 for (i = 0; i < onbuckets; ++i) {
kono
parents:
diff changeset
482 b = obuckets[i];
kono
parents:
diff changeset
483 if (b) {
kono
parents:
diff changeset
484 elem *oel;
kono
parents:
diff changeset
485 for (oel = b->el; oel->key; ++oel)
kono
parents:
diff changeset
486 insert_no_rehash(w, oel->key, oel->hb, oel->view);
kono
parents:
diff changeset
487 }
kono
parents:
diff changeset
488 }
kono
parents:
diff changeset
489
kono
parents:
diff changeset
490 CILK_ASSERT(nelem == onelem);
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 free_buckets(w, obuckets, onbuckets);
kono
parents:
diff changeset
493 }
kono
parents:
diff changeset
494
kono
parents:
diff changeset
495 elem *cilkred_map::rehash_and_insert(__cilkrts_worker *w,
kono
parents:
diff changeset
496 void *key,
kono
parents:
diff changeset
497 __cilkrts_hyperobject_base *hb,
kono
parents:
diff changeset
498 void *view)
kono
parents:
diff changeset
499 {
kono
parents:
diff changeset
500
kono
parents:
diff changeset
501 #if REDPAR_DEBUG >= 1
kono
parents:
diff changeset
502 fprintf(stderr, "W=%d, this_map =%p, inserting key=%p, view=%p\n",
kono
parents:
diff changeset
503 w->self, this, key, view);
kono
parents:
diff changeset
504 verify_current_wkr(w);
kono
parents:
diff changeset
505 #endif
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 if (need_rehash_p())
kono
parents:
diff changeset
508 rehash(w);
kono
parents:
diff changeset
509
kono
parents:
diff changeset
510 return insert_no_rehash(w, key, hb, view);
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 elem *cilkred_map::lookup(void *key)
kono
parents:
diff changeset
515 {
kono
parents:
diff changeset
516 bucket *b = buckets[hashfun(this, key)];
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 if (b) {
kono
parents:
diff changeset
519 elem *el;
kono
parents:
diff changeset
520 for (el = b->el; el->key; ++el) {
kono
parents:
diff changeset
521 if (el->key == key) {
kono
parents:
diff changeset
522 CILK_ASSERT(el->view);
kono
parents:
diff changeset
523 return el;
kono
parents:
diff changeset
524 }
kono
parents:
diff changeset
525 }
kono
parents:
diff changeset
526 }
kono
parents:
diff changeset
527
kono
parents:
diff changeset
528 return 0;
kono
parents:
diff changeset
529 }
kono
parents:
diff changeset
530
kono
parents:
diff changeset
531 void elem::destroy()
kono
parents:
diff changeset
532 {
kono
parents:
diff changeset
533 if (! is_leftmost()) {
kono
parents:
diff changeset
534
kono
parents:
diff changeset
535 // Call destroy_fn and deallocate_fn on the view, but not if it's the
kono
parents:
diff changeset
536 // leftmost view.
kono
parents:
diff changeset
537 cilk_c_monoid *monoid = &(hb->__c_monoid);
kono
parents:
diff changeset
538 cilk_c_reducer_destroy_fn_t destroy_fn = monoid->destroy_fn;
kono
parents:
diff changeset
539 cilk_c_reducer_deallocate_fn_t deallocate_fn = monoid->deallocate_fn;
kono
parents:
diff changeset
540
kono
parents:
diff changeset
541 destroy_fn((void*)hb, view);
kono
parents:
diff changeset
542 deallocate_fn((void*)hb, view);
kono
parents:
diff changeset
543 }
kono
parents:
diff changeset
544
kono
parents:
diff changeset
545 view = 0;
kono
parents:
diff changeset
546 }
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 inline
kono
parents:
diff changeset
549 bool elem::is_leftmost() const
kono
parents:
diff changeset
550 {
kono
parents:
diff changeset
551 // implementation uses the address of the leftmost view as the key, so if
kono
parents:
diff changeset
552 // key == view, then this element refers to the leftmost view.
kono
parents:
diff changeset
553 return key == view;
kono
parents:
diff changeset
554 }
kono
parents:
diff changeset
555
kono
parents:
diff changeset
556 /* remove the reducer from the current reducer map. If the reducer
kono
parents:
diff changeset
557 exists in maps other than the current one, the behavior is
kono
parents:
diff changeset
558 undefined. */
kono
parents:
diff changeset
559 extern "C"
kono
parents:
diff changeset
560 CILK_EXPORT void __CILKRTS_STRAND_STALE(
kono
parents:
diff changeset
561 __cilkrts_hyper_destroy(__cilkrts_hyperobject_base *hb))
kono
parents:
diff changeset
562 {
kono
parents:
diff changeset
563 // Disable Cilkscreen for the duration of this call. The destructor for
kono
parents:
diff changeset
564 // this class will re-enable Cilkscreen when the method returns. This
kono
parents:
diff changeset
565 // will prevent Cilkscreen from reporting apparent races in reducers
kono
parents:
diff changeset
566 DisableCilkscreen x;
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 __cilkrts_worker* w = __cilkrts_get_tls_worker();
kono
parents:
diff changeset
569 if (! w) {
kono
parents:
diff changeset
570 // If no worker, then Cilk is not running and there is no reducer
kono
parents:
diff changeset
571 // map. Do nothing. The reducer's destructor will take care of
kono
parents:
diff changeset
572 // destroying the leftmost view.
kono
parents:
diff changeset
573 return;
kono
parents:
diff changeset
574 }
kono
parents:
diff changeset
575
kono
parents:
diff changeset
576 const char *UNSYNCED_REDUCER_MSG =
kono
parents:
diff changeset
577 "Destroying a reducer while it is visible to unsynced child tasks, or\n"
kono
parents:
diff changeset
578 "calling CILK_C_UNREGISTER_REDUCER() on an unregistered reducer.\n"
kono
parents:
diff changeset
579 "Did you forget a _Cilk_sync or CILK_C_REGISTER_REDUCER()?";
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 cilkred_map* h = w->reducer_map;
kono
parents:
diff changeset
582 if (NULL == h)
kono
parents:
diff changeset
583 cilkos_error(UNSYNCED_REDUCER_MSG); // Does not return
kono
parents:
diff changeset
584
kono
parents:
diff changeset
585 if (h->merging) {
kono
parents:
diff changeset
586 verify_current_wkr(w);
kono
parents:
diff changeset
587 __cilkrts_bug("User error: hyperobject used by another hyperobject");
kono
parents:
diff changeset
588 }
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 void* key = get_hyperobject_key(hb);
kono
parents:
diff changeset
591 elem *el = h->lookup(key);
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 // Verify that the reducer is being destroyed from the leftmost strand for
kono
parents:
diff changeset
594 // which the reducer is defined.
kono
parents:
diff changeset
595 if (! (el && el->is_leftmost()))
kono
parents:
diff changeset
596 cilkos_error(UNSYNCED_REDUCER_MSG);
kono
parents:
diff changeset
597
kono
parents:
diff changeset
598 #if REDPAR_DEBUG >= 3
kono
parents:
diff changeset
599 fprintf(stderr, "[W=%d, key=%p, lookup in map %p, found el=%p, about to destroy]\n",
kono
parents:
diff changeset
600 w->self, key, h, el);
kono
parents:
diff changeset
601 #endif
kono
parents:
diff changeset
602
kono
parents:
diff changeset
603 // Remove the element from the hash bucket. Do not bother shrinking
kono
parents:
diff changeset
604 // the bucket. Note that the destroy() function does not actually
kono
parents:
diff changeset
605 // call the destructor for the leftmost view.
kono
parents:
diff changeset
606 el->destroy();
kono
parents:
diff changeset
607 do {
kono
parents:
diff changeset
608 el[0] = el[1];
kono
parents:
diff changeset
609 ++el;
kono
parents:
diff changeset
610 } while (el->key);
kono
parents:
diff changeset
611 --h->nelem;
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 #if REDPAR_DEBUG >= 2
kono
parents:
diff changeset
614 fprintf(stderr, "[W=%d, desc=hyper_destroy_finish, key=%p, w->reducer_map=%p]\n",
kono
parents:
diff changeset
615 w->self, key, w->reducer_map);
kono
parents:
diff changeset
616 #endif
kono
parents:
diff changeset
617 }
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 extern "C"
kono
parents:
diff changeset
620 CILK_EXPORT
kono
parents:
diff changeset
621 void __cilkrts_hyper_create(__cilkrts_hyperobject_base *hb)
kono
parents:
diff changeset
622 {
kono
parents:
diff changeset
623 // This function registers the specified hyperobject in the current
kono
parents:
diff changeset
624 // reducer map and registers the initial value of the hyperobject as the
kono
parents:
diff changeset
625 // leftmost view of the reducer.
kono
parents:
diff changeset
626 __cilkrts_worker *w = __cilkrts_get_tls_worker();
kono
parents:
diff changeset
627 if (! w) {
kono
parents:
diff changeset
628 // If there is no worker, then there is nothing to do: The iniitial
kono
parents:
diff changeset
629 // value will automatically be used as the left-most view when we
kono
parents:
diff changeset
630 // enter Cilk.
kono
parents:
diff changeset
631 return;
kono
parents:
diff changeset
632 }
kono
parents:
diff changeset
633
kono
parents:
diff changeset
634 // Disable Cilkscreen for the duration of this call. The destructor for
kono
parents:
diff changeset
635 // this class will re-enable Cilkscreen when the method returns. This
kono
parents:
diff changeset
636 // will prevent Cilkscreen from reporting apparent races in reducers
kono
parents:
diff changeset
637 DisableCilkscreen x;
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 void* key = get_hyperobject_key(hb);
kono
parents:
diff changeset
640 void* view = get_leftmost_view(key);
kono
parents:
diff changeset
641 cilkred_map *h = w->reducer_map;
kono
parents:
diff changeset
642
kono
parents:
diff changeset
643 if (__builtin_expect(!h, 0)) {
kono
parents:
diff changeset
644 h = install_new_reducer_map(w);
kono
parents:
diff changeset
645 #if REDPAR_DEBUG >= 2
kono
parents:
diff changeset
646 fprintf(stderr, "[W=%d, hb=%p, hyper_create, isntalled new map %p, view=%p]\n",
kono
parents:
diff changeset
647 w->self, hb, h, view);
kono
parents:
diff changeset
648 #endif
kono
parents:
diff changeset
649 }
kono
parents:
diff changeset
650
kono
parents:
diff changeset
651 /* Must not exist. */
kono
parents:
diff changeset
652 CILK_ASSERT(h->lookup(key) == NULL);
kono
parents:
diff changeset
653
kono
parents:
diff changeset
654 #if REDPAR_DEBUG >= 3
kono
parents:
diff changeset
655 verify_current_wkr(w);
kono
parents:
diff changeset
656 fprintf(stderr, "[W=%d, hb=%p, lookup in map %p of view %p, should be null]\n",
kono
parents:
diff changeset
657 w->self, hb, h, view);
kono
parents:
diff changeset
658 fprintf(stderr, "W=%d, h=%p, inserting key %p, view%p\n",
kono
parents:
diff changeset
659 w->self,
kono
parents:
diff changeset
660 h,
kono
parents:
diff changeset
661 &(hb->__c_monoid),
kono
parents:
diff changeset
662 view);
kono
parents:
diff changeset
663 #endif
kono
parents:
diff changeset
664
kono
parents:
diff changeset
665 if (h->merging)
kono
parents:
diff changeset
666 __cilkrts_bug("User error: hyperobject used by another hyperobject");
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 CILK_ASSERT(w->reducer_map == h);
kono
parents:
diff changeset
669 // The address of the leftmost value is the same as the key for lookup.
kono
parents:
diff changeset
670 (void) h->rehash_and_insert(w, view, hb, view);
kono
parents:
diff changeset
671 }
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 extern "C"
kono
parents:
diff changeset
674 CILK_EXPORT void* __CILKRTS_STRAND_PURE(
kono
parents:
diff changeset
675 __cilkrts_hyper_lookup(__cilkrts_hyperobject_base *hb))
kono
parents:
diff changeset
676 {
kono
parents:
diff changeset
677 __cilkrts_worker* w = __cilkrts_get_tls_worker_fast();
kono
parents:
diff changeset
678 void* key = get_hyperobject_key(hb);
kono
parents:
diff changeset
679 if (! w)
kono
parents:
diff changeset
680 return get_leftmost_view(key);
kono
parents:
diff changeset
681
kono
parents:
diff changeset
682 // Disable Cilkscreen for the duration of this call. This will
kono
parents:
diff changeset
683 // prevent Cilkscreen from reporting apparent races in reducers
kono
parents:
diff changeset
684 DisableCilkscreen dguard;
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 if (__builtin_expect(w->g->force_reduce, 0))
kono
parents:
diff changeset
687 __cilkrts_promote_own_deque(w);
kono
parents:
diff changeset
688 cilkred_map* h = w->reducer_map;
kono
parents:
diff changeset
689
kono
parents:
diff changeset
690 if (__builtin_expect(!h, 0)) {
kono
parents:
diff changeset
691 h = install_new_reducer_map(w);
kono
parents:
diff changeset
692 }
kono
parents:
diff changeset
693
kono
parents:
diff changeset
694 if (h->merging)
kono
parents:
diff changeset
695 __cilkrts_bug("User error: hyperobject used by another hyperobject");
kono
parents:
diff changeset
696 elem* el = h->lookup(key);
kono
parents:
diff changeset
697 if (! el) {
kono
parents:
diff changeset
698 /* lookup failed; insert a new default element */
kono
parents:
diff changeset
699 void *rep;
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 {
kono
parents:
diff changeset
702 /* re-enable cilkscreen while calling the constructor */
kono
parents:
diff changeset
703 EnableCilkscreen eguard;
kono
parents:
diff changeset
704 if (h->is_leftmost)
kono
parents:
diff changeset
705 {
kono
parents:
diff changeset
706 // This special case is called only if the reducer was not
kono
parents:
diff changeset
707 // registered using __cilkrts_hyper_create, e.g., if this is a
kono
parents:
diff changeset
708 // C reducer in global scope or if there is no bound worker.
kono
parents:
diff changeset
709 rep = get_leftmost_view(key);
kono
parents:
diff changeset
710 }
kono
parents:
diff changeset
711 else
kono
parents:
diff changeset
712 {
kono
parents:
diff changeset
713 rep = hb->__c_monoid.allocate_fn((void*)hb,
kono
parents:
diff changeset
714 hb->__view_size);
kono
parents:
diff changeset
715 // TBD: Handle exception on identity function
kono
parents:
diff changeset
716 hb->__c_monoid.identity_fn((void*)hb, rep);
kono
parents:
diff changeset
717 }
kono
parents:
diff changeset
718 }
kono
parents:
diff changeset
719
kono
parents:
diff changeset
720 #if REDPAR_DEBUG >= 3
kono
parents:
diff changeset
721 fprintf(stderr, "W=%d, h=%p, inserting key %p, view%p\n",
kono
parents:
diff changeset
722 w->self,
kono
parents:
diff changeset
723 h,
kono
parents:
diff changeset
724 &(hb->__c_monoid),
kono
parents:
diff changeset
725 rep);
kono
parents:
diff changeset
726 CILK_ASSERT(w->reducer_map == h);
kono
parents:
diff changeset
727 #endif
kono
parents:
diff changeset
728 el = h->rehash_and_insert(w, key, hb, rep);
kono
parents:
diff changeset
729 }
kono
parents:
diff changeset
730
kono
parents:
diff changeset
731 return el->view;
kono
parents:
diff changeset
732 }
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 extern "C" CILK_EXPORT
kono
parents:
diff changeset
735 void* __cilkrts_hyperobject_alloc(void* ignore, std::size_t bytes)
kono
parents:
diff changeset
736 {
kono
parents:
diff changeset
737 return std::malloc(bytes);
kono
parents:
diff changeset
738 }
kono
parents:
diff changeset
739
kono
parents:
diff changeset
740 extern "C" CILK_EXPORT
kono
parents:
diff changeset
741 void __cilkrts_hyperobject_dealloc(void* ignore, void* view)
kono
parents:
diff changeset
742 {
kono
parents:
diff changeset
743 std::free(view);
kono
parents:
diff changeset
744 }
kono
parents:
diff changeset
745
kono
parents:
diff changeset
746 /* No-op destroy function */
kono
parents:
diff changeset
747 extern "C" CILK_EXPORT
kono
parents:
diff changeset
748 void __cilkrts_hyperobject_noop_destroy(void* ignore, void* ignore2)
kono
parents:
diff changeset
749 {
kono
parents:
diff changeset
750 }
kono
parents:
diff changeset
751
kono
parents:
diff changeset
752 cilkred_map *__cilkrts_make_reducer_map(__cilkrts_worker *w)
kono
parents:
diff changeset
753 {
kono
parents:
diff changeset
754 CILK_ASSERT(w);
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756 cilkred_map *h;
kono
parents:
diff changeset
757 size_t nbuckets = 1; /* default value */
kono
parents:
diff changeset
758
kono
parents:
diff changeset
759 h = (cilkred_map *)__cilkrts_frame_malloc(w, sizeof(*h));
kono
parents:
diff changeset
760 #if REDPAR_DEBUG >= 1
kono
parents:
diff changeset
761 fprintf(stderr, "[W=%d, desc=make_reducer_frame_malloc_reducer_map, h=%p]\n",
kono
parents:
diff changeset
762 w->self, h);
kono
parents:
diff changeset
763 #endif
kono
parents:
diff changeset
764
kono
parents:
diff changeset
765 h->g = w ? w->g : 0;
kono
parents:
diff changeset
766 h->make_buckets(w, nbuckets);
kono
parents:
diff changeset
767 h->merging = false;
kono
parents:
diff changeset
768 h->is_leftmost = false;
kono
parents:
diff changeset
769
kono
parents:
diff changeset
770 return h;
kono
parents:
diff changeset
771 }
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 /* Destroy a reducer map. The map must have been allocated
kono
parents:
diff changeset
774 from the worker's global context and should have been
kono
parents:
diff changeset
775 allocated from the same worker. */
kono
parents:
diff changeset
776 void __cilkrts_destroy_reducer_map(__cilkrts_worker *w, cilkred_map *h)
kono
parents:
diff changeset
777 {
kono
parents:
diff changeset
778 CILK_ASSERT((w == 0 && h->g == 0) || w->g == h->g);
kono
parents:
diff changeset
779 verify_current_wkr(w);
kono
parents:
diff changeset
780
kono
parents:
diff changeset
781 /* the reducer map is allowed to contain el->view == NULL here (and
kono
parents:
diff changeset
782 only here). We set el->view == NULL only when we know that the
kono
parents:
diff changeset
783 map will be destroyed immediately afterwards. */
kono
parents:
diff changeset
784 DBG h->check(/*allow_null_view=*/true);
kono
parents:
diff changeset
785
kono
parents:
diff changeset
786 bucket *b;
kono
parents:
diff changeset
787 size_t i;
kono
parents:
diff changeset
788
kono
parents:
diff changeset
789 for (i = 0; i < h->nbuckets; ++i) {
kono
parents:
diff changeset
790 b = h->buckets[i];
kono
parents:
diff changeset
791 if (b) {
kono
parents:
diff changeset
792 elem *el;
kono
parents:
diff changeset
793 for (el = b->el; el->key; ++el) {
kono
parents:
diff changeset
794 if (el->view)
kono
parents:
diff changeset
795 el->destroy();
kono
parents:
diff changeset
796 }
kono
parents:
diff changeset
797 }
kono
parents:
diff changeset
798 }
kono
parents:
diff changeset
799
kono
parents:
diff changeset
800 free_buckets(w, h->buckets, h->nbuckets);
kono
parents:
diff changeset
801
kono
parents:
diff changeset
802 #if REDPAR_DEBUG >= 1
kono
parents:
diff changeset
803 fprintf(stderr, "W=%d, destroy_red_map, freeing map h=%p, size=%zd\n",
kono
parents:
diff changeset
804 w->self, h, sizeof(*h));
kono
parents:
diff changeset
805 #endif
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 __cilkrts_frame_free(w, h, sizeof(*h));
kono
parents:
diff changeset
808 }
kono
parents:
diff changeset
809
kono
parents:
diff changeset
810 /* Set the specified reducer map as the leftmost map if is_leftmost is true,
kono
parents:
diff changeset
811 otherwise, set it to not be the leftmost map. */
kono
parents:
diff changeset
812 void __cilkrts_set_leftmost_reducer_map(cilkred_map *h, int is_leftmost)
kono
parents:
diff changeset
813 {
kono
parents:
diff changeset
814 h->is_leftmost = is_leftmost;
kono
parents:
diff changeset
815 }
kono
parents:
diff changeset
816
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 __cilkrts_worker* cilkred_map::merge(__cilkrts_worker *w,
kono
parents:
diff changeset
819 cilkred_map *other_map,
kono
parents:
diff changeset
820 enum merge_kind kind)
kono
parents:
diff changeset
821 {
kono
parents:
diff changeset
822 // Disable Cilkscreen while the we merge the maps. The destructor for
kono
parents:
diff changeset
823 // the guard class will re-enable Cilkscreen when it goes out of scope.
kono
parents:
diff changeset
824 // This will prevent Cilkscreen from reporting apparent races in between
kono
parents:
diff changeset
825 // the reduce function and the reducer operations. The Cilk runtime
kono
parents:
diff changeset
826 // guarantees that a pair of reducer maps will only be merged when no
kono
parents:
diff changeset
827 // other strand will access them.
kono
parents:
diff changeset
828 DisableCilkscreen guard;
kono
parents:
diff changeset
829
kono
parents:
diff changeset
830 #if REDPAR_DEBUG >= 2
kono
parents:
diff changeset
831 fprintf(stderr, "[W=%d, desc=merge, this_map=%p, other_map=%p]\n",
kono
parents:
diff changeset
832 w->self,
kono
parents:
diff changeset
833 this, other_map);
kono
parents:
diff changeset
834 #endif
kono
parents:
diff changeset
835 // Remember the current stack frame.
kono
parents:
diff changeset
836 __cilkrts_stack_frame *current_sf = w->current_stack_frame;
kono
parents:
diff changeset
837 merging = true;
kono
parents:
diff changeset
838 other_map->merging = true;
kono
parents:
diff changeset
839
kono
parents:
diff changeset
840 // Merging to the leftmost view is a special case because every leftmost
kono
parents:
diff changeset
841 // element must be initialized before the merge.
kono
parents:
diff changeset
842 CILK_ASSERT(!other_map->is_leftmost /* || kind == MERGE_UNORDERED */);
kono
parents:
diff changeset
843 bool merge_to_leftmost = (this->is_leftmost
kono
parents:
diff changeset
844 /* && !other_map->is_leftmost */);
kono
parents:
diff changeset
845
kono
parents:
diff changeset
846 DBG check(/*allow_null_view=*/false);
kono
parents:
diff changeset
847 DBG other_map->check(/*allow_null_view=*/false);
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 for (size_t i = 0; i < other_map->nbuckets; ++i) {
kono
parents:
diff changeset
850 bucket *b = other_map->buckets[i];
kono
parents:
diff changeset
851 if (b) {
kono
parents:
diff changeset
852 for (elem *other_el = b->el; other_el->key; ++other_el) {
kono
parents:
diff changeset
853 /* Steal the value from the other map, which will be
kono
parents:
diff changeset
854 destroyed at the end of this operation. */
kono
parents:
diff changeset
855 void *other_view = other_el->view;
kono
parents:
diff changeset
856 CILK_ASSERT(other_view);
kono
parents:
diff changeset
857
kono
parents:
diff changeset
858 void *key = other_el->key;
kono
parents:
diff changeset
859 __cilkrts_hyperobject_base *hb = other_el->hb;
kono
parents:
diff changeset
860 elem *this_el = lookup(key);
kono
parents:
diff changeset
861
kono
parents:
diff changeset
862 if (this_el == 0 && merge_to_leftmost) {
kono
parents:
diff changeset
863 /* Initialize leftmost view before merging. */
kono
parents:
diff changeset
864 void* leftmost = get_leftmost_view(key);
kono
parents:
diff changeset
865 // leftmost == other_view can be true if the initial view
kono
parents:
diff changeset
866 // was created in other than the leftmost strand of the
kono
parents:
diff changeset
867 // spawn tree, but then made visible to subsequent strands
kono
parents:
diff changeset
868 // (E.g., the reducer was allocated on the heap and the
kono
parents:
diff changeset
869 // pointer was returned to the caller.) In such cases,
kono
parents:
diff changeset
870 // parallel semantics says that syncing with earlier
kono
parents:
diff changeset
871 // strands will always result in 'this_el' being null,
kono
parents:
diff changeset
872 // thus propagating the initial view up the spawn tree
kono
parents:
diff changeset
873 // until it reaches the leftmost strand. When synching
kono
parents:
diff changeset
874 // with the leftmost strand, leftmost == other_view will be
kono
parents:
diff changeset
875 // true and we must avoid reducing the initial view with
kono
parents:
diff changeset
876 // itself.
kono
parents:
diff changeset
877 if (leftmost != other_view)
kono
parents:
diff changeset
878 this_el = rehash_and_insert(w, key, hb, leftmost);
kono
parents:
diff changeset
879 }
kono
parents:
diff changeset
880
kono
parents:
diff changeset
881 if (this_el == 0) {
kono
parents:
diff changeset
882 /* move object from other map into this one */
kono
parents:
diff changeset
883 rehash_and_insert(w, key, hb, other_view);
kono
parents:
diff changeset
884 other_el->view = 0;
kono
parents:
diff changeset
885 continue; /* No element-level merge necessary */
kono
parents:
diff changeset
886 }
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 /* The same key is present in both maps with values
kono
parents:
diff changeset
889 A and B. Three choices: fail, A OP B, B OP A. */
kono
parents:
diff changeset
890 switch (kind)
kono
parents:
diff changeset
891 {
kono
parents:
diff changeset
892 case MERGE_UNORDERED:
kono
parents:
diff changeset
893 __cilkrts_bug("TLS Reducer race");
kono
parents:
diff changeset
894 break;
kono
parents:
diff changeset
895 case MERGE_INTO_RIGHT:
kono
parents:
diff changeset
896 /* Swap elements in order to preserve object
kono
parents:
diff changeset
897 identity */
kono
parents:
diff changeset
898 other_el->view = this_el->view;
kono
parents:
diff changeset
899 this_el->view = other_view;
kono
parents:
diff changeset
900 /* FALL THROUGH */
kono
parents:
diff changeset
901 case MERGE_INTO_LEFT: {
kono
parents:
diff changeset
902 /* Stealing should be disabled during reduce
kono
parents:
diff changeset
903 (even if force-reduce is enabled). */
kono
parents:
diff changeset
904
kono
parents:
diff changeset
905 #if DISABLE_PARALLEL_REDUCERS
kono
parents:
diff changeset
906 __cilkrts_stack_frame * volatile *saved_protected_tail;
kono
parents:
diff changeset
907 saved_protected_tail = __cilkrts_disallow_stealing(w, NULL);
kono
parents:
diff changeset
908 #endif
kono
parents:
diff changeset
909
kono
parents:
diff changeset
910 {
kono
parents:
diff changeset
911 CILK_ASSERT(current_sf->worker == w);
kono
parents:
diff changeset
912 CILK_ASSERT(w->current_stack_frame == current_sf);
kono
parents:
diff changeset
913
kono
parents:
diff changeset
914 /* TBD: if reduce throws an exception we need to stop it
kono
parents:
diff changeset
915 here. */
kono
parents:
diff changeset
916 hb->__c_monoid.reduce_fn((void*)hb,
kono
parents:
diff changeset
917 this_el->view,
kono
parents:
diff changeset
918 other_el->view);
kono
parents:
diff changeset
919 w = current_sf->worker;
kono
parents:
diff changeset
920
kono
parents:
diff changeset
921 #if REDPAR_DEBUG >= 2
kono
parents:
diff changeset
922 verify_current_wkr(w);
kono
parents:
diff changeset
923 CILK_ASSERT(w->current_stack_frame == current_sf);
kono
parents:
diff changeset
924 #endif
kono
parents:
diff changeset
925 }
kono
parents:
diff changeset
926
kono
parents:
diff changeset
927 #if DISABLE_PARALLEL_REDUCERS
kono
parents:
diff changeset
928 /* Restore stealing */
kono
parents:
diff changeset
929 __cilkrts_restore_stealing(w, saved_protected_tail);
kono
parents:
diff changeset
930 #endif
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 } break;
kono
parents:
diff changeset
933 }
kono
parents:
diff changeset
934 }
kono
parents:
diff changeset
935 }
kono
parents:
diff changeset
936 }
kono
parents:
diff changeset
937 this->is_leftmost = this->is_leftmost || other_map->is_leftmost;
kono
parents:
diff changeset
938 merging = false;
kono
parents:
diff changeset
939 other_map->merging = false;
kono
parents:
diff changeset
940 verify_current_wkr(w);
kono
parents:
diff changeset
941 __cilkrts_destroy_reducer_map(w, other_map);
kono
parents:
diff changeset
942 return w;
kono
parents:
diff changeset
943 }
kono
parents:
diff changeset
944
kono
parents:
diff changeset
945
kono
parents:
diff changeset
946 /**
kono
parents:
diff changeset
947 * Print routine for debugging the merging of reducer maps.
kono
parents:
diff changeset
948 * A no-op unless REDPAR_DEBUG set high enough.
kono
parents:
diff changeset
949 */
kono
parents:
diff changeset
950 static inline
kono
parents:
diff changeset
951 void debug_map_merge(__cilkrts_worker *w,
kono
parents:
diff changeset
952 cilkred_map *left_map,
kono
parents:
diff changeset
953 cilkred_map *right_map,
kono
parents:
diff changeset
954 __cilkrts_worker **final_wkr)
kono
parents:
diff changeset
955 {
kono
parents:
diff changeset
956 #if REDPAR_DEBUG >= 2
kono
parents:
diff changeset
957 fprintf(stderr, "[W=%d, desc=finish_merge, left_map=%p, right_map=%p, w->reducer_map=%p, right_ans=%p, final_wkr=%d]\n",
kono
parents:
diff changeset
958 w->self, left_map, right_map, w->reducer_map, right_map, (*final_wkr)->self);
kono
parents:
diff changeset
959 #endif
kono
parents:
diff changeset
960 }
kono
parents:
diff changeset
961
kono
parents:
diff changeset
962
kono
parents:
diff changeset
963 /**
kono
parents:
diff changeset
964 * merge RIGHT into LEFT;
kono
parents:
diff changeset
965 * return whichever map allows for faster merge, and destroy the other one.
kono
parents:
diff changeset
966 *
kono
parents:
diff changeset
967 * *w_ptr should be the currently executing worker.
kono
parents:
diff changeset
968 * *w_ptr may change during execution if the reduction is parallel.
kono
parents:
diff changeset
969 */
kono
parents:
diff changeset
970 cilkred_map*
kono
parents:
diff changeset
971 merge_reducer_maps(__cilkrts_worker **w_ptr,
kono
parents:
diff changeset
972 cilkred_map *left_map,
kono
parents:
diff changeset
973 cilkred_map *right_map)
kono
parents:
diff changeset
974 {
kono
parents:
diff changeset
975 __cilkrts_worker *w = *w_ptr;
kono
parents:
diff changeset
976 if (!left_map) {
kono
parents:
diff changeset
977 debug_map_merge(w, left_map, right_map, w_ptr);
kono
parents:
diff changeset
978 return right_map;
kono
parents:
diff changeset
979 }
kono
parents:
diff changeset
980
kono
parents:
diff changeset
981 if (!right_map) {
kono
parents:
diff changeset
982 debug_map_merge(w, left_map, right_map, w_ptr);
kono
parents:
diff changeset
983 return left_map;
kono
parents:
diff changeset
984 }
kono
parents:
diff changeset
985
kono
parents:
diff changeset
986 /* Special case, if left_map is leftmost, then always merge into it.
kono
parents:
diff changeset
987 For C reducers this forces lazy creation of the leftmost views. */
kono
parents:
diff changeset
988 if (left_map->is_leftmost || left_map->nelem > right_map->nelem) {
kono
parents:
diff changeset
989 *w_ptr = left_map->merge(w, right_map, cilkred_map::MERGE_INTO_LEFT);
kono
parents:
diff changeset
990 debug_map_merge(*w_ptr, left_map, right_map, w_ptr);
kono
parents:
diff changeset
991 return left_map;
kono
parents:
diff changeset
992 } else {
kono
parents:
diff changeset
993 *w_ptr = right_map->merge(w, left_map, cilkred_map::MERGE_INTO_RIGHT);
kono
parents:
diff changeset
994 debug_map_merge(*w_ptr, left_map, right_map, w_ptr);
kono
parents:
diff changeset
995 return right_map;
kono
parents:
diff changeset
996 }
kono
parents:
diff changeset
997 }
kono
parents:
diff changeset
998
kono
parents:
diff changeset
999 /**
kono
parents:
diff changeset
1000 * Merges RIGHT into LEFT, and then repeatedly calls
kono
parents:
diff changeset
1001 * merge_reducer_maps_helper() until (*w_ptr)->reducer_map is NULL.
kono
parents:
diff changeset
1002 *
kono
parents:
diff changeset
1003 * *w_ptr may change as reductions execute.
kono
parents:
diff changeset
1004 */
kono
parents:
diff changeset
1005 cilkred_map*
kono
parents:
diff changeset
1006 repeated_merge_reducer_maps(__cilkrts_worker **w_ptr,
kono
parents:
diff changeset
1007 cilkred_map *left_map,
kono
parents:
diff changeset
1008 cilkred_map *right_map)
kono
parents:
diff changeset
1009 {
kono
parents:
diff changeset
1010 // Note: if right_map == NULL but w->reducer_map != NULL, then
kono
parents:
diff changeset
1011 // this loop will reduce w->reducer_map into left_map.
kono
parents:
diff changeset
1012 do {
kono
parents:
diff changeset
1013 left_map = merge_reducer_maps(w_ptr, left_map, right_map);
kono
parents:
diff changeset
1014 verify_current_wkr(*w_ptr);
kono
parents:
diff changeset
1015
kono
parents:
diff changeset
1016 // Pull any newly created reducer map and loop around again.
kono
parents:
diff changeset
1017 right_map = (*w_ptr)->reducer_map;
kono
parents:
diff changeset
1018 (*w_ptr)->reducer_map = NULL;
kono
parents:
diff changeset
1019 } while (right_map);
kono
parents:
diff changeset
1020 return left_map;
kono
parents:
diff changeset
1021 }
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 /* End reducer_impl.cpp */