Ignore:
Timestamp:
Aug 11, 2020, 4:40:15 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum, stuck-waitfor-destruct
Children:
0d070ca
Parents:
07d867b (diff), 129674b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into new-ast

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/thierry_delisle_PhD/code/relaxed_list.hpp

    r07d867b r22f94a4  
    11#pragma once
     2#define LIST_VARIANT relaxed_list
     3
     4#define VANILLA 0
     5#define SNZI 1
     6#define BITMASK 2
     7#define DISCOVER 3
     8#define SNZM 4
     9#define BIAS 5
     10#define BACK 6
     11#define BACKBIAS 7
     12
     13#ifndef VARIANT
     14#define VARIANT VANILLA
     15#endif
    216
    317#ifndef NO_STATS
     
    519#endif
    620
     21#include <cmath>
     22#include <functional>
    723#include <memory>
    824#include <mutex>
     25#include <thread>
    926#include <type_traits>
    1027
    1128#include "assert.hpp"
    1229#include "utils.hpp"
     30#include "links.hpp"
     31#include "snzi.hpp"
     32#include "snzi-packed.hpp"
     33#include "snzm.hpp"
    1334
    1435using namespace std;
    15 
    16 struct spinlock_t {
    17         std::atomic_bool ll = { false };
    18 
    19         inline void lock() {
    20                 while( __builtin_expect(ll.exchange(true),false) ) {
    21                         while(ll.load(std::memory_order_relaxed))
    22                                 asm volatile("pause");
    23                 }
    24         }
    25 
    26         inline bool try_lock() {
    27                 return false == ll.exchange(true);
    28         }
    29 
    30         inline void unlock() {
    31                 ll.store(false, std::memory_order_release);
    32         }
    33 
    34         inline explicit operator bool() {
    35                 return ll.load(std::memory_order_relaxed);
    36         }
    37 };
    38 
    39 static inline bool bts(std::atomic_size_t & target, size_t bit ) {
    40         //*
    41         int result = 0;
    42         asm volatile(
    43                 "LOCK btsq %[bit], %[target]\n\t"
    44                 :"=@ccc" (result)
    45                 : [target] "m" (target), [bit] "r" (bit)
    46         );
    47         return result != 0;
    48         /*/
    49         size_t mask = 1ul << bit;
    50         size_t ret = target.fetch_or(mask, std::memory_order_relaxed);
    51         return (ret & mask) != 0;
    52         //*/
    53 }
    54 
    55 static inline bool btr(std::atomic_size_t & target, size_t bit ) {
    56         //*
    57         int result = 0;
    58         asm volatile(
    59                 "LOCK btrq %[bit], %[target]\n\t"
    60                 :"=@ccc" (result)
    61                 : [target] "m" (target), [bit] "r" (bit)
    62         );
    63         return result != 0;
    64         /*/
    65         size_t mask = 1ul << bit;
    66         size_t ret = target.fetch_and(~mask, std::memory_order_relaxed);
    67         return (ret & mask) != 0;
    68         //*/
    69 }
    70 
    71 extern bool enable_stats;
    7236
    7337struct pick_stat {
     
    7539                size_t attempt = 0;
    7640                size_t success = 0;
     41                size_t local = 0;
    7742        } push;
    7843        struct {
     
    8045                size_t success = 0;
    8146                size_t mask_attempt = 0;
     47                size_t mask_reset = 0;
     48                size_t local = 0;
    8249        } pop;
    8350};
     
    9562
    9663template<typename node_t>
    97 struct _LinksFields_t {
    98         node_t * prev = nullptr;
    99         node_t * next = nullptr;
    100         unsigned long long ts = 0;
    101 };
    102 
    103 template<typename node_t>
    10464class __attribute__((aligned(128))) relaxed_list {
    10565        static_assert(std::is_same<decltype(node_t::_links), _LinksFields_t<node_t>>::value, "Node must have a links field");
    10666
    10767public:
    108         relaxed_list(unsigned numLists)
    109                 : lists(new intrusive_queue_t[numLists])
    110                 , numLists(numLists)
     68        static const char * name() {
     69                const char * names[] = {
     70                        "RELAXED: VANILLA",
     71                        "RELAXED: SNZI",
     72                        "RELAXED: BITMASK",
     73                        "RELAXED: SNZI + DISCOVERED MASK",
     74                        "RELAXED: SNZI + MASK",
     75                        "RELAXED: SNZI + LOCAL BIAS",
     76                        "RELAXED: SNZI + REVERSE RNG",
     77                        "RELAXED: SNZI + LOCAL BIAS + REVERSE RNG"
     78                };
     79                return names[VARIANT];
     80        }
     81
     82        relaxed_list(unsigned numThreads, unsigned numQueues)
     83                : numLists(numThreads * numQueues)
     84                , lists(new intrusive_queue_t<node_t>[numLists])
     85                #if VARIANT == SNZI || VARIANT == BACK
     86                        , snzi( std::log2( numLists / (2 * numQueues) ), 2 )
     87                #elif VARIANT == BIAS || VARIANT == BACKBIAS
     88                        #ifdef SNZI_PACKED
     89                                , snzi( std::ceil( std::log2(numLists) ) )
     90                        #else
     91                                , snzi( std::log2( numLists / (2 * numQueues) ), 2 )
     92                        #endif
     93                #elif VARIANT == SNZM || VARIANT == DISCOVER
     94                        , snzm( numLists )
     95                #endif
    11196        {
    11297                assertf(7 * 8 * 8 >= numLists, "List currently only supports 448 sublists");
    113                 // assert(sizeof(*this) == 128);
    11498                std::cout << "Constructing Relaxed List with " << numLists << std::endl;
    115 
    116                 #ifndef NO_STATS
    117                         if(head) this->next = head;
    118                         head = this;
    119                 #endif
    12099        }
    121100
     
    130109                while(true) {
    131110                        // Pick a random list
    132                         unsigned i = tls.rng.next() % numLists;
     111                        unsigned i = idx_from_r(tls.rng1.next(), VARIANT == BIAS || VARIANT == BACKBIAS);
    133112
    134113                        #ifndef NO_STATS
     
    139118                        if( !lists[i].lock.try_lock() ) continue;
    140119
    141                         __attribute__((unused)) int num = numNonEmpty;
     120                        #if VARIANT == VANILLA || VARIANT == BITMASK
     121                                __attribute__((unused)) int num = numNonEmpty;
     122                        #endif
    142123
    143124                        // Actually push it
    144125                        if(lists[i].push(node)) {
    145                                 numNonEmpty++;
    146                                 size_t qword = i >> 6ull;
    147                                 size_t bit   = i & 63ull;
    148                                 assertf((list_mask[qword] & (1ul << bit)) == 0, "Before set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
    149                                 __attribute__((unused)) bool ret = bts(list_mask[qword], bit);
    150                                 assert(!ret);
    151                                 assertf((list_mask[qword] & (1ul << bit)) != 0, "After set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
    152                         }
    153                         assert(numNonEmpty <= (int)numLists);
     126                                #if VARIANT == DISCOVER
     127                                        size_t qword = i >> 6ull;
     128                                        size_t bit   = i & 63ull;
     129                                        assert(qword == 0);
     130                                        bts(tls.mask, bit);
     131                                        snzm.arrive(i);
     132                                #elif VARIANT == SNZI || VARIANT == BIAS
     133                                        snzi.arrive(i);
     134                                #elif VARIANT == BACK || VARIANT == BACKBIAS
     135                                        snzi.arrive(i);
     136                                        tls.rng2.set_raw_state( tls.rng1.get_raw_state());
     137                                #elif VARIANT == SNZM
     138                                        snzm.arrive(i);
     139                                #elif VARIANT == BITMASK
     140                                        numNonEmpty++;
     141                                        size_t qword = i >> 6ull;
     142                                        size_t bit   = i & 63ull;
     143                                        assertf((list_mask[qword] & (1ul << bit)) == 0, "Before set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
     144                                        __attribute__((unused)) bool ret = bts(list_mask[qword], bit);
     145                                        assert(!ret);
     146                                        assertf((list_mask[qword] & (1ul << bit)) != 0, "After set %zu:%zu (%u), %zx & %zx", qword, bit, i, list_mask[qword].load(), (1ul << bit));
     147                                #else
     148                                        numNonEmpty++;
     149                                #endif
     150                        }
     151                        #if VARIANT == VANILLA || VARIANT == BITMASK
     152                                assert(numNonEmpty <= (int)numLists);
     153                        #endif
    154154
    155155                        // Unlock and return
     
    158158                        #ifndef NO_STATS
    159159                                tls.pick.push.success++;
    160                                 tls.empty.push.value += num;
    161                                 tls.empty.push.count += 1;
     160                                #if VARIANT == VANILLA || VARIANT == BITMASK
     161                                        tls.empty.push.value += num;
     162                                        tls.empty.push.count += 1;
     163                                #endif
    162164                        #endif
    163165                        return;
     
    166168
    167169        __attribute__((noinline, hot)) node_t * pop() {
    168                 #if !defined(NO_BITMASK)
    169                         // for(int r = 0; r < 10 && numNonEmpty != 0; r++) {
    170                         //      // Pick two lists at random
    171                         //      unsigned i = tls.rng.next() % numLists;
    172                         //      unsigned j = tls.rng.next() % numLists;
    173 
    174                         //      if(auto node = try_pop(i, j)) return node;
    175                         // }
     170                #if VARIANT == DISCOVER
     171                        assert(numLists <= 64);
     172                        while(snzm.query()) {
     173                                tls.pick.pop.mask_attempt++;
     174                                unsigned i, j;
     175                                {
     176                                        // Pick first list totally randomly
     177                                        i = tls.rng1.next() % numLists;
     178
     179                                        // Pick the other according to the bitmask
     180                                        unsigned r = tls.rng1.next();
     181
     182                                        size_t mask = tls.mask.load(std::memory_order_relaxed);
     183                                        if(mask == 0) {
     184                                                tls.pick.pop.mask_reset++;
     185                                                mask = (1U << numLists) - 1;
     186                                                tls.mask.store(mask, std::memory_order_relaxed);
     187                                        }
     188
     189                                        unsigned b = rand_bit(r, mask);
     190
     191                                        assertf(b < 64, "%zu %u", mask, b);
     192
     193                                        j = b;
     194
     195                                        assert(j < numLists);
     196                                }
     197
     198                                if(auto node = try_pop(i, j)) return node;
     199                        }
     200                #elif VARIANT == SNZI
     201                        while(snzi.query()) {
     202                                // Pick two lists at random
     203                                int i = tls.rng1.next() % numLists;
     204                                int j = tls.rng1.next() % numLists;
     205
     206                                if(auto node = try_pop(i, j)) return node;
     207                        }
     208
     209                #elif VARIANT == BACK
     210                        while(snzi.query()) {
     211                                // Pick two lists at random
     212                                int i = tls.rng2.prev() % numLists;
     213                                int j = tls.rng2.prev() % numLists;
     214
     215                                if(auto node = try_pop(i, j)) return node;
     216                        }
     217
     218                #elif VARIANT == BACKBIAS
     219                        while(snzi.query()) {
     220                                // Pick two lists at random
     221                                int i = idx_from_r(tls.rng2.prev(), true);
     222                                int j = idx_from_r(tls.rng2.prev(), true);
     223
     224                                if(auto node = try_pop(i, j)) return node;
     225                        }
     226
     227                #elif VARIANT == BIAS
     228                        while(snzi.query()) {
     229                                // Pick two lists at random
     230                                unsigned ri = tls.rng1.next();
     231                                unsigned i;
     232                                unsigned j = tls.rng1.next();
     233                                if(0 == (ri & 0xF)) {
     234                                        i = (ri >> 4) % numLists;
     235                                } else {
     236                                        i = tls.my_queue + ((ri >> 4) % 4);
     237                                        j = tls.my_queue + ((j >> 4) % 4);
     238                                        tls.pick.pop.local++;
     239                                }
     240                                i %= numLists;
     241                                j %= numLists;
     242
     243                                if(auto node = try_pop(i, j)) return node;
     244                        }
     245                #elif VARIANT == SNZM
     246                        //*
     247                        while(snzm.query()) {
     248                                tls.pick.pop.mask_attempt++;
     249                                unsigned i, j;
     250                                {
     251                                        // Pick two random number
     252                                        unsigned ri = tls.rng1.next();
     253                                        unsigned rj = tls.rng1.next();
     254
     255                                        // Pick two nodes from it
     256                                        unsigned wdxi = ri & snzm.mask;
     257                                        // unsigned wdxj = rj & snzm.mask;
     258
     259                                        // Get the masks from the nodes
     260                                        // size_t maski = snzm.masks(wdxi);
     261                                        size_t maskj = snzm.masks(wdxj);
     262
     263                                        if(maski == 0 && maskj == 0) continue;
     264
     265                                        #if defined(__BMI2__)
     266                                                uint64_t idxsi = _pext_u64(snzm.indexes, maski);
     267                                                // uint64_t idxsj = _pext_u64(snzm.indexes, maskj);
     268
     269                                                auto pi = __builtin_popcountll(maski);
     270                                                // auto pj = __builtin_popcountll(maskj);
     271
     272                                                ri = pi ? ri & ((pi >> 3) - 1) : 0;
     273                                                rj = pj ? rj & ((pj >> 3) - 1) : 0;
     274
     275                                                unsigned bi = (idxsi >> (ri << 3)) & 0xff;
     276                                                unsigned bj = (idxsj >> (rj << 3)) & 0xff;
     277                                        #else
     278                                                unsigned bi = rand_bit(ri >> snzm.depth, maski);
     279                                                unsigned bj = rand_bit(rj >> snzm.depth, maskj);
     280                                        #endif
     281
     282                                        i = (bi << snzm.depth) | wdxi;
     283                                        j = (bj << snzm.depth) | wdxj;
     284
     285                                        /* paranoid */ assertf(i < numLists, "%u %u", bj, wdxi);
     286                                        /* paranoid */ assertf(j < numLists, "%u %u", bj, wdxj);
     287                                }
     288
     289                                if(auto node = try_pop(i, j)) return node;
     290                        }
     291                        /*/
     292                        while(snzm.query()) {
     293                                // Pick two lists at random
     294                                int i = tls.rng1.next() % numLists;
     295                                int j = tls.rng1.next() % numLists;
     296
     297                                if(auto node = try_pop(i, j)) return node;
     298                        }
     299                        //*/
     300                #elif VARIANT == BITMASK
    176301                        int nnempty;
    177302                        while(0 != (nnempty = numNonEmpty)) {
    178303                                tls.pick.pop.mask_attempt++;
    179304                                unsigned i, j;
    180                                 // if( numLists < 4 || (numLists / nnempty) < 4 ) {
    181                                 //      // Pick two lists at random
    182                                 //      i = tls.rng.next() % numLists;
    183                                 //      j = tls.rng.next() % numLists;
    184                                 // } else
    185305                                {
    186                                         #ifndef NO_STATS
    187                                                 // tls.pick.push.mask_attempt++;
    188                                         #endif
    189 
    190306                                        // Pick two lists at random
    191307                                        unsigned num = ((numLists - 1) >> 6) + 1;
    192308
    193                                         unsigned ri = tls.rng.next();
    194                                         unsigned rj = tls.rng.next();
     309                                        unsigned ri = tls.rng1.next();
     310                                        unsigned rj = tls.rng1.next();
    195311
    196312                                        unsigned wdxi = (ri >> 6u) % num;
     
    220336                        while(numNonEmpty != 0) {
    221337                                // Pick two lists at random
    222                                 int i = tls.rng.next() % numLists;
    223                                 int j = tls.rng.next() % numLists;
     338                                int i = tls.rng1.next() % numLists;
     339                                int j = tls.rng1.next() % numLists;
    224340
    225341                                if(auto node = try_pop(i, j)) return node;
     
    234350                #ifndef NO_STATS
    235351                        tls.pick.pop.attempt++;
     352                #endif
     353
     354                #if VARIANT == DISCOVER
     355                        if(lists[i].ts() > 0) bts(tls.mask, i); else btr(tls.mask, i);
     356                        if(lists[j].ts() > 0) bts(tls.mask, j); else btr(tls.mask, j);
    236357                #endif
    237358
     
    249370                if( !list.lock.try_lock() ) return nullptr;
    250371
    251                 __attribute__((unused)) int num = numNonEmpty;
     372                #if VARIANT == VANILLA || VARIANT == BITMASK
     373                        __attribute__((unused)) int num = numNonEmpty;
     374                #endif
    252375
    253376                // If list is empty, unlock and retry
     
    264387
    265388                if(emptied) {
    266                         numNonEmpty--;
    267                         size_t qword = w >> 6ull;
    268                         size_t bit   = w & 63ull;
    269                         assert((list_mask[qword] & (1ul << bit)) != 0);
    270                         __attribute__((unused)) bool ret = btr(list_mask[qword], bit);
    271                         assert(ret);
    272                         assert((list_mask[qword] & (1ul << bit)) == 0);
     389                        #if VARIANT == DISCOVER
     390                                size_t qword = w >> 6ull;
     391                                size_t bit   = w & 63ull;
     392                                assert(qword == 0);
     393                                __attribute__((unused)) bool ret = btr(tls.mask, bit);
     394                                snzm.depart(w);
     395                        #elif VARIANT == SNZI || VARIANT == BIAS || VARIANT == BACK || VARIANT == BACKBIAS
     396                                snzi.depart(w);
     397                        #elif VARIANT == SNZM
     398                                snzm.depart(w);
     399                        #elif VARIANT == BITMASK
     400                                numNonEmpty--;
     401                                size_t qword = w >> 6ull;
     402                                size_t bit   = w & 63ull;
     403                                assert((list_mask[qword] & (1ul << bit)) != 0);
     404                                __attribute__((unused)) bool ret = btr(list_mask[qword], bit);
     405                                assert(ret);
     406                                assert((list_mask[qword] & (1ul << bit)) == 0);
     407                        #else
     408                                numNonEmpty--;
     409                        #endif
    273410                }
    274411
    275412                // Unlock and return
    276413                list.lock.unlock();
    277                 assert(numNonEmpty >= 0);
     414                #if VARIANT == VANILLA || VARIANT == BITMASK
     415                        assert(numNonEmpty >= 0);
     416                #endif
    278417                #ifndef NO_STATS
    279418                        tls.pick.pop.success++;
    280                         tls.empty.pop.value += num;
    281                         tls.empty.pop.count += 1;
     419                        #if VARIANT == VANILLA || VARIANT == BITMASK
     420                                tls.empty.pop.value += num;
     421                                tls.empty.pop.count += 1;
     422                        #endif
    282423                #endif
    283424                return node;
    284425        }
    285426
    286 private:
    287 
    288         class __attribute__((aligned(128))) intrusive_queue_t {
    289         public:
    290                 typedef spinlock_t lock_t;
    291 
    292                 friend class relaxed_list<node_t>;
    293 
    294                 struct stat {
    295                         ssize_t diff = 0;
    296                         size_t  push = 0;
    297                         size_t  pop  = 0;
    298                         // size_t value = 0;
    299                         // size_t count = 0;
    300                 };
    301 
    302         private:
    303                 struct sentinel_t {
    304                         _LinksFields_t<node_t> _links;
    305                 };
    306 
    307                 lock_t lock;
    308                 sentinel_t before;
    309                 sentinel_t after;
    310                 #ifndef NO_STATS
    311                         stat s;
    312                 #endif
    313 
    314 #pragma GCC diagnostic push
    315 #pragma GCC diagnostic ignored "-Winvalid-offsetof"
    316                 static constexpr auto fields_offset = offsetof( node_t, _links );
    317 #pragma GCC diagnostic pop
    318         public:
    319                 intrusive_queue_t()
    320                         : before{{ nullptr, tail() }}
    321                         , after {{ head(), nullptr }}
    322                 {
    323                         /* paranoid */ assert((reinterpret_cast<uintptr_t>( head() ) + fields_offset) == reinterpret_cast<uintptr_t>(&before));
    324                         /* paranoid */ assert((reinterpret_cast<uintptr_t>( tail() ) + fields_offset) == reinterpret_cast<uintptr_t>(&after ));
    325                         /* paranoid */ assert(head()->_links.prev == nullptr);
    326                         /* paranoid */ assert(head()->_links.next == tail() );
    327                         /* paranoid */ assert(tail()->_links.next == nullptr);
    328                         /* paranoid */ assert(tail()->_links.prev == head() );
    329                         /* paranoid */ assert(sizeof(*this) == 128);
    330                         /* paranoid */ assert((intptr_t(this) % 128) == 0);
     427        inline unsigned idx_from_r(unsigned r, bool bias) {
     428                unsigned i;
     429                if(bias) {
     430                        if(0 == (r & 0x3F)) {
     431                                i = r >> 6;
     432                        } else {
     433                                i = tls.my_queue + ((r >> 6) % 4);
     434                                tls.pick.push.local++;
     435                        }
     436                } else {
     437                        i = r;
    331438                }
    332 
    333                 ~intrusive_queue_t() = default;
    334 
    335                 inline node_t * head() const {
    336                         node_t * rhead = reinterpret_cast<node_t *>(
    337                                 reinterpret_cast<uintptr_t>( &before ) - fields_offset
    338                         );
    339                         assert(rhead);
    340                         return rhead;
    341                 }
    342 
    343                 inline node_t * tail() const {
    344                         node_t * rtail = reinterpret_cast<node_t *>(
    345                                 reinterpret_cast<uintptr_t>( &after ) - fields_offset
    346                         );
    347                         assert(rtail);
    348                         return rtail;
    349                 }
    350 
    351                 inline bool push(node_t * node) {
    352                         assert(lock);
    353                         assert(node->_links.ts != 0);
    354                         node_t * tail = this->tail();
    355 
    356                         node_t * prev = tail->_links.prev;
    357                         // assertf(node->_links.ts >= prev->_links.ts,
    358                         //      "New node has smaller timestamp: %llu < %llu", node->_links.ts, prev->_links.ts);
    359                         node->_links.next = tail;
    360                         node->_links.prev = prev;
    361                         prev->_links.next = node;
    362                         tail->_links.prev = node;
    363                         #ifndef NO_STATS
    364                                 if(enable_stats) {
    365                                         s.diff++;
    366                                         s.push++;
    367                                 }
    368                         #endif
    369                         if(before._links.ts == 0l) {
    370                                 before._links.ts = node->_links.ts;
    371                                 assert(node->_links.prev == this->head());
    372                                 return true;
    373                         }
    374                         return false;
    375                 }
    376 
    377                 inline std::pair<node_t *, bool> pop() {
    378                         assert(lock);
    379                         node_t * head = this->head();
    380                         node_t * tail = this->tail();
    381 
    382                         node_t * node = head->_links.next;
    383                         node_t * next = node->_links.next;
    384                         if(node == tail) return {nullptr, false};
    385 
    386                         head->_links.next = next;
    387                         next->_links.prev = head;
    388 
    389                         #ifndef NO_STATS
    390                                 if(enable_stats) {
    391                                         s.diff--;
    392                                         s.pop ++;
    393                                 }
    394                         #endif
    395                         if(next == tail) {
    396                                 before._links.ts = 0l;
    397                                 return {node, true};
    398                         }
    399                         else {
    400                                 assert(next->_links.ts != 0);
    401                                 before._links.ts = next->_links.ts;
    402                                 assert(before._links.ts != 0);
    403                                 return {node, false};
    404                         }
    405                 }
    406 
    407                 long long ts() const {
    408                         return before._links.ts;
    409                 }
    410         };
    411 
     439                return i % numLists;
     440        }
    412441
    413442public:
    414443
    415444        static __attribute__((aligned(128))) thread_local struct TLS {
    416                 Random     rng = { int(rdtscl()) };
     445                Random     rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
     446                Random     rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
     447                unsigned   my_queue = (ticket++) * 4;
    417448                pick_stat  pick;
    418449                empty_stat empty;
     450                __attribute__((aligned(64))) std::atomic_size_t mask = { 0 };
    419451        } tls;
    420452
     453private:
     454        const unsigned numLists;
     455        __attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t<node_t> []> lists;
     456private:
     457        #if VARIANT == SNZI || VARIANT == BACK
     458                snzi_t snzi;
     459        #elif VARIANT == BIAS || VARIANT == BACKBIAS
     460                #ifdef SNZI_PACKED
     461                        snzip_t snzi;
     462                #else
     463                        snzi_t snzi;
     464                #endif
     465        #elif VARIANT == SNZM || VARIANT == DISCOVER
     466                snzm_t snzm;
     467        #else
     468                std::atomic_int numNonEmpty  = { 0 };  // number of non-empty lists
     469        #endif
     470        #if VARIANT == BITMASK
     471                std::atomic_size_t list_mask[7] = { {0}, {0}, {0}, {0}, {0}, {0}, {0} }; // which queues are empty
     472        #endif
     473
    421474public:
    422         std::atomic_int numNonEmpty  = { 0 };  // number of non-empty lists
    423         std::atomic_size_t list_mask[7] = { {0}, {0}, {0}, {0}, {0}, {0}, {0} }; // which queues are empty
    424 private:
    425         __attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t []> lists;
    426         const unsigned numLists;
    427 
    428 public:
    429         static const constexpr size_t sizeof_queue = sizeof(intrusive_queue_t);
     475        static const constexpr size_t sizeof_queue = sizeof(intrusive_queue_t<node_t>);
     476        static std::atomic_uint32_t ticket;
    430477
    431478#ifndef NO_STATS
    432         static void stats_print(std::ostream & os) {
    433                 auto it = head;
    434                 while(it) {
    435                         it->stats_print_local(os);
    436                         it = it->next;
    437                 }
    438         }
    439 
    440479        static void stats_tls_tally() {
    441480                global_stats.pick.push.attempt += tls.pick.push.attempt;
    442481                global_stats.pick.push.success += tls.pick.push.success;
     482                global_stats.pick.push.local += tls.pick.push.local;
    443483                global_stats.pick.pop .attempt += tls.pick.pop.attempt;
    444484                global_stats.pick.pop .success += tls.pick.pop.success;
    445485                global_stats.pick.pop .mask_attempt += tls.pick.pop.mask_attempt;
     486                global_stats.pick.pop .mask_reset += tls.pick.pop.mask_reset;
     487                global_stats.pick.pop .local += tls.pick.pop.local;
    446488
    447489                global_stats.qstat.push.value += tls.empty.push.value;
     
    457499                                std::atomic_size_t attempt = { 0 };
    458500                                std::atomic_size_t success = { 0 };
     501                                std::atomic_size_t local = { 0 };
    459502                        } push;
    460503                        struct {
     
    462505                                std::atomic_size_t success = { 0 };
    463506                                std::atomic_size_t mask_attempt = { 0 };
     507                                std::atomic_size_t mask_reset = { 0 };
     508                                std::atomic_size_t local = { 0 };
    464509                        } pop;
    465510                } pick;
     
    476521        } global_stats;
    477522
    478         // Link list of all lists for stats
    479         __attribute__((aligned(64))) relaxed_list<node_t> * next = nullptr;
    480 
    481         static relaxed_list<node_t> * head;
    482 
    483         void stats_print_local(std::ostream & os ) {
     523public:
     524        static void stats_print(std::ostream & os ) {
    484525                std::cout << "----- Relaxed List Stats -----" << std::endl;
    485                 {
    486                         ssize_t diff = 0;
    487                         size_t  num  = 0;
    488                         ssize_t max  = 0;
    489 
    490                         for(size_t i = 0; i < numLists; i++) {
    491                                 const auto & list = lists[i];
    492                                 diff+= list.s.diff;
    493                                 num ++;
    494                                 max  = std::abs(max) > std::abs(list.s.diff) ? max : list.s.diff;
    495                                 os << "Local Q ops   : " << (list.s.push + list.s.pop) << "(" << list.s.push << "i, " << list.s.pop << "o)\n";
    496                         }
    497 
    498                         os << "Difference   : " << ssize_t(double(diff) / num  ) << " avg\t" << max << "max" << std::endl;
    499                 }
    500526
    501527                const auto & global = global_stats;
     
    504530                double pop_sur  = (100.0 * double(global.pick.pop .success) / global.pick.pop .attempt);
    505531                double mpop_sur = (100.0 * double(global.pick.pop .success) / global.pick.pop .mask_attempt);
    506 
    507                 os << "Push   Pick % : " << push_sur << "(" << global.pick.push.success << " / " << global.pick.push.attempt << ")\n";
    508                 os << "Pop    Pick % : " << pop_sur  << "(" << global.pick.pop .success << " / " << global.pick.pop .attempt << ")\n";
    509                 os << "TryPop Pick % : " << mpop_sur << "(" << global.pick.pop .success << " / " << global.pick.pop .mask_attempt << ")\n";
     532                double rpop_sur = (100.0 * double(global.pick.pop .success) / global.pick.pop .mask_reset);
     533
     534                double push_len = double(global.pick.push.attempt     ) / global.pick.push.success;
     535                double pop_len  = double(global.pick.pop .attempt     ) / global.pick.pop .success;
     536                double mpop_len = double(global.pick.pop .mask_attempt) / global.pick.pop .success;
     537                double rpop_len = double(global.pick.pop .mask_reset  ) / global.pick.pop .success;
     538
     539                os << "Push   Pick   : " << push_sur << " %, len " << push_len << " (" << global.pick.push.attempt      << " / " << global.pick.push.success << ")\n";
     540                os << "Pop    Pick   : " << pop_sur  << " %, len " << pop_len  << " (" << global.pick.pop .attempt      << " / " << global.pick.pop .success << ")\n";
     541                os << "TryPop Pick   : " << mpop_sur << " %, len " << mpop_len << " (" << global.pick.pop .mask_attempt << " / " << global.pick.pop .success << ")\n";
     542                os << "Pop M Reset   : " << rpop_sur << " %, len " << rpop_len << " (" << global.pick.pop .mask_reset   << " / " << global.pick.pop .success << ")\n";
    510543
    511544                double avgQ_push = double(global.qstat.push.value) / global.qstat.push.count;
     
    515548                os << "Pop    Avg Qs : " << avgQ_pop  << " (" << global.qstat.pop .count << "ops)\n";
    516549                os << "Global Avg Qs : " << avgQ      << " (" << (global.qstat.push.count + global.qstat.pop .count) << "ops)\n";
     550
     551                os << "Local Push    : " << global.pick.push.local << "\n";
     552                os << "Local Pop     : " << global.pick.pop .local << "\n";
    517553        }
    518554#endif
Note: See TracChangeset for help on using the changeset viewer.