source: doc/theses/thierry_delisle_PhD/code/readyQ_proto/dynamic_entropy.hpp@ bb7422a

ADT ast-experimental
Last change on this file since bb7422a was a1b9bc3, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Many small changes to prototype code

  • Property mode set to 100644
File size: 5.4 KB
Line 
1#pragma once
2
3#define LIST_VARIANT dyn_ent_list
4
5#include <memory>
6#include <mutex>
7#include <thread>
8
9#include "assert.hpp"
10#include "utils.hpp"
11#include "links.hpp"
12
13std::mutex mtx_;
14
15template<typename node_t>
16class __attribute__((aligned(128))) dyn_ent_list {
17 const unsigned numLists;
18 __attribute__((aligned(64))) std::unique_ptr<intrusive_queue_t<node_t> []> lists;
19
20public:
21 dyn_ent_list(unsigned numThreads, unsigned)
22 : numLists(numThreads * 4)
23 , lists(new intrusive_queue_t<node_t>[numLists])
24 {
25 std::cout << "Constructing Relaxed List with " << numLists << std::endl;
26 }
27
28 __attribute__((noinline, hot)) void push(node_t * node) {
29 node->_links.ts = rdtscl();
30
31 // Try to pick a lane and lock it
32 unsigned i;
33 do {
34 // Pick the index of a lane
35 i = idx_from_r(tls.rng1.next(), tls.my_queue).first;
36 // i = ret.first; //local = ret.second;
37 tls.stats.push.attempt++;
38 } while( !lists[i].lock.try_lock() );
39
40 lists[i].push(node);
41 lists[i].lock.unlock();
42 tls.rng2.set_raw_state( tls.rng1.get_raw_state());
43 tls.stats.push.success++;
44 }
45
46 __attribute__((noinline, hot)) node_t * pop() {
47 for(int n = 0; n < 25; n++) {
48 // Pick two lists at random
49 unsigned i, j;
50 bool locali, localj;
51 auto reti = idx_from_r(tls.rng2.prev(), tls.my_queue);
52 auto retj = idx_from_r(tls.rng2.prev(), tls.my_queue);
53
54 i = reti.first; locali = reti.second;
55 j = retj.first; localj = retj.second;
56 tls.stats.pop.attempt++;
57
58 // try popping from the 2 picked lists
59 node_t * thrd = try_pop(i, j);
60 if(thrd) {
61 tls.stats.pop.success++;
62 return thrd;
63 }
64 }
65
66 unsigned offset = tls.rng2.next();
67 for(unsigned i = 0; i < numLists; i++) {
68 unsigned idx = (offset + i) % numLists;
69 node_t * thrd = try_pop(idx);
70 if(thrd) {
71 return thrd;
72 }
73 }
74
75 // All lanes where empty return 0p
76 return nullptr;
77 }
78
79private:
80 inline node_t * try_pop(unsigned i, unsigned j) {
81 // Pick the bet list
82 int w = i;
83 if( __builtin_expect(!(lists[j].ts() > 0), true) ) {
84 w = (lists[i].ts() < lists[j].ts()) ? i : j;
85 }
86
87 return try_pop(w);
88 }
89
90 inline node_t * try_pop(unsigned w) {
91 // If list looks empty retry
92 if( lists[w].ts() == 0 ) { tls.stats.pop.empty++; return nullptr; }
93
94 // If we can't get the lock retry
95 if( !lists[w].lock.try_lock() ) { tls.stats.pop.locked++; return nullptr; }
96
97
98 // If list is empty, unlock and retry
99 if( lists[w].ts() == 0 ) {
100 tls.stats.pop.both++;
101 lists[w].lock.unlock();
102 return nullptr;
103 }
104
105 auto node = lists[w].pop();
106 lists[w].lock.unlock();
107 return node.first;
108 }
109
110 inline std::pair<unsigned, bool> idx_from_r(unsigned r, unsigned preferred) {
111 unsigned i;
112 bool local;
113 unsigned rlow = r % 4;
114 unsigned rhigh = r / 4;
115 if((0 != rlow) && preferred != outside) {
116 // (BIAS - 1) out of BIAS chances
117 // Use perferred queues
118 i = preferred + (rhigh % 4);
119 local = true;
120 }
121 else {
122 // 1 out of BIAS chances
123 // Use all queues
124 i = rhigh;
125 local = false;
126 }
127 return {i % numLists, local};
128 }
129private:
130 static std::atomic_uint32_t ticket;
131 static const unsigned outside = 0xFFFFFFFF;
132
133 static inline unsigned calc_preferred() {
134 unsigned t = ticket++;
135 if(t == 0) return outside;
136 unsigned i = 4 * (t - 1);
137 return i;
138 }
139
140 static __attribute__((aligned(128))) thread_local struct TLS {
141 Random rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
142 Random rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
143 Random rng3 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
144 unsigned my_queue = calc_preferred();
145 struct {
146 struct {
147 size_t attempt = 0;
148 size_t success = 0;
149 } push;
150 struct {
151 size_t attempt = 0;
152 size_t success = 0;
153 size_t empty = 0;
154 size_t locked = 0;
155 size_t both = 0;
156 } pop;
157 } stats;
158 } tls;
159public:
160 static const char * name() {
161 return "Dynamic Entropy List";
162 }
163
164public:
165 static struct GlobalStats {
166 struct {
167 std::atomic_size_t attempt = 0;
168 std::atomic_size_t success = 0;
169 } push;
170 struct {
171 std::atomic_size_t attempt = 0;
172 std::atomic_size_t success = 0;
173 std::atomic_size_t empty = 0;
174 std::atomic_size_t locked = 0;
175 std::atomic_size_t both = 0;
176 } pop;
177 } global_stats;
178 static void stats_tls_tally() {
179 global_stats.push.attempt += tls.stats.push.attempt;
180 global_stats.push.success += tls.stats.push.success;
181 global_stats.pop .attempt += tls.stats.pop.attempt;
182 global_stats.pop .success += tls.stats.pop.success;
183 global_stats.pop .empty += tls.stats.pop.empty;
184 global_stats.pop .locked += tls.stats.pop.locked;
185 global_stats.pop .both += tls.stats.pop.both;
186 }
187
188 static void stats_print(std::ostream & os, double) {
189 const auto & global = global_stats;
190
191 double push_sur = (100.0 * double(global.push.success) / global.push.attempt);
192 double pop_sur = (100.0 * double(global.pop .success) / global.pop .attempt);
193
194 double push_len = double(global.push.attempt ) / global.push.success;
195 double pop_len = double(global.pop .attempt ) / global.pop .success;
196
197 os << "Push Pick : " << push_sur << " %, len " << push_len << " (" << global.push.attempt << " / " << global.push.success << ")\n";
198 os << "Pop Pick : " << pop_sur << " %, len " << pop_len << " (" << global.pop .attempt << " / " << global.pop .success << ")\n";
199 os << "Pop Fails : " << global_stats.pop .empty << "e, " << global_stats.pop .locked << "l, " << global_stats.pop .both << "\n";
200 }
201};
Note: See TracBrowser for help on using the repository browser.