]> git.ipfire.org Git - thirdparty/gcc.git/blob - libcilkrts/runtime/record-replay.h
[Patch AArch64] Fixup floating point division with -march=armv8-a+nosimd
[thirdparty/gcc.git] / libcilkrts / runtime / record-replay.h
1 /* record_replay.h -*-C++-*-
2 *
3 *************************************************************************
4 *
5 * Copyright (C) 2012-2016, Intel Corporation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of Intel Corporation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
32 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * *********************************************************************
36 *
37 * PLEASE NOTE: This file is a downstream copy of a file mainitained in
38 * a repository at cilkplus.org. Changes made to this file that are not
39 * submitted through the contribution process detailed at
40 * http://www.cilkplus.org/submit-cilk-contribution will be lost the next
41 * time that a new version is released. Changes only submitted to the
42 * GNU compiler collection or posted to the git repository at
43 * https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
44 * not tracked.
45 *
46 * We welcome your contributions to this open source project. Thank you
47 * for your assistance in helping us improve Cilk Plus.
48 *
49 **************************************************************************/
50
51 /**
52 * @file record-replay.h
53 *
54 * @brief record-replay.h and .cpp encapsulate most of the functionality to
55 * record and play back a Cilk Plus application.
56 *
57 * Recording is directed by the setting of the CILK_RECORD_LOG environment
58 * variable. If it's defined, the value specifies the root we'll use to
59 * generate files for each worker using the following format string:
60 * "%s%d.cilklog", where the integer is the value of w->self.
61 *
62 * Replay is directed by the setting of the CILK_REPLAY_LOG environment
63 * variable, interpreted the same way as CILK_RECORD_LOG. If both
64 * CILK_RECORD_LOG and CILK_REPLAY_LOG are defined, a warning will be given
65 * and the attempt to record a log will be ignored.
66 *
67 * Recording is relatively straightforward. We write all information about a
68 * worker to a per-worker file.
69 *
70 * Each pedigree record consists of the following fields. All fields must be
71 * present in every record to make parsing easy.
72 * - Type - A string identifying the pedigree record. See the PED_TYPE_STR_
73 * macros for the currently defined values.
74 * - Pedigree - A string of pedigree values, with underscores between
75 * adjacent values.
76 * - i1 - Record type-specific value. -1 if not used.
77 * - i2 - Record type-specific value. -1 if not used.
78 *
79 * WORKERS record - only written to the file for worker 0. Note that this is
80 * the first worker in the workers array. Worker 0 is the first system worker,
81 * *NOT* a user worker.
82 * - Type: "Workers"
83 * - Pedigree: Always "0" - ignored
84 * - i1: Number of workers (g->P) when we recorded the log. A mismatch when
85 * we attempt to replay the log will result in aborting the execution.
86 * - i2: Log version number - Specified by PED_VERSION in record-replay.cpp
87 *
88 * STEAL record - written after a successful steal.
89 * - Type: "Steal"
90 * - Pedigree: Pedigree of stolen frame
91 * - i1: Worker the frame was stolen from
92 * - i2: -1
93 *
94 * SYNC record - written after a worker continues from a sync.
95 * - Type: "Sync"
96 * - Pedigree: Pedigree of sync. Note that this is the pedigree *before*
97 * the pedigree in incremented in setup_for_execution_pedigree().
98 * - i1: -1
99 * - i2: -1
100 *
101 * ORPHANED record - saved on a return to a stolen parent.
102 * - Type: "Orphaned"
103 * - Pedigree: Pedigree of the parent frame *before* the pedigree is
104 * incremented by the return
105 * - i1: -1
106 * - i2: -1
107 *
108 * On replay, the data is loaded into a per-worker array, and the data is
109 * consumed in order as needed.
110 */
111
112 #ifndef INCLUDED_RECORD_REPLAY_DOT_H
113 #define INCLUDED_RECORD_REPLAY_DOT_H
114
115 #include "cilk/common.h"
116 #include "global_state.h"
117
118 /**
119 * Define CILK_RECORD_REPLAY to enable record/replay functionality. If
120 * CILK_RECORD_REPLAY is not defined, all of the record/replay functions in
121 * record-replay.h will be stubbed out. Since they're declared as inline,
122 * functions, the resulting build should have no performance impact due to
123 * the implementation or record/replay.
124 */
125 #define CILK_RECORD_REPLAY 1
126
127 /**
128 * Define RECORD_ON_REPLAY=1 to write logs when we're replaying a log. This
129 * should only be needed when debugging the replay functionality. This should
130 * always be defined as 0 when record-replay.h is checked in.
131 */
132 #define RECORD_ON_REPLAY 0
133
134 __CILKRTS_BEGIN_EXTERN_C
135
136 #ifdef CILK_RECORD_REPLAY
137 // Declarations of internal record/replay functions. The inlined versions
138 // further down do some preliminary testing (like if we're not recording or
139 // replaying) and will stub out the functionality if we've compiled out the
140 // record/replay feature
141 int replay_match_sync_pedigree_internal(__cilkrts_worker *w);
142 void replay_wait_for_steal_if_parent_was_stolen_internal(__cilkrts_worker *w);
143 void replay_record_steal_internal(__cilkrts_worker *w, int32_t victim_id);
144 void replay_record_sync_internal(__cilkrts_worker *w);
145 void replay_record_orphaned_internal(__cilkrts_worker *w);
146 int replay_match_victim_pedigree_internal(__cilkrts_worker *w, __cilkrts_worker *victim);
147 void replay_advance_from_sync_internal (__cilkrts_worker *w);
148 int replay_get_next_recorded_victim_internal(__cilkrts_worker *w);
149 #endif // CILK_RECORD_REPLAY
150
151 // Publically defined record/replay API
152
153 /**
154 * If we're replaying a log, wait for our parent to be stolen if it was when
155 * the log was recorded. If record/replay is compiled out, this is a noop.
156 *
157 * @param w The __cilkrts_worker we're executing on. The worker's replay
158 * list will be checked for a ORPHANED record with a matching pedigree. If
159 * there is a match, the ORPHANED record will be consumed.
160 */
161 #ifdef CILK_RECORD_REPLAY
162 __CILKRTS_INLINE
163 void replay_wait_for_steal_if_parent_was_stolen(__cilkrts_worker *w)
164 {
165 // Only check if we're replaying a log
166 if (REPLAY_LOG == w->g->record_or_replay)
167 replay_wait_for_steal_if_parent_was_stolen_internal(w);
168 }
169 #else
170 __CILKRTS_INLINE
171 void replay_wait_for_steal_if_parent_was_stolen(__cilkrts_worker *w)
172 {
173 // If record/replay is disabled, we never wait
174 }
175 #endif // CILK_RECORD_REPLAY
176
177 /**
178 * Called from random_steal() to override the ID of the randomly chosen victim
179 * worker which this worker will attempt to steal from. Returns the worker id
180 * of the next victim this worker was recorded stealing from, or -1 if the
181 * next record in the log is not a STEAL.
182 *
183 * @note This call does NOT attempt to match the pedigree. That will be done
184 * by replay_match_victim_pedigree() after random_steal() has locked the victim
185 * worker.
186 *
187 * @param w The __cilkrts_worker we're executing on. The worker's replay log
188 * is checked for a STEAL record. If we've got one, the stolen worker ID is
189 * returned.
190 * @param id The randomly chosen victim worker ID. If we're not replaying a
191 * log, or if record/replay has been compiled out, this is the value that
192 * will be returned.
193 *
194 * @return id if we're not replaying a log
195 * @return -1 if the next record is not a STEAL
196 * @return recorded stolen worker ID if we've got a matching STEAL record
197 */
198 #ifdef CILK_RECORD_REPLAY
199 __CILKRTS_INLINE
200 int replay_get_next_recorded_victim(__cilkrts_worker *w, int id)
201 {
202 // Only check if we're replaying a log
203 if (REPLAY_LOG == w->g->record_or_replay)
204 return replay_get_next_recorded_victim_internal(w);
205 else
206 return id;
207 }
208 #else
209 __CILKRTS_INLINE
210 int replay_get_next_recorded_victim(__cilkrts_worker *w, int id)
211 {
212 // Record/replay is disabled. Always return the original worker id
213 return id;
214 }
215 #endif // CILK_RECORD_REPLAY
216
217 /**
218 * Initialize per-worker data for record/replay. A noop if record/replay
219 * is disabled, or if we're not recording or replaying anything.
220 *
221 * If we're recording a log, this will ready us to create the per-worker
222 * logs.
223 *
224 * If we're replaying a log, this will read the logs into the per-worker
225 * structures.
226 *
227 * @param g Cilk runtime global state
228 */
229 void replay_init_workers(global_state_t *g);
230
231 /**
232 * Record a record on a successful steal. A noop if record/replay is
233 * diabled, or if we're not recording anything
234 *
235 * @param w The __cilkrts_worker we're executing on. The pedigree of
236 * the stolen frame will be walked to generate the STEAL record.
237 *
238 * @param victim_id The worker ID of the worker w stole from.
239 */
240 #ifdef CILK_RECORD_REPLAY
241 __CILKRTS_INLINE
242 void replay_record_steal(__cilkrts_worker *w, int32_t victim_id)
243 {
244 #if RECORD_ON_REPLAY
245 // If we're recording on replay, write the record if we're recording or
246 // replaying
247 if (RECORD_REPLAY_NONE == w->g->record_or_replay)
248 return;
249 #else
250 // Only write the record if we're recording
251 if (RECORD_LOG != w->g->record_or_replay)
252 return;
253 #endif
254
255 replay_record_steal_internal(w, victim_id);
256 }
257 #else
258 __CILKRTS_INLINE
259 void replay_record_steal(__cilkrts_worker *w, int32_t victim_id)
260 {
261 }
262 #endif // CILK_RECORD_REPLAY
263
264 /**
265 * Record a record when continuing after a sync. A noop if record/replay is
266 * diabled, or if we're not recording anything, or if the sync was abandoned,
267 * meaning this isn't the worker that continues from the sync.
268 *
269 * @param w The __cilkrts_worker for we're executing on. The pedigree of
270 * the sync-ing frame will be walked to generate the SYNC record.
271 *
272 * @param continuing True if this worker will be continuing from the
273 * cilk_sync. A SYNC record will only be generated if continuing is true.
274 */
275 #ifdef CILK_RECORD_REPLAY
276 __CILKRTS_INLINE
277 void replay_record_sync(__cilkrts_worker *w, int continuing)
278 {
279 // If this was not the last worker to the syn, return
280 if (! continuing)
281 return;
282
283 #if RECORD_ON_REPLAY
284 // If we're recording on replay, write the record if we're recording or
285 // replaying
286 if (RECORD_REPLAY_NONE == w->g->record_or_replay)
287 return;
288 #else
289 // Only write the record if we're recording
290 if (RECORD_LOG != w->g->record_or_replay)
291 return;
292 #endif
293
294 replay_record_sync_internal(w);
295 }
296 #else
297 __CILKRTS_INLINE
298 void replay_record_sync(__cilkrts_worker *w, int abandoned)
299 {
300 }
301 #endif // CILK_RECORD_REPLAY
302
303 /**
304 * Record a record on a return to a stolen parent. A noop if record/replay is
305 * diabled, or if we're not recording anything.
306 *
307 * @param w The __cilkrts_worker for we're executing on. The pedigree of the
308 * frame that has discovered that its parent has been stolken will be walked
309 * to generate the ORPHANED record.
310 */
311 #ifdef CILK_RECORD_REPLAY
312 __CILKRTS_INLINE
313 void replay_record_orphaned(__cilkrts_worker *w)
314 {
315 #if RECORD_ON_REPLAY
316 // If we're recording on replay, write the record if we're recording or
317 // replaying
318 if (RECORD_REPLAY_NONE == w->g->record_or_replay)
319 return;
320 #else
321 // Only write the record if we're recording
322 if (RECORD_LOG != w->g->record_or_replay)
323 return;
324 #endif
325
326 replay_record_orphaned_internal(w);
327 }
328 #else
329 __CILKRTS_INLINE
330 void replay_record_orphaned(__cilkrts_worker *w)
331 {
332 }
333 #endif // CILK_RECORD_REPLAY
334
335 /**
336 * Test whether the frame at the head of the victim matches the pedigree of
337 * the frame that was recorded being stolen. Called in random steal to verify
338 * that we're about to steal the correct frame.
339 *
340 * @param w The __cilkrts_worker for we're executing on. The current worker
341 * is needed to find the replay entry to be checked.
342 *
343 * @param victim The __cilkrts_worker for we're proposing to steal a frame
344 * from. The victim's head entry is
345 * is needed to find the replay entry to be checked.
346 *
347 * @return 0 if we're replaying a log and the victim's pedigree does NOT match
348 * the next frame the worker is expected to steal.
349 *
350 * @return 1 in all other cases to indicate that the steal attempt should
351 * continue
352 */
353 #ifdef CILK_RECORD_REPLAY
354 __CILKRTS_INLINE
355 int replay_match_victim_pedigree(__cilkrts_worker *w, __cilkrts_worker *victim)
356 {
357 // We're not replaying a log. The victim is always acceptable
358 if (REPLAY_LOG != w->g->record_or_replay)
359 return 1;
360
361 // Return 1 if the victim's pedigree matches the frame the worker stole
362 // when we recorded the log
363 return replay_match_victim_pedigree_internal(w, victim);
364 }
365 #else
366 __CILKRTS_INLINE
367 int replay_match_victim_pedigree(__cilkrts_worker *w, __cilkrts_worker *victim)
368 {
369 // Record/replay is disabled. The victim is always acceptable
370 return 1;
371 }
372 #endif // CILK_RECORD_REPLAY
373
374 /**
375 * Test whether the current replay entry is a sync record matching the
376 * worker's pedigree.
377 *
378 * @param w The __cilkrts_worker for we're executing on.
379 *
380 * @return 1 if the current replay entry matches the current pedigree.
381 * @return 0 if there's no match, or if we're not replaying a log.
382 */
383 #ifdef CILK_RECORD_REPLAY
384 __CILKRTS_INLINE
385 int replay_match_sync_pedigree(__cilkrts_worker *w)
386 {
387 // If we're not replaying, assume no match
388 if (REPLAY_LOG != w->g->record_or_replay)
389 return 0;
390
391 return replay_match_sync_pedigree_internal(w);
392 }
393 #else
394 __CILKRTS_INLINE
395 int replay_match_sync_pedigree(__cilkrts_worker *w)
396 {
397 // Record/replay is disabled. Assume no match
398 return 0;
399 }
400 #endif
401
402 /**
403 * Marks a sync record seen, advancing to the next record in the replay list.
404 *
405 * This function will only advance to the next record if:
406 * - Record/replay hasn't been compiled out AND
407 * - We're replaying a log AND
408 * - A match was found AND
409 * - The sync is not being abandoned
410 *
411 * @param w The __cilkrts_worker for we're executing on.
412 * @param match_found The value returned by replay_match_sync_pedigree(). If
413 * match_found is false, nothing is done.
414 * @param continuing Flag indicating whether this worker will continue from
415 * the sync (it's the last worker to the sync) or if it will abandon the work
416 * and go to the scheduling loop to look for more work it can steal.
417 */
418 #ifdef CILK_RECORD_REPLAY
419 __CILKRTS_INLINE
420 void replay_advance_from_sync(__cilkrts_worker *w, int match_found, int continuing)
421 {
422 // If we're replaying a log, and the current sync wasn't abandoned, and we
423 // found a match in the log, mark the sync record seen.
424 if ((REPLAY_LOG == w->g->record_or_replay) && match_found && continuing)
425 replay_advance_from_sync_internal(w);
426 }
427 #else
428 __CILKRTS_INLINE
429 void replay_advance_from_sync(__cilkrts_worker *w, int match_found, int continuing)
430 {
431 }
432 #endif
433
434 /**
435 * Release any resources used to read or write a replay log.
436 *
437 * @param g Cilk runtime global state
438 */
439 void replay_term(global_state_t *g);
440
441 __CILKRTS_END_EXTERN_C
442
443 #endif // ! defined(INCLUDED_RECORD_REPLAY_DOT_H)