1 | #include <time.h>
|
---|
2 | #include <stdio.h>
|
---|
3 | #include <stdlib.h>
|
---|
4 | #include <string.h>
|
---|
5 | #include <stdint.h>
|
---|
6 | #include <assert.h>
|
---|
7 |
|
---|
8 | #ifdef DISABLE_OBSERVATION
|
---|
9 | #include "proglang.h"
|
---|
10 | #define bobs_init(...)
|
---|
11 | #else
|
---|
12 | #include "observation.h"
|
---|
13 | #endif
|
---|
14 |
|
---|
15 | #ifdef HUGE_USER_ITEMS
|
---|
16 | #define UDATA_T float
|
---|
17 | #define UDATA_LEN 17
|
---|
18 | #endif
|
---|
19 |
|
---|
20 | // canonical insertion order means the order of traversing B_UserItem.{succ|pred}_pos references
|
---|
21 | // outer v middle action: as at (just after) inserting or (just before) removing the element in question...
|
---|
22 | // - outer-action node: one that is at the front or back of the list
|
---|
23 | // - middle-action node: otherwise
|
---|
24 | // outer action is
|
---|
25 | // - typical/default: middle action happens only when InterleaveFrac > 0, and only on this fraction
|
---|
26 | // - logically first: a prefix of items, in canonical insertion order, gets outer action; a suffix gets middle action
|
---|
27 | // regardless of interleaving, canonical insertion order is the same as linked-list element order in the final built-up state, up to polarity
|
---|
28 | // nontrivial interleaving makes the time oder of insertion/removal _operation_invocations_ different from canonical
|
---|
29 | typedef enum InterleaveAction { OuterActn = 0, InnerActn = 1 } InterleaveAction;
|
---|
30 | enum { N_INTERLEAVE_ACTION = 2 } ;
|
---|
31 |
|
---|
32 | typedef
|
---|
33 | struct __attribute__(( aligned(64) )) B_UserItem
|
---|
34 | BFX_EXTRUSION_DECL(B_UserItem)
|
---|
35 | {
|
---|
36 | BFX_INTRUSION(B_UserItem)
|
---|
37 | #ifndef DISABLE_SHUFFLING_INDIRECTION
|
---|
38 | size_t succ_pos;
|
---|
39 | size_t pred_pos;
|
---|
40 | #endif
|
---|
41 | size_t self_ord;
|
---|
42 | #ifndef DISABLE_INTERLEAVING
|
---|
43 | InterleaveAction later_flip;
|
---|
44 | #endif
|
---|
45 | #ifndef DISABLE_ITERS
|
---|
46 | BFX_LISTED_ELEM_T(struct B_UserItem) selfListed;
|
---|
47 | #endif
|
---|
48 | #ifdef HUGE_USER_ITEMS
|
---|
49 | UDATA_T udata[UDATA_T] __attribute__((unused));
|
---|
50 | #endif
|
---|
51 | }
|
---|
52 | B_UserItem;
|
---|
53 |
|
---|
54 | BFX_EXTRUSION_FOLLOWUP(B_UserItem)
|
---|
55 |
|
---|
56 | #if defined(NDEBUG) || (defined(__cforall) && !defined(__CFA_DEBUG__))
|
---|
57 | enum { DefaultNumNodes = 1000, DefaultExperimentDurSec = 1, DefaultCheckDonePeriod = 1000, DefaultExperimentDurOpCount = -1, DefaultSeed = 5 };
|
---|
58 | const double DefaultInterleaveFrac = 0.0;
|
---|
59 | #define TRACE(tp)
|
---|
60 | #else
|
---|
61 | enum { DefaultNumNodes = 10, DefaultExperimentDurSec = 1, DefaultCheckDonePeriod = 2, DefaultExperimentDurOpCount = 20, DefaultSeed = 5 };
|
---|
62 | const double DefaultInterleaveFrac = 0.5;
|
---|
63 | static const char * tp_filter
|
---|
64 | // = "";
|
---|
65 | // = "+ea";
|
---|
66 | = "*";
|
---|
67 | #define TRACE(tp) \
|
---|
68 | if (strcmp("*", tp_filter) == 0 || strchr(tp_filter, tp)) { \
|
---|
69 | printf("%c", tp); \
|
---|
70 | bobs_report(); \
|
---|
71 | }
|
---|
72 | #endif
|
---|
73 |
|
---|
74 | static B_UserItem *ui = NULL;
|
---|
75 |
|
---|
76 | static BFX_LISTED_ELEM_T(B_UserItem) observedItem;
|
---|
77 |
|
---|
78 | static BFX_LIST_HEAD_T(B_UserItem) lst;
|
---|
79 |
|
---|
80 | B_UserItem * seekUi( size_t i ) {
|
---|
81 | #ifdef DISABLE_SHUFFLING_INDIRECTION
|
---|
82 | return & ui[i];
|
---|
83 | #else
|
---|
84 | B_UserItem * cur = & ui[0];
|
---|
85 | for (; i > 0; i--) cur = & ui[ cur->succ_pos ];
|
---|
86 | return cur;
|
---|
87 | #endif
|
---|
88 | }
|
---|
89 |
|
---|
90 | #ifdef DISABLE_OBSERVATION
|
---|
91 | MAYBE_EXTERN_C (
|
---|
92 | void bobs_seek(size_t i) {}
|
---|
93 | void bobs_moveNext() {}
|
---|
94 | void bobs_movePrev() {}
|
---|
95 | bool bobs_hasCurrent() { return 0; }
|
---|
96 | void * bobs_getCurrentLoc() { return NULL; }
|
---|
97 | size_t bobs_getCurrentVal() { return 0; }
|
---|
98 | // enum bobs_op_movement_t bobs_op_movement = OP_MOVEMENT;
|
---|
99 | // enum bobs_op_polarity_t bobs_op_polarity = OP_POLARITY;
|
---|
100 | )
|
---|
101 |
|
---|
102 | #else
|
---|
103 |
|
---|
104 | MAYBE_EXTERN_C (
|
---|
105 |
|
---|
106 | volatile size_t bobs_ops_completed = 0;
|
---|
107 | volatile size_t bobs_prog_inserting = 0;
|
---|
108 | volatile size_t bobs_prog_removing = 0;
|
---|
109 | volatile size_t bobs_prog_removing_end = 0;
|
---|
110 | volatile size_t bobs_prog_rollover_flag = 0;
|
---|
111 | // bobs_prog_rem_pos (defined after BOP_REMPROGEND_IS_REMNO_BASED)
|
---|
112 |
|
---|
113 | void bobs_seek(size_t i) {
|
---|
114 | #ifndef DISABLE_ITERS
|
---|
115 | observedItem = seekUi(i)->selfListed;
|
---|
116 | #endif
|
---|
117 | }
|
---|
118 |
|
---|
119 | void bobs_moveNext() {
|
---|
120 | observedItem = BFX_GET_AFTER(B_UserItem, lst, observedItem);
|
---|
121 | }
|
---|
122 |
|
---|
123 | void bobs_movePrev() {
|
---|
124 | observedItem = BFX_GET_BEFORE(B_UserItem, lst, observedItem);
|
---|
125 | }
|
---|
126 |
|
---|
127 | bool bobs_hasCurrent() {
|
---|
128 | return BFX_IS_VALID_POS(B_UserItem, lst, observedItem);
|
---|
129 | }
|
---|
130 |
|
---|
131 | void * bobs_getCurrentLoc() {
|
---|
132 | return BFX_DEREF_POS(B_UserItem, lst, observedItem);
|
---|
133 | }
|
---|
134 | size_t bobs_getCurrentVal() {
|
---|
135 | B_UserItem * curUI = BFX_DEREF_POS(B_UserItem, lst, observedItem);
|
---|
136 | return curUI->self_ord;
|
---|
137 | }
|
---|
138 |
|
---|
139 | enum bobs_op_movement_t bobs_op_movement = OP_MOVEMENT;
|
---|
140 | enum bobs_op_polarity_t bobs_op_polarity = OP_POLARITY;
|
---|
141 | )
|
---|
142 | #endif
|
---|
143 |
|
---|
144 |
|
---|
145 | #ifndef DISABLE_OBSERVATION
|
---|
146 |
|
---|
147 | // Remove progress end (as in, outer) (number) is based (upon) remove-number
|
---|
148 | // True when an OP's REMELEM used remNo to choose which element to remove
|
---|
149 | // False otherwise; notably including when REMELEM just bases upon first/last
|
---|
150 | // Default to false.
|
---|
151 | #ifndef BOP_REMPROGEND_IS_REMNO_BASED
|
---|
152 | #define BOP_REMPROGEND_IS_REMNO_BASED false
|
---|
153 | #endif
|
---|
154 | MAYBE_EXTERN_C (
|
---|
155 | volatile size_t const * bobs_prog_rem_pos =
|
---|
156 | #ifdef DISABLE_INTERLEAVING
|
---|
157 | & bobs_prog_removing
|
---|
158 | #else
|
---|
159 | BOP_REMPROGEND_IS_REMNO_BASED ? & bobs_prog_removing_end : & bobs_prog_removing
|
---|
160 | #endif
|
---|
161 | ;
|
---|
162 | )
|
---|
163 |
|
---|
164 | #endif // ndef DISABLE_OBSERVATION
|
---|
165 |
|
---|
166 | // size_t uDefaultPreemption() {
|
---|
167 | // return 0;
|
---|
168 | // }
|
---|
169 |
|
---|
170 | #ifdef DISABLE_ITERS
|
---|
171 | // Saves on memory accesses, makes element-oriented removals and observation impossible (instead, they crash)
|
---|
172 | static inline BFX_LISTED_ELEM_T(B_UserItem) buhrdice_pass( BFX_LISTED_ELEM_T(B_UserItem) v ) { // prevent eliding, cheaper than volatile
|
---|
173 | __asm__ __volatile__ ( "" : "+r"(v) );
|
---|
174 | return v ;
|
---|
175 | } // pass
|
---|
176 | #define ITERS_SAVE(i, insertElemExpr) buhrdice_pass(insertElemExpr)
|
---|
177 | #endif
|
---|
178 |
|
---|
179 | // begin: copied from https://stackoverflow.com/a/33021408
|
---|
180 | #define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
|
---|
181 | #define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX)
|
---|
182 | static_assert((RAND_MAX & (RAND_MAX + 1u)) == 0, "RAND_MAX not a Mersenne number");
|
---|
183 |
|
---|
184 | uint64_t rand64(void) {
|
---|
185 | uint64_t r = 0;
|
---|
186 | for (int i = 0; i < 64; i += RAND_MAX_WIDTH) {
|
---|
187 | r <<= RAND_MAX_WIDTH;
|
---|
188 | r ^= (unsigned) rand();
|
---|
189 | }
|
---|
190 | return r;
|
---|
191 | }
|
---|
192 | // end: copied from https://stackoverflow.com/a/33021408
|
---|
193 |
|
---|
194 | int main(int argc, const char *argv[]) {
|
---|
195 |
|
---|
196 | #ifdef DISABLE_OBSERVATION
|
---|
197 | // define the outbound dependencies as locals, for compiling into nops
|
---|
198 | size_t bobs_ops_completed = 0;
|
---|
199 | size_t bobs_prog_inserting = 0;
|
---|
200 | size_t bobs_prog_removing = 0;
|
---|
201 | size_t bobs_prog_removing_end = 0;
|
---|
202 | size_t bobs_prog_rollover_flag = 0;
|
---|
203 | #endif
|
---|
204 |
|
---|
205 | const char * usage_args = "[ExperimentDurSec [CheckDonePeriod [NumNodes [ExperimentDurOpCount [Seed [InterleaveFrac]]]]]]";
|
---|
206 | const int static_arg_posns = 6;
|
---|
207 |
|
---|
208 | size_t ExperimentDurSec = DefaultExperimentDurSec;
|
---|
209 | size_t CheckDonePeriod = DefaultCheckDonePeriod;
|
---|
210 | size_t NumNodes = DefaultNumNodes;
|
---|
211 | size_t ExperimentDurOpCount = DefaultExperimentDurOpCount;
|
---|
212 | size_t Seed = DefaultSeed;
|
---|
213 | double InterleaveFrac = DefaultInterleaveFrac;
|
---|
214 |
|
---|
215 | switch (((argc - 1) < static_arg_posns) ? (argc - 1) : static_arg_posns) {
|
---|
216 | case 6: InterleaveFrac = atof(argv[6]);
|
---|
217 | case 5: Seed = atoi(argv[5]);
|
---|
218 | case 4: ExperimentDurOpCount = atol(argv[4]);
|
---|
219 | case 3: NumNodes = atoi(argv[3]);
|
---|
220 | case 2: CheckDonePeriod = atoi(argv[2]);
|
---|
221 | case 1: ExperimentDurSec = atoi(argv[1]);
|
---|
222 | }
|
---|
223 |
|
---|
224 | // printf("ExperimentDurSec=%d, CheckDonePeriod=%d, NumNodes=%d, ExperimentDurOpCount=%zd, Seed=%d,\n",
|
---|
225 | // ExperimentDurSec, CheckDonePeriod, NumNodes, ExperimentDurOpCount, Seed );
|
---|
226 |
|
---|
227 | if (ExperimentDurSec == 0 || CheckDonePeriod == 0 || NumNodes == 0 || ExperimentDurOpCount == 0 || Seed == 0 ) {
|
---|
228 | printf("usage: %s %s\n", argv[0], usage_args);
|
---|
229 | return -1;
|
---|
230 | }
|
---|
231 |
|
---|
232 | #ifdef DISABLE_CLOCK_RECHECK
|
---|
233 | if (ExperimentDurSec != -1) {
|
---|
234 | printf("Error: experiment compiled as fixed-work only. ExperimentDurSec (currently %d) must be set to -1.\nUsage: %s %s\n", ExperimentDurSec, argv[0], usage_args);
|
---|
235 | return -1;
|
---|
236 | }
|
---|
237 | #endif
|
---|
238 |
|
---|
239 | ui = (B_UserItem*) malloc( (size_t)NumNodes * (size_t)sizeof(B_UserItem) );
|
---|
240 | if (!ui) {
|
---|
241 | printf("malloc request for %zd bytes for ui refused\n", (size_t)NumNodes * (size_t)sizeof(B_UserItem));
|
---|
242 | return 1;
|
---|
243 | }
|
---|
244 | memset(ui, 0, (size_t)NumNodes * (size_t)sizeof(B_UserItem));
|
---|
245 | // Construct
|
---|
246 | #ifdef __cforall
|
---|
247 | for (size_t i = 0; i < NumNodes; i++) {
|
---|
248 | B_UserItem * curUI = & ui[i];
|
---|
249 | (*curUI){};
|
---|
250 | }
|
---|
251 | #endif
|
---|
252 |
|
---|
253 | // Shuffling makes listed items' physical order in memory different from their order within to the list.
|
---|
254 | // Affects insertion: next item to insert picked through insertOrdShuf.
|
---|
255 | #ifdef DISABLE_SHUFFLING_INDIRECTION
|
---|
256 | for ( size_t insertOrdinal = 0; insertOrdinal < NumNodes; insertOrdinal += 1 ) {
|
---|
257 | ui[insertOrdinal].self_ord = insertOrdinal;
|
---|
258 | }
|
---|
259 | #else
|
---|
260 | // To ensure random memory order of nodes being inserted, do so according to a shuffled ordering of them.
|
---|
261 | {
|
---|
262 | // insertOrdShuf is a temporary list of integers; once the order is generated, we'll write its consequence into the elements
|
---|
263 | size_t * insertOrdShuf = (size_t *) malloc( sizeof( size_t ) * NumNodes );
|
---|
264 | if (!insertOrdShuf) {
|
---|
265 | printf("malloc request for %zd bytes for insertOrdShuf refused\n", (size_t)NumNodes * (size_t)sizeof(size_t));
|
---|
266 | return 1;
|
---|
267 | }
|
---|
268 | // Fill with the ordinals (iota)
|
---|
269 | for (size_t i = 0; i < NumNodes; i++) {
|
---|
270 | insertOrdShuf[i] = i;
|
---|
271 | }
|
---|
272 | // Dummy "Seed" of -1 means skip the shuffle: measure overhead of shuffling indirection
|
---|
273 | if (Seed != -1) {
|
---|
274 | // Shuffle per https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Sattolo's_algorithm
|
---|
275 | // Don't want to draw from all permutations, only single-cycle permutations
|
---|
276 | srand(Seed);
|
---|
277 | for (size_t i = NumNodes - 1; i > 0; --i) {
|
---|
278 | size_t j = rand64() % i; // j in [0, i-1]
|
---|
279 | size_t tmp = insertOrdShuf[i];
|
---|
280 | insertOrdShuf[i] = insertOrdShuf[j];
|
---|
281 | insertOrdShuf[j] = tmp;
|
---|
282 | }
|
---|
283 | }
|
---|
284 | // take inserOrdShuf as successor-index; write consequences of this traversal into the elements
|
---|
285 | size_t lastPos = 0;
|
---|
286 | size_t curPos = 0;
|
---|
287 | for ( size_t insertOrdinal = 0; insertOrdinal < NumNodes; insertOrdinal += 1 ) {
|
---|
288 | B_UserItem * curItem = & ui[ curPos ];
|
---|
289 | curItem->succ_pos = insertOrdShuf[ curPos ];
|
---|
290 | curItem->pred_pos = lastPos;
|
---|
291 | curItem->self_ord = insertOrdinal;
|
---|
292 | lastPos = curPos;
|
---|
293 | curPos = curItem->succ_pos;
|
---|
294 | }
|
---|
295 | assert( curPos == 0 ); // completed sole cycle
|
---|
296 | ui[0].pred_pos = lastPos;
|
---|
297 | free(insertOrdShuf);
|
---|
298 | }
|
---|
299 | #define INSERTPOS(insertNum) insertOrdShuf[insertNum]
|
---|
300 | #endif
|
---|
301 |
|
---|
302 |
|
---|
303 | /*
|
---|
304 |
|
---|
305 |
|
---|
306 |
|
---|
307 |
|
---|
308 |
|
---|
309 | TO FIX
|
---|
310 |
|
---|
311 |
|
---|
312 |
|
---|
313 |
|
---|
314 |
|
---|
315 | clarify self_ord meaning insertion order or physical-adjacency order
|
---|
316 |
|
---|
317 |
|
---|
318 |
|
---|
319 |
|
---|
320 |
|
---|
321 |
|
---|
322 |
|
---|
323 |
|
---|
324 |
|
---|
325 | */
|
---|
326 |
|
---|
327 |
|
---|
328 | // Interleaving affects the list position where an element-oriented operation occurs: at an outer vs. inner node.
|
---|
329 | // Perterbs the sequence of logical insert/remove numbers presented to the OP cartridge, e.g. from [0 1 2 3 4 5 6]
|
---|
330 | // to [3 0 4 1 5 2 6], which is [inner outer inner outer inner outer solo], for a perfect-alternation interleave; except that the
|
---|
331 | // outer/inner interleave is atually selected randomly.
|
---|
332 | #ifndef DISABLE_INTERLEAVING
|
---|
333 | // see InterleaveAction comments near top
|
---|
334 |
|
---|
335 | size_t numNodesItlv[N_INTERLEAVE_ACTION] = {}; // logically const, complex init
|
---|
336 |
|
---|
337 | //
|
---|
338 | // begin: specific to a two-fingered interleave
|
---|
339 | //
|
---|
340 | static_assert( OuterActn == 0 && InnerActn == 1 && N_INTERLEAVE_ACTION == 2 );
|
---|
341 |
|
---|
342 | const size_t iactSplitPos = NumNodes - NumNodes * InterleaveFrac;
|
---|
343 |
|
---|
344 | // initialize numNodesItlv
|
---|
345 | numNodesItlv[InnerActn] = (NumNodes-1) * InterleaveFrac; // inner, later: usual outer-inner order revd for data dep
|
---|
346 | numNodesItlv[OuterActn] = (NumNodes-1) - numNodesItlv[InnerActn]; // outer, earlier: ditto
|
---|
347 | assert( (numNodesItlv[InnerActn] + numNodesItlv[OuterActn] == NumNodes - 1) &&
|
---|
348 | "The two modes are meant to cover all items but one, which is left for bop_setup/bop_teardown" );
|
---|
349 |
|
---|
350 | B_UserItem * const iactFwdStartItem[N_INTERLEAVE_ACTION] = { seekUi(0), (iactSplitPos == NumNodes) ? NULL : seekUi(iactSplitPos) };
|
---|
351 | B_UserItem * const iactRevStartItem[N_INTERLEAVE_ACTION] = { seekUi(NumNodes-1), (iactSplitPos == NumNodes) ? NULL : seekUi(NumNodes - iactSplitPos -1) };
|
---|
352 |
|
---|
353 | {
|
---|
354 | // Not all nodes'interleave invalues are random. Need bookending nodes set to specific values.
|
---|
355 | // Last node seen in outer handling
|
---|
356 | // - must refer to inner mode
|
---|
357 | // - is near the split position (middle of list)
|
---|
358 | // - forward outer processing goes first to middle
|
---|
359 | // - reverse outer processing goes last to middle
|
---|
360 | // Last node seen in inner handling
|
---|
361 | // - must refer to outer mode
|
---|
362 | // - is at a leaf (first or last of list)
|
---|
363 | // - forward inner processing goes middle to last
|
---|
364 | // - reverse inner processing goes middle to first
|
---|
365 | // One of these cross references gets navigated, when its mode is the one that finishes first.
|
---|
366 | // (By then, all references "back" into this mode have been used up, so it's a termination condition for the mode that finishes first.)
|
---|
367 | // When the other mode exhausts its stash, the global ternimation condition (handled all non setup/teardown nodes) overrides its cross reference.
|
---|
368 | // Call out these four nodes as special (equal number, 2, referring to each mode); fill the rest randomly.
|
---|
369 |
|
---|
370 | assert( InterleaveFrac >= 0.0 && InterleaveFrac <= 1.0 );
|
---|
371 | // no action required on no-interleave
|
---|
372 | if ( InterleaveFrac > 0.0 ) {
|
---|
373 |
|
---|
374 | // assert( ( NumNodes >= 2 * N_INTERLEAVE_ACTION)
|
---|
375 | // && "Don't feel like dealing with interleave edge cases on tiny lists");
|
---|
376 |
|
---|
377 | if ( NumNodes >= 2 * N_INTERLEAVE_ACTION ) {
|
---|
378 | InterleaveAction * interleaveKey = (InterleaveAction *) malloc( sizeof(InterleaveAction) * NumNodes );
|
---|
379 |
|
---|
380 | const size_t iactStartPos [N_INTERLEAVE_ACTION] = { 0, iactSplitPos };
|
---|
381 | const size_t iactFinshPos [N_INTERLEAVE_ACTION] = { iactSplitPos, NumNodes };
|
---|
382 |
|
---|
383 | // generate randomly drawn ikey values
|
---|
384 | static_assert( 1 && "sorry, not checkable" && "values of InterleaveAction are enumerable" );
|
---|
385 | for ( unsigned char kk = 0; kk < (unsigned char) N_INTERLEAVE_ACTION; kk++ ) { // fill to the fractions
|
---|
386 | InterleaveAction k = (InterleaveAction) kk;
|
---|
387 | for ( int i = iactStartPos[k]; i < iactFinshPos[k]; i++ ) {
|
---|
388 | interleaveKey[i] = k;
|
---|
389 | }
|
---|
390 | }
|
---|
391 | for (size_t i = 0; i < NumNodes; i++) { // shuffle
|
---|
392 | size_t nodesRemaining = NumNodes - i;
|
---|
393 | size_t swapWith = i + (rand64() % nodesRemaining);
|
---|
394 | InterleaveAction tempValue = interleaveKey[swapWith];
|
---|
395 | interleaveKey[swapWith] = interleaveKey[i];
|
---|
396 | interleaveKey[i] = tempValue;
|
---|
397 | }
|
---|
398 | for (size_t i = 0; i < NumNodes; i++) { // record inside items
|
---|
399 | ui[i].later_flip = interleaveKey[i];
|
---|
400 | }
|
---|
401 | // set bookened positions
|
---|
402 | // FIXME: still incorrect; can't simply overwrite like done here;
|
---|
403 | // need to find an oppositely actioned node to swap with;
|
---|
404 | // as is,
|
---|
405 | // ./perfexp--upp-upp--queue-inslast-remelem 5 100000 37 -1 3 .50
|
---|
406 | // gets one too many outers;
|
---|
407 | // this extra outer reenables the outer cursor at ordinal 18
|
---|
408 | // after the inner cursor already remvoed ordinal 18
|
---|
409 | assert(false && "need to fix bookends");
|
---|
410 | seekUi( iactStartPos[OuterActn] )->later_flip = OuterActn;
|
---|
411 | seekUi( iactStartPos[InnerActn] )->later_flip = InnerActn;
|
---|
412 | seekUi( iactFinshPos[OuterActn] -1 )->later_flip = InnerActn;
|
---|
413 | seekUi( iactFinshPos[InnerActn] -1 )->later_flip = OuterActn;
|
---|
414 | //
|
---|
415 | // end: specific to a two-fingered interleave
|
---|
416 | //
|
---|
417 | free(interleaveKey);
|
---|
418 | } else {
|
---|
419 | // makefile targets call it, not easy to disable
|
---|
420 | // so just fill as if no interleave
|
---|
421 | for (size_t i = 0; i < NumNodes; i++) {
|
---|
422 | ui[i].later_flip = OuterActn;
|
---|
423 | }
|
---|
424 | }
|
---|
425 | }
|
---|
426 |
|
---|
427 | }
|
---|
428 | #endif
|
---|
429 |
|
---|
430 | #ifndef DISABLE_ITERS
|
---|
431 | #define ITERS_SAVE(lastInsertedElemPtr, lastInsertedIter) (lastInsertedElemPtr)->selfListed = lastInsertedIter
|
---|
432 | #endif
|
---|
433 |
|
---|
434 | BFX_INIT(B_UserItem, lst);
|
---|
435 |
|
---|
436 | bobs_init(NumNodes);
|
---|
437 |
|
---|
438 | // BOP_ADDFOO(lst, iters, insNo, item)
|
---|
439 | // BOP_REMFOO(lst, iters, remNo)
|
---|
440 | // lst lvalue of the list head being added to / removed from
|
---|
441 | // iters array of ADD return values, in logical-insert order; on ADD, is valid at [0..insNo)
|
---|
442 | // insNo interleave-perterbed counter of the ADD calls (logical insert number)
|
---|
443 | // remNo interleave-perterbed counter of the REM calls (logical remove number)
|
---|
444 | // item lvalue of the item being added
|
---|
445 | // Logical insert number 0 and remove number n-1 are given with a distinguished hook.
|
---|
446 | // Logical insert numbers [1,n) and remove numbers [0,n-1) are pumped by the basic SUT hooks.
|
---|
447 | // This pattern lets BOP cartridges that measure element-level operations know statically when there is a reference element in the list.
|
---|
448 | // The driver owns the relationship between a logical insert number and the location of the `item` argument within `ui`. (Scattered for randomness.)
|
---|
449 | // The BOP cartridge owns the relationship between logical remove number and any choice of an item in iters. (Defines stack vs queue.)
|
---|
450 |
|
---|
451 | // Default init/teardown is insert/remove
|
---|
452 | // Cartridges whose SUT insert/remove actions work on empty lists need not provide special-case ones.
|
---|
453 | #ifndef BOP_INIT
|
---|
454 | #define BOP_INIT(lst, item) BOP_INSERT(lst, ERROR_REQD_ITER_NOT_PROVIDED, item)
|
---|
455 | #endif
|
---|
456 | #ifndef BOP_TEARDOWN
|
---|
457 | #define BOP_TEARDOWN(lst) BOP_REMOVE(lst, ERROR_REQD_ITER_NOT_PROVIDED)
|
---|
458 | #endif
|
---|
459 |
|
---|
460 |
|
---|
461 | size_t privateOpsCompleted = 0;
|
---|
462 |
|
---|
463 | double elapsed_sec = 0;
|
---|
464 | clock_t start = clock();
|
---|
465 |
|
---|
466 | while (elapsed_sec <= (double) ExperimentDurSec && privateOpsCompleted < ExperimentDurOpCount) {
|
---|
467 | for ( size_t t = 0; t < CheckDonePeriod; t += 1 ) {
|
---|
468 | TRACE('a') // insert special first
|
---|
469 | ITERS_SAVE( &ui[0],
|
---|
470 | BOP_INIT(lst, ui[0]) );
|
---|
471 | TRACE('b') // insert general
|
---|
472 | // Keep lastInserted even on DISABLE_ITERS because it's communication to the remove phase
|
---|
473 | BFX_LISTED_ELEM_T(B_UserItem) lastInserted = BFX_GET_FIRST(B_UserItem, lst);
|
---|
474 | B_UserItem * insertNow = seekUi(1);
|
---|
475 | for ( size_t privateCurInsert = 1;
|
---|
476 | (bobs_prog_inserting = privateCurInsert, privateCurInsert < NumNodes);
|
---|
477 | privateCurInsert += 1
|
---|
478 | ) {
|
---|
479 | assert( insertNow->self_ord == privateCurInsert );
|
---|
480 | TRACE('-')
|
---|
481 | lastInserted =
|
---|
482 | BOP_INSERT( lst, lastInserted, (*insertNow) );
|
---|
483 | TRACE('+')
|
---|
484 | ITERS_SAVE( insertNow, lastInserted );
|
---|
485 | #ifdef DISABLE_SHUFFLING_INDIRECTION
|
---|
486 | insertNow++;
|
---|
487 | #else
|
---|
488 | insertNow = & ui[ insertNow->succ_pos ];
|
---|
489 | #endif
|
---|
490 | }
|
---|
491 | #ifdef DISABLE_INTERLEAVING
|
---|
492 | // interleaving off, simple removes
|
---|
493 | // (remove logic of 2b01f8eb0956)
|
---|
494 | #ifndef DISABLE_ITERS
|
---|
495 | BFX_LISTED_ELEM_T(B_UserItem) nextRemoval = BOP_SWITCH_REMDIR (
|
---|
496 | ui[0].selfListed, // forward starts from first insert
|
---|
497 | lastInserted // backward starts from last insert
|
---|
498 | );
|
---|
499 | #endif
|
---|
500 | TRACE('c')
|
---|
501 | for ( size_t privateCurRemove = 1;
|
---|
502 | (bobs_prog_removing = privateCurRemove, privateCurRemove < NumNodes);
|
---|
503 | privateCurRemove += 1
|
---|
504 | ) {
|
---|
505 | #ifdef DISABLE_ITERS
|
---|
506 | #define curRemovalI ERROR_REQD_ITER_NOT_PROVIDED
|
---|
507 | #else
|
---|
508 | BFX_LISTED_ELEM_T(B_UserItem) curRemovalI = nextRemoval;
|
---|
509 | B_UserItem * curRemovalE = BFX_DEREF_POS(B_UserItem, lst, nextRemoval);
|
---|
510 | #ifdef DISABLE_SHUFFLING_INDIRECTION
|
---|
511 | nextRemoval = (BOP_SWITCH_REMDIR( curRemovalE + 1, curRemovalE - 1 ))->selfListed;
|
---|
512 | #else
|
---|
513 | nextRemoval = ui[ curRemovalE->BOP_SWITCH_REMDIR(succ_pos, pred_pos) ].selfListed;
|
---|
514 | #endif
|
---|
515 | #endif
|
---|
516 | TRACE('-')
|
---|
517 | BOP_REMOVE( lst, curRemovalI );
|
---|
518 | TRACE('+')
|
---|
519 | }
|
---|
520 | #else
|
---|
521 | // interleaving on, complex removes
|
---|
522 | TRACE('c') // remove general
|
---|
523 | size_t removeProgress [N_INTERLEAVE_ACTION] = { 0, 0 };
|
---|
524 | #define startItem BOP_SWITCH_REMDIR( iactFwdStartItem, iactRevStartItem )
|
---|
525 | B_UserItem * removeItem[N_INTERLEAVE_ACTION] =
|
---|
526 | { startItem[OuterActn], startItem[InnerActn] };
|
---|
527 | for ( InterleaveAction flip = OuterActn
|
---|
528 | ; (bobs_prog_removing = removeProgress[0] + removeProgress[1] + 1,
|
---|
529 | bobs_prog_removing_end = removeProgress[0] + 1,
|
---|
530 | removeProgress[0] + removeProgress[1] < NumNodes - 1 )
|
---|
531 | ;
|
---|
532 | ) {
|
---|
533 | //printf("--- flip=%d removeProgress[0]=%zd removeProgress[1]=%zd removeItem[flip]->self_ord=%zd\n", flip, removeProgress[0], removeProgress[1], removeItem[flip]->self_ord);
|
---|
534 | TRACE('-')
|
---|
535 | BOP_REMOVE( lst, removeItem[flip]->selfListed );
|
---|
536 | TRACE('+')
|
---|
537 |
|
---|
538 | InterleaveAction nextFlip = removeItem[flip]->later_flip;
|
---|
539 | removeProgress[flip] += 1;
|
---|
540 | removeItem[flip] = & ui[ removeItem[flip]-> BOP_SWITCH_REMDIR(succ_pos, pred_pos) ];
|
---|
541 | flip = nextFlip;
|
---|
542 | }
|
---|
543 |
|
---|
544 | // for ( InterleaveAction flip = OuterActn;
|
---|
545 | // (bobs_prog_removing = removeProgress[0] + removeProgress[1] + 1,
|
---|
546 | // bobs_prog_removing_end = removeProgress[0] + 1,
|
---|
547 | // removeProgress[0] < numNodesItlv[0] && removeProgress[1] < numNodesItlv[1] );
|
---|
548 | // ) {
|
---|
549 | // TRACE('-')
|
---|
550 | // BOP_REMOVE( lst, removeItem[flip]->selfListed );
|
---|
551 | // TRACE('+')
|
---|
552 |
|
---|
553 | // InterleaveAction nextFlip = removeItem[flip]->later_flip;
|
---|
554 | // removeProgress[flip] += 1;
|
---|
555 | // removeItem[flip] = & ui[ removeItem[flip]-> BOP_SWITCH_REMDIR(succ_pos, pred_pos) ];
|
---|
556 | // flip = nextFlip;
|
---|
557 | // }
|
---|
558 | // TRACE('X') // remove imbalanced
|
---|
559 | // // most work done under general; it stops when either flip-side's work finishes
|
---|
560 | // // now drain any any stragglers so both flip-sides' work finishes
|
---|
561 | // for ( InterleaveAction flip = 0; flip < N_INTERLEAVE_ACTION; flip ++ ) {
|
---|
562 | // for ( ; (bobs_prog_removing = removeProgress[0] + removeProgress[1] + 1,
|
---|
563 | // bobs_prog_removing_end = removeProgress[0] + 1,
|
---|
564 | // removeProgress[flip] < numNodesItlv[flip] )
|
---|
565 | // ;
|
---|
566 | // ) {
|
---|
567 | // //printf("--- flip=%d removeProgress[flip]=%zd numNodesItlv[flip]=%zd removeItem[flip]->self_ord=%zd\n", flip, removeProgress[flip], numNodesItlv[flip], removeItem[flip]->self_ord);
|
---|
568 | // TRACE('-')
|
---|
569 | // BOP_REMOVE( lst, removeItem[flip]->selfListed );
|
---|
570 | // TRACE('+')
|
---|
571 |
|
---|
572 | // removeProgress[flip] += 1;
|
---|
573 | // removeItem[flip] = & ui[ removeItem[flip]-> BOP_SWITCH_REMDIR(succ_pos, pred_pos) ];
|
---|
574 | // }
|
---|
575 | // }
|
---|
576 | #endif // DISABLE_INTERLEAVING
|
---|
577 | TRACE('D') // remove special last
|
---|
578 | BOP_TEARDOWN(lst);
|
---|
579 | TRACE('d')
|
---|
580 |
|
---|
581 | privateOpsCompleted += NumNodes;
|
---|
582 |
|
---|
583 | bobs_prog_rollover_flag = 1;
|
---|
584 | TRACE('e')
|
---|
585 | bobs_prog_inserting = 0;
|
---|
586 | bobs_prog_removing = 0;
|
---|
587 | bobs_prog_removing_end = 0;
|
---|
588 | bobs_ops_completed = privateOpsCompleted;
|
---|
589 | TRACE('f')
|
---|
590 | bobs_prog_rollover_flag = 0;
|
---|
591 | TRACE('g')
|
---|
592 | }
|
---|
593 | #ifndef DISABLE_CLOCK_RECHECK
|
---|
594 | clock_t end = clock();
|
---|
595 | elapsed_sec = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
|
---|
596 | #endif
|
---|
597 | }
|
---|
598 | #ifdef DISABLE_CLOCK_RECHECK
|
---|
599 | {
|
---|
600 | clock_t end = clock();
|
---|
601 | elapsed_sec = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
|
---|
602 | }
|
---|
603 | #endif
|
---|
604 |
|
---|
605 | double mean_op_dur_ns = elapsed_sec / ((double)bobs_ops_completed) * 1000 * 1000 * 1000;
|
---|
606 | printf("%s,%zd,%f,%f\n", argv[0], bobs_ops_completed, elapsed_sec, mean_op_dur_ns);
|
---|
607 |
|
---|
608 | free(ui);
|
---|
609 | }
|
---|