Galois
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Termination.h
Go to the documentation of this file.
1 /*
2  * This file belongs to the Galois project, a C++ library for exploiting
3  * parallelism. The code is being released under the terms of the 3-Clause BSD
4  * License (a copy is located in LICENSE.txt at the top-level directory).
5  *
6  * Copyright (C) 2018, The University of Texas at Austin. All rights reserved.
7  * UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS
8  * SOFTWARE AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY,
9  * FITNESS FOR ANY PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF
10  * PERFORMANCE, AND ANY WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF
11  * DEALING OR USAGE OF TRADE. NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH
12  * RESPECT TO THE USE OF THE SOFTWARE OR DOCUMENTATION. Under no circumstances
13  * shall University be liable for incidental, special, indirect, direct or
14  * consequential damages or loss of profits, interruption of business, or
15  * related expenses which may arise from use of Software or Documentation,
16  * including but not limited to those resulting from defects in Software and/or
17  * Documentation, or loss or inaccuracy of data of any kind.
18  */
19 
20 #ifndef GALOIS_SUBSTRATE_TERMINATION_H
21 #define GALOIS_SUBSTRATE_TERMINATION_H
22 
23 #include <atomic>
24 
25 #include "galois/config.h"
28 
29 namespace galois {
30 namespace substrate {
31 
32 class TerminationDetection;
33 /*
34  * returns an object. The object will be reused, but reinitialized to
35  * activeThreads
36  */
37 TerminationDetection& getSystemTermination(unsigned activeThreads);
38 
40 
42 
43 protected:
45 
49  virtual void init(unsigned activeThreads) = 0;
50 
51 public:
52  virtual ~TerminationDetection(void);
57  virtual void initializeThread() = 0;
58 
67  virtual void localTermination(bool workHappened) = 0;
68 
72  bool globalTermination() const { return globalTerm.data; }
73 };
74 
75 namespace internal {
76 // Dijkstra style 2-pass ring termination detection
77 template <typename _UNUSED = void>
78 class LocalTerminationDetection : public TerminationDetection {
79 
80  struct TokenHolder {
81  friend class TerminationDetection;
82  std::atomic<long> tokenIsBlack;
83  std::atomic<long> hasToken;
84  long processIsBlack;
85  bool lastWasWhite; // only used by the master
86  };
87 
89 
90  unsigned activeThreads;
91 
92  // send token onwards
93  void propToken(bool isBlack) {
94  unsigned id = ThreadPool::getTID();
95  TokenHolder& th = *data.getRemote((id + 1) % activeThreads);
96  th.tokenIsBlack = isBlack;
97  th.hasToken = true;
98  }
99 
100  void propGlobalTerm() { globalTerm = true; }
101 
102  bool isSysMaster() const { return ThreadPool::getTID() == 0; }
103 
104 protected:
105  virtual void init(unsigned aThreads) { activeThreads = aThreads; }
106 
107 public:
108  LocalTerminationDetection() {}
109 
110  virtual void initializeThread() {
111  TokenHolder& th = *data.getLocal();
112  th.tokenIsBlack = false;
113  th.processIsBlack = true;
114  th.lastWasWhite = true;
115  globalTerm = false;
116  if (isSysMaster())
117  th.hasToken = true;
118  else
119  th.hasToken = false;
120  }
121 
122  virtual void localTermination(bool workHappened) {
123  assert(!(workHappened && globalTerm.get()));
124  TokenHolder& th = *data.getLocal();
125  th.processIsBlack |= workHappened;
126  if (th.hasToken) {
127  if (isSysMaster()) {
128  bool failed = th.tokenIsBlack || th.processIsBlack;
129  th.tokenIsBlack = th.processIsBlack = false;
130  if (th.lastWasWhite && !failed) {
131  // This was the second success
132  propGlobalTerm();
133  return;
134  }
135  th.lastWasWhite = !failed;
136  }
137  // Normal thread or recirc by master
138  assert(!globalTerm.get() &&
139  "no token should be in progress after globalTerm");
140  bool taint = th.processIsBlack || th.tokenIsBlack;
141  th.processIsBlack = th.tokenIsBlack = false;
142  th.hasToken = false;
143  propToken(taint);
144  }
145  }
146 };
147 
148 // Dijkstra style 2-pass tree termination detection
149 template <typename _UNUSED = void>
150 class TreeTerminationDetection : public TerminationDetection {
151  static const int num = 2;
152 
153  struct TokenHolder {
154  friend class TerminationDetection;
155  // incoming from above
156  volatile long down_token;
157  // incoming from below
158  volatile long up_token[num];
159  // my state
160  long processIsBlack;
161  bool hasToken;
162  bool lastWasWhite; // only used by the master
163  int parent;
164  int parent_offset;
165  TokenHolder* child[num];
166  };
167 
168  PerThreadStorage<TokenHolder> data;
169 
170  unsigned activeThreads;
171 
172  void processToken() {
173  TokenHolder& th = *data.getLocal();
174  // int myid = LL::getTID();
175  // have all up tokens?
176  bool haveAll = th.hasToken;
177  bool black = th.processIsBlack;
178  for (int i = 0; i < num; ++i) {
179  if (th.child[i]) {
180  if (th.up_token[i] == -1)
181  haveAll = false;
182  else
183  black |= th.up_token[i];
184  }
185  }
186  // Have the tokens, propagate
187  if (haveAll) {
188  th.processIsBlack = false;
189  th.hasToken = false;
190  if (isSysMaster()) {
191  if (th.lastWasWhite && !black) {
192  // This was the second success
193  propGlobalTerm();
194  return;
195  }
196  th.lastWasWhite = !black;
197  th.down_token = true;
198  } else {
199  data.getRemote(th.parent)->up_token[th.parent_offset] = black;
200  }
201  }
202 
203  // recieved a down token, propagate
204  if (th.down_token) {
205  th.down_token = false;
206  th.hasToken = true;
207  for (int i = 0; i < num; ++i) {
208  th.up_token[i] = -1;
209  if (th.child[i])
210  th.child[i]->down_token = true;
211  }
212  }
213  }
214 
215  void propGlobalTerm() { globalTerm = true; }
216 
217  bool isSysMaster() const { return ThreadPool::getTID() == 0; }
218 
219 protected:
220  virtual void init(unsigned aThreads) { activeThreads = aThreads; }
221 
222 public:
223  TreeTerminationDetection() {}
224 
225  virtual void initializeThread() {
226  TokenHolder& th = *data.getLocal();
227  th.down_token = false;
228  for (int i = 0; i < num; ++i)
229  th.up_token[i] = false;
230  th.processIsBlack = true;
231  th.hasToken = false;
232  th.lastWasWhite = false;
233  globalTerm = false;
234  auto tid = ThreadPool::getTID();
235  th.parent = (tid - 1) / num;
236  th.parent_offset = (tid - 1) % num;
237  for (unsigned i = 0; i < num; ++i) {
238  unsigned cn = tid * num + i + 1;
239  if (cn < activeThreads)
240  th.child[i] = data.getRemote(cn);
241  else
242  th.child[i] = 0;
243  }
244  if (isSysMaster()) {
245  th.down_token = true;
246  }
247  }
248 
249  virtual void localTermination(bool workHappened) {
250  assert(!(workHappened && globalTerm.get()));
251  TokenHolder& th = *data.getLocal();
252  th.processIsBlack |= workHappened;
253  processToken();
254  }
255 };
256 
257 void setTermDetect(TerminationDetection* term);
258 } // end namespace internal
259 
260 } // namespace substrate
261 } // end namespace galois
262 
263 #endif
CacheLineStorage< std::atomic< int > > globalTerm
Definition: Termination.h:44
virtual void initializeThread()=0
Initializes the per-thread state.
virtual void localTermination(bool workHappened)=0
Process termination locally.
friend TerminationDetection & getSystemTermination(unsigned)
Definition: CacheLineStorage.h:32
bool globalTermination() const
Returns whether global termination is detected.
Definition: Termination.h:72
void init(const RangeTy &range)
Definition: Executor_ParaMeter.h:409
T & get()
Definition: CacheLineStorage.h:46
TerminationDetection & getSystemTermination(unsigned activeThreads)
Definition: Termination.cpp:35
virtual ~TerminationDetection(void)
Definition: Termination.cpp:24
static unsigned getTID()
Definition: ThreadPool.h:204
Definition: PerThreadStorage.h:88
unsigned int activeThreads
Definition: Threads.cpp:26
Definition: Termination.h:39
virtual void init(unsigned activeThreads)=0
for internal use by child classes
T data
Definition: CacheLineStorage.h:33