00001
00028 #ifndef GALOIS_RUNTIME_DOALL_H
00029 #define GALOIS_RUNTIME_DOALL_H
00030
00031 #include "Galois/gstl.h"
00032 #include "Galois/Statistic.h"
00033 #include "Galois/Runtime/Barrier.h"
00034 #include "Galois/Runtime/Support.h"
00035 #include "Galois/Runtime/Range.h"
00036 #include "Galois/Runtime/ForEachTraits.h"
00037
00038 #include <algorithm>
00039
00040 namespace Galois {
00041 namespace Runtime {
00042
00043 struct EmptyFn {
00044 template<typename T>
00045 void operator()(T a, T b) {}
00046 };
00047
00048
00049
00050 template<class FunctionTy, class ReduceFunTy, class RangeTy>
00051 class DoAllWork {
00052 typedef typename RangeTy::local_iterator local_iterator;
00053 LL::SimpleLock<true> reduceLock;
00054 FunctionTy origF;
00055 FunctionTy outputF;
00056 ReduceFunTy RF;
00057 RangeTy range;
00058 Barrier& barrier;
00059 bool needsReduce;
00060 bool useStealing;
00061
00062 struct SharedState {
00063 local_iterator stealBegin;
00064 local_iterator stealEnd;
00065 LL::SimpleLock<true> stealLock;
00066 };
00067
00068 struct PrivateState {
00069 local_iterator begin;
00070 local_iterator end;
00071 FunctionTy F;
00072 PrivateState(FunctionTy& o) :F(o) {}
00073 };
00074
00075 PerThreadStorage<SharedState> TLDS;
00076
00078 void processRange(PrivateState& tld) {
00079 for (; tld.begin != tld.end; ++tld.begin)
00080 tld.F(*tld.begin);
00081 }
00082
00083 bool doSteal(SharedState& source, PrivateState& dest) {
00084
00085 if (source.stealBegin != source.stealEnd) {
00086 source.stealLock.lock();
00087 if (source.stealBegin != source.stealEnd) {
00088 dest.begin = source.stealBegin;
00089 source.stealBegin = dest.end = Galois::split_range(source.stealBegin, source.stealEnd);
00090 }
00091 source.stealLock.unlock();
00092 }
00093 return dest.begin != dest.end;
00094 }
00095
00096 void populateSteal(PrivateState& tld, SharedState& tsd) {
00097 if (tld.begin != tld.end && std::distance(tld.begin, tld.end) > 1) {
00098 tsd.stealLock.lock();
00099 tsd.stealEnd = tld.end;
00100 tsd.stealBegin = tld.end = Galois::split_range(tld.begin, tld.end);
00101 tsd.stealLock.unlock();
00102 }
00103 }
00104
00105 GALOIS_ATTRIBUTE_NOINLINE
00106 bool trySteal(PrivateState& mytld) {
00107
00108 if (doSteal(*TLDS.getLocal(), mytld))
00109 return true;
00110
00111 unsigned myID = LL::getTID();
00112 for (unsigned x = 1; x < activeThreads; x += x) {
00113 SharedState& r = *TLDS.getRemote((myID + x) % activeThreads);
00114 if (doSteal(r, mytld)) {
00115
00116 return true;
00117 }
00118 }
00119 return false;
00120 }
00121
00122 void doReduce(PrivateState& mytld) {
00123 if (needsReduce) {
00124 reduceLock.lock();
00125 RF(outputF, mytld.F);
00126 reduceLock.unlock();
00127 }
00128 }
00129
00130 public:
00131 DoAllWork(const FunctionTy& F, const ReduceFunTy& R, bool needsReduce, RangeTy r, bool steal)
00132 : origF(F), outputF(F), RF(R), range(r), barrier(getSystemBarrier()), needsReduce(needsReduce), useStealing(steal)
00133 { }
00134
00135 void operator()() {
00136
00137 PrivateState thisTLD(origF);
00138 thisTLD.begin = range.local_begin();
00139 thisTLD.end = range.local_end();
00140
00141 if (useStealing) {
00142 populateSteal(thisTLD, *TLDS.getLocal());
00143
00144
00145
00146 barrier.wait();
00147 }
00148
00149 do {
00150 processRange(thisTLD);
00151 } while (useStealing && trySteal(thisTLD));
00152
00153 doReduce(thisTLD);
00154 }
00155
00156 FunctionTy getFn() const { return outputF; }
00157 };
00158
00159 template<typename RangeTy, typename FunctionTy, typename ReducerTy>
00160 FunctionTy do_all_dispatch(RangeTy range, FunctionTy f, ReducerTy r, bool doReduce, const char* loopname, bool steal) {
00161 if (Galois::Runtime::inGaloisForEach) {
00162 return std::for_each(range.begin(), range.end(), f);
00163 } else {
00164
00165 StatTimer LoopTimer("LoopTime", loopname);
00166 if (ForEachTraits<FunctionTy>::NeedsStats)
00167 LoopTimer.start();
00168
00169 inGaloisForEach = true;
00170
00171 DoAllWork<FunctionTy, ReducerTy, RangeTy> W(f, r, doReduce, range, steal);
00172 RunCommand w[2] = {std::ref(W),
00173 std::ref(getSystemBarrier())};
00174 getSystemThreadPool().run(&w[0], &w[2],activeThreads);
00175 if (ForEachTraits<FunctionTy>::NeedsStats)
00176 LoopTimer.stop();
00177 inGaloisForEach = false;
00178 return W.getFn();
00179 }
00180 }
00181
00182 template<typename RangeTy, typename FunctionTy>
00183 FunctionTy do_all_impl(RangeTy range, FunctionTy f, const char* loopname = 0, bool steal = false) {
00184 return do_all_dispatch(range, f, EmptyFn(), false, loopname, steal);
00185 }
00186
00187 template<typename RangeTy, typename FunctionTy, typename ReduceTy>
00188 FunctionTy do_all_impl(RangeTy range, FunctionTy f, ReduceTy r, const char* loopname = 0, bool steal = false) {
00189 return do_all_dispatch(range, f, r, true, loopname, steal);
00190 }
00191
00192 }
00193 }
00194
00195 #endif // GALOIS_RUNTIME_DOALL_H