Ignore:
Timestamp:
Aug 12, 2025, 12:44:35 AM (2 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master
Children:
7f995d70
Parents:
81e1984b
Message:

Revise data in linked-list plots with streamlined harness and data from runs on swift.

No change to text discussing the plots, so some of that discussion is now stale.

Harness changes allow more ifdef feature disabling and eliminate side-array usage, keeping all per-node harness state inside the list nodes.

Completely disable the interleaving experiment, which was not giving discernable data.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/mike_brooks_MMath/benchmarks/list/driver.c

    r81e1984b r6c58850  
    33#include <stdlib.h>
    44#include <string.h>
     5#include <stdint.h>
     6#include <assert.h>
    57
    68#ifdef DISABLE_OBSERVATION
     
    1113#endif
    1214
    13 #ifdef TINY_USER_ITEMS
    14   #define UDATA_T char
    15   #define UDATA_LEN 1
    16   #define UDATA_USE_POS 0
    17 #else
    18   #define UDATA_T int
    19   #define UDATA_LEN 64
    20   #define UDATA_USE_POS 17
     15#ifdef HUGE_USER_ITEMS
     16  #define UDATA_T float
     17  #define UDATA_LEN 17
    2118#endif
    2219
    23 typedef struct B_UserItem
     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
     29typedef enum InterleaveAction { OuterActn = 0, InnerActn = 1 } InterleaveAction;
     30enum { N_INTERLEAVE_ACTION = 2 } ;
     31
     32typedef
     33struct __attribute__(( aligned(64) )) B_UserItem
    2434    BFX_EXTRUSION_DECL(B_UserItem)
    2535{
    2636    BFX_INTRUSION(B_UserItem)
    27 //    BFX_LISTED_ELEM_T(B_UserItem) selfListed;
    28     UDATA_T userdata[ UDATA_LEN ];
     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
    2951}
    3052B_UserItem;
     
    5274static B_UserItem *ui = NULL;
    5375
    54 static BFX_LISTED_ELEM_T(B_UserItem) *listedItems = NULL;
    5576static BFX_LISTED_ELEM_T(B_UserItem) observedItem;
    5677
    5778static BFX_LIST_HEAD_T(B_UserItem) lst;
     79
     80B_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}
    5889
    5990#ifdef DISABLE_OBSERVATION
    6091MAYBE_EXTERN_C (
    61     void bobs_seek(unsigned int i) {}
     92    void bobs_seek(size_t i) {}
    6293    void bobs_moveNext() {}
    6394    void bobs_movePrev() {}
    64     int bobs_hasCurrent() { return 0; }
     95    bool bobs_hasCurrent() { return 0; }
    6596    void * bobs_getCurrentLoc() { return NULL; }
    66     int bobs_getCurrentVal() { return 0; }
     97    size_t bobs_getCurrentVal() { return 0; }
    6798    // enum bobs_op_movement_t bobs_op_movement = OP_MOVEMENT;
    6899    // enum bobs_op_polarity_t bobs_op_polarity = OP_POLARITY;
     
    74105
    75106    volatile size_t       bobs_ops_completed      = 0;
    76     volatile unsigned int bobs_prog_inserting     = 0;
    77     volatile unsigned int bobs_prog_removing      = 0;
    78     volatile unsigned int bobs_prog_removing_end  = 0;
    79     volatile unsigned int bobs_prog_rollover_flag = 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;
    80111    //                    bobs_prog_rem_pos         (defined after BOP_REMPROGEND_IS_REMNO_BASED)
    81112
    82     void bobs_seek(unsigned int i) {
    83         observedItem = listedItems[i];
     113    void bobs_seek(size_t i) {
     114      #ifndef DISABLE_ITERS
     115        observedItem = seekUi(i)->selfListed;
     116      #endif
    84117    }
    85118
     
    92125    }
    93126
    94     int bobs_hasCurrent() {
     127    bool bobs_hasCurrent() {
    95128        return BFX_IS_VALID_POS(B_UserItem, lst, observedItem);
    96129    }
     
    99132        return BFX_DEREF_POS(B_UserItem, lst, observedItem);
    100133    }
    101     int bobs_getCurrentVal() {
     134    size_t bobs_getCurrentVal() {
    102135        B_UserItem * curUI = BFX_DEREF_POS(B_UserItem, lst, observedItem);
    103         return curUI->userdata[ UDATA_USE_POS ];
     136        return curUI->self_ord;
    104137    }
    105138
     
    112145#ifndef DISABLE_OBSERVATION
    113146
    114 // Remove progress end (number) is based (upon) remove-number
     147// Remove progress end (as in, outer) (number) is based (upon) remove-number
    115148// True when an OP's REMELEM used remNo to choose which element to remove
    116149// False otherwise; notably including when REMELEM just bases upon first/last
     
    120153#endif
    121154MAYBE_EXTERN_C (
    122     volatile unsigned int const * bobs_prog_rem_pos =
     155    volatile size_t const * bobs_prog_rem_pos =
    123156      #ifdef DISABLE_INTERLEAVING
    124157        & bobs_prog_removing
     
    131164#endif // ndef DISABLE_OBSERVATION
    132165
    133 unsigned int uDefaultPreemption() {
    134         return 0;
    135 }
    136 
    137 #ifdef DISABLE_ITERS_AR
     166// size_t uDefaultPreemption() {
     167//         return 0;
     168// }
     169
     170#ifdef DISABLE_ITERS
    138171// Saves on memory accesses, makes element-oriented removals and observation impossible (instead, they crash)
    139172static inline BFX_LISTED_ELEM_T(B_UserItem) buhrdice_pass( BFX_LISTED_ELEM_T(B_UserItem) v ) {   // prevent eliding, cheaper than volatile
     
    144177#endif
    145178
     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)
     182static_assert((RAND_MAX & (RAND_MAX + 1u)) == 0, "RAND_MAX not a Mersenne number");
     183
     184uint64_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
    146194int main(int argc, const char *argv[]) {
    147195
     
    149197    // define the outbound dependencies as locals, for compiling into nops
    150198    size_t       bobs_ops_completed      = 0;
    151     unsigned int bobs_prog_inserting     = 0;
    152     unsigned int bobs_prog_removing      = 0;
    153     unsigned int bobs_prog_removing_end  = 0;
    154     unsigned int bobs_prog_rollover_flag = 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;
    155203  #endif
    156204
     
    158206    const int static_arg_posns = 6;
    159207
    160     unsigned int ExperimentDurSec     = DefaultExperimentDurSec;
    161     unsigned int CheckDonePeriod      = DefaultCheckDonePeriod;
    162     unsigned int NumNodes             = DefaultNumNodes;
    163     size_t       ExperimentDurOpCount = DefaultExperimentDurOpCount;
    164     unsigned int Seed                 = DefaultSeed;
    165     double       InterleaveFrac       = DefaultInterleaveFrac;
     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;
    166214
    167215    switch (((argc - 1) < static_arg_posns) ? (argc - 1) : static_arg_posns) {
     
    189237  #endif
    190238
    191     // Shuffling makes listed items' physical order in memory different from their order within to the list.
    192     // Affects insertion: next item to insert picked through insertOrdShuf.
    193   #ifdef DISABLE_SHUFFLING_INDIRECTION
    194     #define INSERTPOS(insertNum) insertNum
    195   #else
    196     // To ensure random memory order of nodes being inserted, do so according to a shuffled ordering of them.
    197     unsigned int * insertOrdShuf = (unsigned int *) malloc( (size_t)NumNodes * sizeof(unsigned int) );
    198     if (!insertOrdShuf) {
    199         printf("malloc request for %zd bytes for insertOrdShuf refused\n", (size_t)NumNodes * (size_t)sizeof(unsigned int));
    200         return 1;
    201     }
    202     // Fill with the ordinals (iota)
    203     for (int i = 0; i < NumNodes; i++) {
    204         insertOrdShuf[i] = i;
    205     }
    206     // Dummy "Seed" of -1 means skip the shuffle: measure overhead of insertOrdShuf indirection
    207     if (Seed != -1) {
    208         // Shuffle
    209         srand(Seed);
    210         for (unsigned int i = 0; i < NumNodes; i++) {
    211             unsigned int nodesRemaining = NumNodes - i;
    212             unsigned int swapWith = i + rand() % nodesRemaining;
    213             unsigned int tempValue = insertOrdShuf[swapWith];
    214             insertOrdShuf[swapWith] = insertOrdShuf[i];
    215             insertOrdShuf[i] = tempValue;
    216         }
    217     }
    218     #define INSERTPOS(insertNum) insertOrdShuf[insertNum]
    219   #endif
    220 
    221     // Interleaving affects the list position where an element-oriented operation occurs: at an end vs. in the middle.
    222     // Perterbs the sequence of logical insert/remove numbers presented to the OP cartridge, e.g. from [0 1 2 3 4 5 6]
    223     // to [3 0 4 1 5 2 6], which is [mid end mid end mid end solo], for a perfect-alternation interleave; except that the
    224     // end/mid interleave is atually selected randomly.
    225   #ifdef DISABLE_INTERLEAVING
    226     #define nextInterleave 0
    227   #else
    228     const unsigned int INTRL_KEYLEN = 64;
    229     unsigned char interleaveKey[INTRL_KEYLEN];
    230     unsigned char nextInterleavePos = 0;
    231     {
    232         unsigned int numOnes = INTRL_KEYLEN * InterleaveFrac;
    233         unsigned int numZeros = INTRL_KEYLEN - numOnes;
    234         // generate randomly drawn 0/1
    235         memset( interleaveKey         , 0, numZeros );  // zeros then ones
    236         memset( interleaveKey+numZeros, 1, numOnes );
    237         for (unsigned int i = 0; i < 64; i++) { // shuffle it
    238             unsigned int nodesRemaining = 64 - i;
    239             unsigned int swapWith = i + rand() % nodesRemaining;
    240             unsigned char tempValue = interleaveKey[swapWith];
    241             interleaveKey[swapWith] = interleaveKey[i];
    242             interleaveKey[i] = tempValue;
    243         }
    244         #define nextInterleave (interleaveKey[nextInterleavePos = (nextInterleavePos + 1) % 64])
    245     }
    246     {
    247         unsigned int z = 0, o = 0;
    248         for ( int i = 0; i < INTRL_KEYLEN; i++ ) {
    249             if (interleaveKey[i]) o++;
    250             else z++;
    251         }
    252         // printf("Interleaving with %u in middle and %u at end\n", o, z);
    253     }
    254     // printf("interleave key begins %016llx\n", *(unsigned long long*)interleaveKey);
    255     // printf("interleave key begins %016llx\n", *(unsigned long long*)(interleaveKey+8));
    256     // printf("sample interleave value %d\n", nextInterleave);
    257     // printf("sample interleave value %d\n", nextInterleave);
    258     // printf("sample interleave value %d\n", nextInterleave);
    259     // printf("sample interleave value %d\n", nextInterleave);
    260     // printf("sample interleave value %d\n", nextInterleave);
    261     // printf("sample interleave value %d\n", nextInterleave);
    262     // printf("sample interleave value %d\n", nextInterleave);
    263     // printf("sample interleave value %d\n", nextInterleave);
    264     // printf("sample interleave value %d\n", nextInterleave);
    265     // printf("sample interleave value %d\n", nextInterleave);
    266     // printf("sample interleave value %d\n", nextInterleave);
    267     // printf("sample interleave value %d\n", nextInterleave);
    268   #endif
    269 
    270239    ui = (B_UserItem*) malloc( (size_t)NumNodes * (size_t)sizeof(B_UserItem) );
    271240    if (!ui) {
     
    274243    }
    275244    memset(ui, 0, (size_t)NumNodes * (size_t)sizeof(B_UserItem));
    276 
    277   #ifndef DISABLE_ITERS_AR
    278     listedItems = (BFX_LISTED_ELEM_T(B_UserItem)*)malloc( (size_t)NumNodes * (size_t)sizeof(BFX_LISTED_ELEM_T(B_UserItem)) );
    279     if (!listedItems) {
    280         printf("malloc request for %zd bytes for listedItems refused\n", (size_t)NumNodes * (size_t)sizeof(BFX_LISTED_ELEM_T(B_UserItem)));
    281         return 1;
    282     }
    283     memset(listedItems, 0, (size_t)NumNodes * (size_t)sizeof(BFX_LISTED_ELEM_T(B_UserItem)));
    284     #define ITERS_SAVE(i, insertElemExpr) listedItems[i] = (insertElemExpr)
    285   #endif
    286 
    287     // Construct and fill with demo data
    288     for (unsigned int i = 0; i < NumNodes; i++) {
    289         B_UserItem * curUI = & ui[INSERTPOS(i)];
    290       #ifdef __cforall
     245    // Construct
     246    #ifdef __cforall
     247    for (size_t i = 0; i < NumNodes; i++) {
     248        B_UserItem * curUI = & ui[i];
    291249        (*curUI){};
    292       #endif
    293         curUI->userdata[ UDATA_USE_POS ] = i;
    294     }
     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
    295433
    296434    BFX_INIT(B_UserItem, lst);
     
    314452    // Cartridges whose SUT insert/remove actions work on empty lists need not provide special-case ones.
    315453    #ifndef BOP_INIT
    316     #define BOP_INIT(lst, iters, insNo, item) BOP_INSERT(lst, iters, insNo, item)
     454    #define BOP_INIT(lst, item) BOP_INSERT(lst, ERROR_REQD_ITER_NOT_PROVIDED, item)
    317455    #endif
    318456    #ifndef BOP_TEARDOWN
    319     #define BOP_TEARDOWN(lst, iters, remNo) BOP_REMOVE(lst, iters, remNo)
     457    #define BOP_TEARDOWN(lst) BOP_REMOVE(lst, ERROR_REQD_ITER_NOT_PROVIDED)
    320458    #endif
     459
     460
     461    size_t privateOpsCompleted = 0;
    321462
    322463    double elapsed_sec = 0;
    323464    clock_t start = clock();
    324  
    325     const unsigned int numMiddleNodes = (NumNodes-1) * InterleaveFrac;
    326     const unsigned int numEndNodes = NumNodes - numMiddleNodes - 1;
    327 
    328     // printf("Running with %u in the middle and %u at end\n", numMiddleNodes, numEndNodes);
    329 
    330     const unsigned int removeBase[] = {0, numEndNodes};
    331     const unsigned int removeLimit[] = {numEndNodes, numMiddleNodes};
    332 
    333     size_t privateOpsCompleted = 0;
    334465
    335466    while (elapsed_sec <= (double) ExperimentDurSec && privateOpsCompleted < ExperimentDurOpCount) {
    336         for ( int t = 0; t < CheckDonePeriod; t += 1 ) {
     467        for ( size_t t = 0; t < CheckDonePeriod; t += 1 ) {
    337468            TRACE('a')              // insert special first
    338             ITERS_SAVE( 0,
    339                 BOP_INIT(lst, listedItems, 0, ui[INSERTPOS(0)]) );
     469            ITERS_SAVE( &ui[0],
     470                BOP_INIT(lst, ui[0]) );
    340471            TRACE('b')              // insert general
    341             for ( int privateCurInsert = 1;
     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;
    342476                  (bobs_prog_inserting = privateCurInsert, privateCurInsert < NumNodes);
    343477                  privateCurInsert += 1
    344478                ) {
     479                assert( insertNow->self_ord == privateCurInsert );
    345480                TRACE('-')
    346                 ITERS_SAVE( privateCurInsert,
    347                     BOP_INSERT( lst, listedItems, privateCurInsert, ui[INSERTPOS(privateCurInsert)] ) );
     481                lastInserted =
     482                    BOP_INSERT( lst, lastInserted, (*insertNow) );
    348483                TRACE('+')
     484                ITERS_SAVE( insertNow, lastInserted );
     485              #ifdef DISABLE_SHUFFLING_INDIRECTION
     486                insertNow++;
     487              #else
     488                insertNow = & ui[ insertNow->succ_pos ];
     489              #endif
    349490            }
    350491          #ifdef DISABLE_INTERLEAVING
    351492            // interleaving off, simple removes
    352493            // (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
    353500            TRACE('c')
    354             for ( int privateCurRemove = 1;
     501            for ( size_t privateCurRemove = 1;
    355502                  (bobs_prog_removing = privateCurRemove, privateCurRemove < NumNodes);
    356503                  privateCurRemove += 1
    357504                ) {
     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
    358516                TRACE('-')
    359                 BOP_REMOVE( lst, listedItems, privateCurRemove-1 );
     517                BOP_REMOVE( lst, curRemovalI );
    360518                TRACE('+')
    361519            }
     
    363521            // interleaving on, complex removes
    364522            TRACE('c')              // remove general
    365             int removeProgress[] = { 0, 0 };
    366             for ( int flip = 0;
    367                   (bobs_prog_removing = removeProgress[0] + removeProgress[1] + 1,
     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,
    368529                     bobs_prog_removing_end = removeProgress[0] + 1,
    369                      flip = nextInterleave,
    370                      removeProgress[0] < removeLimit[0] && removeProgress[1] < removeLimit[1] );
    371                   removeProgress[flip] += 1
     530                     removeProgress[0] + removeProgress[1] < NumNodes - 1 )
     531                ;
    372532                ) {
     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);
    373534                TRACE('-')
    374                 BOP_REMOVE( lst, listedItems, removeBase[flip]+removeProgress[flip] );
     535                BOP_REMOVE( lst, removeItem[flip]->selfListed );
    375536                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;
    376542            }
    377             TRACE('X')              // remove imbalanced
    378             // most work done under general; it stops when either flip-side's work finishes
    379             // now drain any any stragglers so both flip-sides' work finishes
    380             for ( int flip = 0; flip < 2; flip ++ ) {
    381                 for ( ; (bobs_prog_removing = removeProgress[0] + removeProgress[1] + 1,
    382                          bobs_prog_removing_end = removeProgress[0] + 1,
    383                          removeProgress[flip] < removeLimit[flip] )
    384                       ;  removeProgress[flip] += 1
    385                     ) {
    386                     TRACE('-')
    387                     BOP_REMOVE( lst, listedItems, removeBase[flip]+removeProgress[flip] );
    388                     TRACE('+')
    389                 }
    390             }
     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//             }
    391576          #endif // DISABLE_INTERLEAVING
    392577            TRACE('D')              // remove special last
    393             BOP_TEARDOWN(lst, listedItems, NumNodes-1);
     578            BOP_TEARDOWN(lst);
    394579            TRACE('d')
    395580
     
    422607
    423608    free(ui);
    424     free(listedItems);
    425   #ifndef DISABLE_SHUFFLING_INDIRECTION
    426     free(insertOrdShuf);
    427   #endif
    428609}
Note: See TracChangeset for help on using the changeset viewer.