PFUNC 1.0
|
00001 #ifndef PFUNC_GROUP_HPP 00002 #define PFUNC_GROUP_HPP 00003 00004 00010 #include <pfunc/pfunc_common.h> 00011 #include <pfunc/exception.hpp> 00012 #include <pfunc/mutex.hpp> 00013 #include <pfunc/pfunc_atomics.h> 00014 00015 namespace pfunc { namespace detail { 00016 00020 struct group { 00021 private: 00022 ALIGN128 volatile bool barrier_phase; 00023 ALIGN128 volatile unsigned int barrier_count; 00024 volatile unsigned int rank_token; 00025 unsigned int group_id; 00026 unsigned int group_size; 00027 mutex group_lock; 00028 unsigned int type_of_barrier; 00029 PFUNC_DEFINE_EXCEPT_PTR() 00031 public: 00035 void barrier_spin () { 00036 PFUNC_START_TRY_BLOCK() 00037 while (!group_lock.trylock()); /* spin until lock acquire */ 00038 volatile bool my_phase = barrier_phase; 00039 ++barrier_count; 00040 if (barrier_count == group_size) { 00041 barrier_count = 0; 00042 barrier_phase = !barrier_phase; 00043 group_lock.unlock(); 00044 } else { 00045 group_lock.unlock(); 00046 while (my_phase == barrier_phase); /* spin until different phase */ 00047 } 00048 PFUNC_END_TRY_BLOCK() 00049 PFUNC_CATCH_AND_RETHROW(group,barrier_spin) 00050 } 00051 00052 00058 template <typename TaskManager> 00059 void barrier_steal (TaskManager& taskmgr) { 00060 PFUNC_START_TRY_BLOCK() 00061 group_lock.lock(); 00062 volatile bool my_phase = barrier_phase; 00063 ++barrier_count; 00064 if (barrier_count == group_size) { 00065 barrier_count = 0; 00066 barrier_phase = !barrier_phase; 00067 group_lock.unlock(); 00068 } else { 00069 group_lock.unlock(); 00070 while (my_phase == barrier_phase) taskmgr.progress_barrier (); 00071 } 00072 PFUNC_END_TRY_BLOCK() 00073 PFUNC_CATCH_AND_RETHROW(group,barrier_steal) 00074 } 00075 00079 unsigned int join_group () { 00080 return pfunc_fetch_and_add_32 00081 (reinterpret_cast<volatile int32_t*>(&rank_token), 1); 00082 } 00083 00087 void leave_group (void) { 00088 pfunc_fetch_and_add_32 00089 (reinterpret_cast<volatile int32_t*>(&rank_token), -1); 00090 } 00091 00095 unsigned int get_id () const { return group_id; } 00096 00101 unsigned int get_size () const { return group_size; } 00102 00106 unsigned int get_barrier() const { return type_of_barrier; } 00107 00111 void set_id (const unsigned int& gid) { group_id = gid; } 00112 00116 void set_size (const unsigned int& gsize) { group_size = gsize; } 00117 00121 void set_barrier (const unsigned int& barr) {type_of_barrier = barr;} 00122 00126 template <typename TaskManager> 00127 void barrier (TaskManager& taskmgr) { 00128 PFUNC_START_TRY_BLOCK() 00129 if (group_size > 1) { 00130 if (BARRIER_SPIN == type_of_barrier) return barrier_spin(); 00131 else if (BARRIER_STEAL == type_of_barrier) return barrier_steal(taskmgr); 00132 } else { 00133 /* If the group count is 0 or 1, no use with the barrier */ 00134 } 00135 PFUNC_END_TRY_BLOCK() 00136 PFUNC_CATCH_AND_RETHROW(group,barrier) 00137 } 00138 00142 group () : barrier_phase (false), 00143 barrier_count (0), 00144 rank_token (0), 00145 group_id (0), 00146 group_size (0), 00147 type_of_barrier (BARRIER_SPIN) 00148 PFUNC_EXCEPT_PTR_INIT() {} 00149 00156 group (const unsigned int& group_id, 00157 const unsigned int& group_size) : barrier_phase (false), 00158 barrier_count (0), 00159 rank_token (0), 00160 group_id (group_id), 00161 group_size (group_size), 00162 type_of_barrier (BARRIER_SPIN) 00163 PFUNC_EXCEPT_PTR_INIT() {} 00164 00172 group (const unsigned int& group_id, 00173 const unsigned int& group_size, 00174 const unsigned int& barrier) : barrier_phase (false), 00175 barrier_count (0), 00176 rank_token (0), 00177 group_id (group_id), 00178 group_size (group_size), 00179 type_of_barrier (barrier) 00180 PFUNC_EXCEPT_PTR_INIT() {} 00181 00185 ~group () { PFUNC_EXCEPT_PTR_CLEAR() } 00186 00187 00194 friend bool operator== (const group& one, const group& two) { 00195 return (one.group_size == two.group_size && one.group_id == two.group_id); 00196 } 00197 }; 00198 00199 } /* namespace detail */ } /* namespace pfunc */ 00200 #endif // PFUNC_GROUP_HPP