00001
00023 #ifndef GALOIS_RUNTIME_ALTCHUNKED_H
00024 #define GALOIS_RUNTIME_ALTCHUNKED_H
00025
00026 #include "Galois/FixedSizeRing.h"
00027 #include "Galois/Threads.h"
00028 #include "Galois/Runtime/PerThreadStorage.h"
00029 #include "Galois/Runtime/ll/CompilerSpecific.h"
00030 #include "Galois/Runtime/ll/PtrLock.h"
00031 #include "Galois/Runtime/mm/Mem.h"
00032 #include "WLCompileCheck.h"
00033
00034 namespace Galois {
00035 namespace WorkList {
00036
00037 struct ChunkHeader {
00038 ChunkHeader* next;
00039 ChunkHeader* prev;
00040 };
00041
00042 #if 0
00043 class AtomicChunkedDeque {
00044 Runtime::LL::PtrLock<ChunkHeader, true> head;
00045 ChunkHeader* volatile tail;
00046
00047 public:
00048
00049 void push_front(ChunkHeader* obj) {
00050 head.lock();
00051 obj->prev = 0;
00052 obj->next = head.getValue();
00053 if (obj->next)
00054 obj->next->prev = obj;
00055 if (!tail)
00056 tail = obj;
00057 head.unlock_and_set(obj);
00058 }
00059
00060 void push_back(ChunkHeader* obj) {
00061 head.lock();
00062 obj->next = 0;
00063 obj->prev = tail;
00064 if (obj->prev)
00065 obj->prev->next = obj;
00066 tail = obj;
00067 if (head.getValue())
00068 head.unlock();
00069 else
00070 head.unlock_and_set(obj);
00071 }
00072
00073 ChunkHeader* pop_back() {
00074
00075 if (!tail) return 0;
00076 head.lock();
00077 ChunkHeader* retval = tail;
00078 if (retval) {
00079 if (retval->prev)
00080 retval->prev->next = 0;
00081 tail = retval->prev;
00082 if (head.getValue() == retval)
00083 head.unlock_and_clear();
00084 else
00085 head.unlock();
00086
00087 retval->prev = retval->next = 0;
00088 return retval;
00089 } else {
00090 head.unlock();
00091 return 0;
00092 }
00093 }
00094
00095 ChunkHeader* pop_front() {
00096
00097 if (!tail) return 0;
00098 head.lock();
00099 ChunkHeader* retval = head.getValue();
00100 if (retval) {
00101 if (retval->next)
00102 retval->next->prev = 0;
00103 if (tail == retval)
00104 tail = 0;
00105 head.unlock_and_set(retval->next);
00106
00107 retval->prev = retval->next = 0;
00108 return retval;
00109 } else {
00110 head.unlock();
00111 return 0;
00112 }
00113 }
00114 };
00115 #endif
00116
00117 class AltChunkedQueue {
00118 Runtime::LL::PtrLock<ChunkHeader, true> head;
00119 ChunkHeader* tail;
00120
00121 void prepend(ChunkHeader* C) {
00122
00123 ChunkHeader* t = C;
00124 while (t->next) { t = t->next; }
00125 head.lock();
00126 t->next = head.getValue();
00127 if (!t->next)
00128 tail = t;
00129 head.unlock_and_set(C);
00130 }
00131
00132 public:
00133 AltChunkedQueue(): tail(0) { }
00134
00135 bool empty() const {
00136 return !tail;
00137 }
00138
00139 void push(ChunkHeader* obj) {
00140 head.lock();
00141 obj->next = 0;
00142 if (tail) {
00143 tail->next = obj;
00144 tail = obj;
00145 head.unlock();
00146 } else {
00147 assert(!head.getValue());
00148 tail = obj;
00149 head.unlock_and_set(obj);
00150 }
00151 }
00152
00153 ChunkHeader* pop() {
00154
00155 if (empty()) return 0;
00156
00157 head.lock();
00158 ChunkHeader* h = head.getValue();
00159 if (!h) {
00160 head.unlock();
00161 return 0;
00162 }
00163 if (tail == h) {
00164 tail = 0;
00165 assert(!h->next);
00166 head.unlock_and_clear();
00167 } else {
00168 head.unlock_and_set(h->next);
00169 h->next = 0;
00170 }
00171 return h;
00172 }
00173
00174 ChunkHeader* stealAllAndPop(AltChunkedQueue& victim) {
00175
00176 if (victim.empty()) return 0;
00177
00178 victim.head.lock();
00179 ChunkHeader* C = victim.head.getValue();
00180 if (C)
00181 victim.tail = 0;
00182 victim.head.unlock_and_clear();
00183 if (!C) return 0;
00184 ChunkHeader* retval = C;
00185 C = C->next;
00186 retval->next = 0;
00187 if (!C) return retval;
00188 prepend(C);
00189 return retval;
00190 }
00191
00192 ChunkHeader* stealHalfAndPop(AltChunkedQueue& victim) {
00193
00194 if (victim.empty()) return 0;
00195
00196 victim.head.lock();
00197 ChunkHeader* C = victim.head.getValue();
00198 ChunkHeader* ntail = C;
00199 bool count = false;
00200 while (C) {
00201 C = C->next;
00202 if (count)
00203 ntail = ntail->next;
00204 count = !count;
00205 }
00206 if (ntail) {
00207 C = ntail->next;
00208 ntail->next = 0;
00209 victim.tail = ntail;
00210 }
00211 victim.head.unlock();
00212 if (!C) return 0;
00213 ChunkHeader* retval = C;
00214 C = C->next;
00215 retval->next = 0;
00216 if (!C) return retval;
00217 prepend(C);
00218 return retval;
00219 }
00220 };
00221
00222 class AltChunkedStack {
00223 Runtime::LL::PtrLock<ChunkHeader, true> head;
00224
00225 void prepend(ChunkHeader* C) {
00226
00227 ChunkHeader* tail = C;
00228 while (tail->next) { tail = tail->next; }
00229 head.lock();
00230 tail->next = head.getValue();
00231 head.unlock_and_set(C);
00232 }
00233
00234 public:
00235 bool empty() const {
00236 return !head.getValue();
00237 }
00238
00239 void push(ChunkHeader* obj) {
00240 ChunkHeader* oldhead = 0;
00241 do {
00242 oldhead = head.getValue();
00243 obj->next = oldhead;
00244 } while (!head.CAS(oldhead, obj));
00245 }
00246
00247 ChunkHeader* pop() {
00248
00249 if (empty()) return 0;
00250
00251
00252 head.lock();
00253 ChunkHeader* retval = head.getValue();
00254 ChunkHeader* setval = 0;
00255 if (retval) {
00256 setval = retval->next;
00257 retval->next = 0;
00258 }
00259 head.unlock_and_set(setval);
00260 return retval;
00261 }
00262
00263 ChunkHeader* stealAllAndPop(AltChunkedStack& victim) {
00264
00265 if (victim.empty()) return 0;
00266
00267 victim.head.lock();
00268 ChunkHeader* C = victim.head.getValue();
00269 victim.head.unlock_and_clear();
00270 if (!C) return 0;
00271 ChunkHeader* retval = C;
00272 C = C->next;
00273 retval->next = 0;
00274 if (!C) return retval;
00275 prepend(C);
00276 return retval;
00277 }
00278
00279 ChunkHeader* stealHalfAndPop(AltChunkedStack& victim) {
00280
00281 if (victim.empty()) return 0;
00282
00283 victim.head.lock();
00284 ChunkHeader* C = victim.head.getValue();
00285 ChunkHeader* ntail = C;
00286 bool count = false;
00287 while (C) {
00288 C = C->next;
00289 if (count)
00290 ntail = ntail->next;
00291 count = !count;
00292 }
00293 if (ntail) {
00294 C = ntail->next;
00295 ntail->next = 0;
00296 }
00297 victim.head.unlock();
00298 if (!C) return 0;
00299 ChunkHeader* retval = C;
00300 C = C->next;
00301 retval->next = 0;
00302 if (!C) return retval;
00303 prepend(C);
00304 return retval;
00305 }
00306 };
00307
00308 template<typename InnerWL>
00309 class StealingQueue : private boost::noncopyable {
00310 Runtime::PerThreadStorage<std::pair<InnerWL, unsigned> > local;
00311
00312 GALOIS_ATTRIBUTE_NOINLINE
00313 ChunkHeader* doSteal() {
00314 std::pair<InnerWL, unsigned>& me = *local.getLocal();
00315 unsigned id = Runtime::LL::getTID();
00316 unsigned pkg = Runtime::LL::getPackageForSelf(id);
00317 unsigned num = Galois::getActiveThreads();
00318
00319
00320 for (unsigned eid = id + 1; eid < num; ++eid) {
00321 if (Runtime::LL::getPackageForThread(eid) == pkg) {
00322 ChunkHeader* c = me.first.stealHalfAndPop(local.getRemote(eid)->first);
00323 if (c)
00324 return c;
00325 }
00326 }
00327 for (unsigned eid = 0; eid < id; ++eid) {
00328 if (Runtime::LL::getPackageForThread(eid) == pkg) {
00329 ChunkHeader* c = me.first.stealHalfAndPop(local.getRemote(eid)->first);
00330 if (c)
00331 return c;
00332 }
00333 }
00334
00335
00336 if (Runtime::LL::isPackageLeaderForSelf(id)) {
00337 unsigned eid = (id + me.second) % num;
00338 ++me.second;
00339 if (id != eid && Runtime::LL::isPackageLeader(eid)) {
00340 ChunkHeader* c = me.first.stealAllAndPop(local.getRemote(eid)->first);
00341 if (c)
00342 return c;
00343 }
00344 }
00345 return 0;
00346 }
00347
00348 public:
00349 void push(ChunkHeader* c) {
00350 local.getLocal()->first.push(c);
00351 }
00352
00353 ChunkHeader* pop() {
00354 if (ChunkHeader* c = local.getLocal()->first.pop())
00355 return c;
00356 return doSteal();
00357 }
00358 };
00359
00360 template<bool IsLocallyLIFO, int ChunkSize, typename Container, typename T>
00361 struct AltChunkedMaster : private boost::noncopyable {
00362 template<typename _T>
00363 struct retype { typedef AltChunkedMaster<IsLocallyLIFO, ChunkSize, Container, _T> type; };
00364
00365 template<bool _concurrent>
00366 struct rethread { typedef AltChunkedMaster<IsLocallyLIFO, ChunkSize, Container, T> type; };
00367
00368 template<int _chunk_size>
00369 struct with_chunk_size { typedef AltChunkedMaster<IsLocallyLIFO, _chunk_size, Container, T> type; };
00370
00371 private:
00372 class Chunk : public ChunkHeader, public Galois::FixedSizeRing<T, ChunkSize> {};
00373
00374 Runtime::MM::FixedSizeAllocator heap;
00375 Runtime::PerThreadStorage<std::pair<Chunk*, Chunk*> > data;
00376 Container worklist;
00377
00378 Chunk* mkChunk() {
00379 return new (heap.allocate(sizeof(Chunk))) Chunk();
00380 }
00381
00382 void delChunk(Chunk* C) {
00383 C->~Chunk();
00384 heap.deallocate(C);
00385 }
00386
00387 void swapInPush(std::pair<Chunk*, Chunk*>& d) {
00388 if (!IsLocallyLIFO)
00389 std::swap(d.first, d.second);
00390 }
00391
00392 Chunk*& getPushChunk(std::pair<Chunk*, Chunk*>& d) {
00393 if (!IsLocallyLIFO)
00394 return d.second;
00395 else
00396 return d.first;
00397 }
00398
00399 Chunk*& getPopChunk(std::pair<Chunk*, Chunk*>& d) {
00400 return d.first;
00401 }
00402
00403 bool doPush(Chunk* c, const T& val) {
00404 return c->push_back(val);
00405 }
00406
00407 Galois::optional<T> doPop(Chunk* c) {
00408 if (!IsLocallyLIFO)
00409 return c->extract_front();
00410 else
00411 return c->extract_back();
00412 }
00413
00414 void push_internal(std::pair<Chunk*, Chunk*>& tld, Chunk*& n, const T& val) {
00415
00416 if (n && doPush(n, val))
00417 return;
00418
00419 if (n)
00420 worklist.push(static_cast<ChunkHeader*>(n));
00421
00422 n = mkChunk();
00423
00424 doPush(n, val);
00425 }
00426
00427 public:
00428 typedef T value_type;
00429
00430 AltChunkedMaster() : heap(sizeof(Chunk)) {}
00431
00432 void push(value_type val) {
00433 std::pair<Chunk*, Chunk*>& tld = *data.getLocal();
00434 Chunk*& n = getPushChunk(tld);
00435 push_internal(tld, n, val);
00436 }
00437
00438 template<typename Iter>
00439 void push(Iter b, Iter e) {
00440 std::pair<Chunk*, Chunk*>& tld = *data.getLocal();
00441 Chunk*& n = getPushChunk(tld);
00442 while (b != e)
00443 push_internal(tld, n, *b++);
00444 }
00445
00446 template<typename RangeTy>
00447 void push_initial(const RangeTy& range) {
00448 auto rp = range.local_pair();
00449 push(rp.first, rp.second);
00450 }
00451
00452 Galois::optional<value_type> pop() {
00453 std::pair<Chunk*, Chunk*>& tld = *data.getLocal();
00454 Chunk*& n = getPopChunk(tld);
00455 Galois::optional<value_type> retval;
00456
00457 if (n && (retval = doPop(n)))
00458 return retval;
00459
00460 if (n)
00461 delChunk(n);
00462
00463 n = static_cast<Chunk*>(worklist.pop());
00464 if (n && (retval = doPop(n)))
00465 return retval;
00466
00467 swapInPush(tld);
00468 if (n)
00469 retval = doPop(n);
00470 return retval;
00471 }
00472 };
00473
00474 template<int ChunkSize=64, typename T = int>
00475 class AltChunkedLIFO : public AltChunkedMaster<true, ChunkSize, StealingQueue<AltChunkedStack>, T> {};
00476 GALOIS_WLCOMPILECHECK(AltChunkedLIFO)
00477
00478 template<int ChunkSize=64, typename T = int>
00479 class AltChunkedFIFO : public AltChunkedMaster<false, ChunkSize, StealingQueue<AltChunkedQueue>, T> {};
00480 GALOIS_WLCOMPILECHECK(AltChunkedFIFO)
00481
00482 }
00483 }
00484 #endif