The new version of comlib! This version passed "make test" in charm/tests on order...
[charm.git] / src / conv-com / convcomlibstrategy.h
1
2
3 /**
4    @addtogroup ConvComlib
5    @{
6    @file
7    
8    @brief Converse Strategy This file contains the main declarations for
9    converse strategies. This include the classes Strategy, MessageHolder and
10    StrategyWrapper.
11    
12    This file is the lowest in the inclusion chain of comlib, so it is included
13    in all other pars of comlib.
14    
15    Heavily revised, Filippo Gioachin 01/06
16 */
17
18 #ifndef CONVCOMLIBSTRATEGY_H
19 #define CONVCOMLIBSTRATEGY_H
20
21 // FILIPPO: TEMPORARY HACK
22 #ifndef COMLIBSTRATEGY_H
23 #define CkpvDeclare CpvDeclare
24 #define CkpvAccess CpvAccess
25 #define CkpvExtern CpvExtern
26 #define CkpvInitialize CpvInitialize
27 #define CkpvInitialized CpvInitialized
28 #define CkMyPe CmiMyPe
29 #define CkNumPes CmiNumPes
30 #undef CkRegisterHandler
31 #define CkRegisterHandler(x) CmiRegisterHandler(x)
32 #endif
33
34
35
36
37
38 #include "converse.h"
39 #include "pup.h"
40 #include "cklists.h"
41 #include <set>
42
43 /***************************************************************
44  * Definitions used by the strategies as constants plus information to
45  * debug comlib.
46  * Copied from old convcomlib.h - Filippo
47  ****************************************************************/
48 extern int com_debug;
49 #ifdef CMK_OPTIMIZE
50 inline void ComlibPrintf(...) {}
51 #else
52 #define ComlibPrintf if(com_debug) CmiPrintf
53 //#define ComlibPrintf  CmiPrintf
54 #endif
55
56 #define USE_TREE 1            //Organizes the all to all as a tree
57 #define USE_MESH 2            //Virtual topology is a mesh here
58 #define USE_HYPERCUBE 3       //Virtual topology is a hypercube
59 #define USE_DIRECT 4          //A dummy strategy that directly forwards 
60                               //messages without any processing.
61 #define USE_GRID 5            //Virtual topology is a 3d grid
62 #define USE_LINEAR 6          //Virtual topology is a linear array
63 #define USE_PREFIX 7          //Prefix router to avoid contention
64
65 #define IS_BROADCAST -1
66 #define IS_SECTION_MULTICAST -2
67
68 /** This class is a handle for a strategy, used and passed by the user to comlib
69     funcions that need it. Whenever necessary, the system can create additional
70     handles used for specific purposes starting from an instance of this class.
71     At the moment it is simply a typedef to an int.
72  */
73 typedef int ComlibInstanceHandle;
74
75
76 /** An abstract data structure that holds a converse message and which can be
77     buffered by the communication library Message holder is a wrapper around a
78     message. Has other useful data like destination processor list for a
79     multicast etc. */
80
81 class MessageHolder : public PUP::able {
82  public:
83     char *data;
84     int size;
85     int isDummy;
86     
87     //For multicast, the user can pass the pelist and list of Pes he
88     //wants to send the data to.
89
90     /** npes=0 means broadcast, npes=1 means one destination specified by
91         dest_proc, npes>1 means multicast with destinations specified in the
92         array pelist */
93     int npes;
94     union {
95       int *pelist;
96       int dest_proc;
97     };
98     
99     MessageHolder() 
100         {dest_proc = size = isDummy = 0; data = NULL;}    
101
102     MessageHolder(CkMigrateMessage *m) {}
103
104     /// Single destination constructor
105     inline MessageHolder(char * msg, int sz, int proc) {
106         data = msg;
107         size = sz;
108
109         npes = 1;
110         dest_proc = proc;
111         
112         isDummy = 0;
113     }
114
115     /// Broadcast constructor
116     inline MessageHolder(char * msg, int sz) {
117         data = msg;
118         size = sz;
119
120         npes = 0;
121         dest_proc = 0;
122         
123         isDummy = 0;
124     }
125
126     /// Multicast constructor
127     inline MessageHolder(char * msg, int sz, int np, int *pes) {
128         data = msg;
129         size = sz;
130
131         npes = np;
132         pelist = pes;
133         
134         isDummy = 0;
135     }
136
137     inline ~MessageHolder() {
138         /*
139           if(pelist != NULL && npes > 0)
140           delete[] pelist;
141         */
142     }
143
144     inline char * getMessage() {
145         return data;
146     }
147
148     inline int getSize() {
149       return size;
150     }
151
152     inline void * operator new(size_t size) {
153         return CmiAlloc(size);
154     }
155
156     inline void operator delete (void *buf) {
157         CmiFree(buf);
158     }
159
160     virtual void pup(PUP::er &p);
161     PUPable_decl(MessageHolder);
162 };
163
164 // These should not be here by in Charm!!
165 #define CONVERSE_STRATEGY 0     //The strategy works for converse programs
166 #define NODEGROUP_STRATEGY 1    //Node group level optimizations 
167 #define GROUP_STRATEGY 2        //Charm Processor level optimizations
168 #define ARRAY_STRATEGY 3        //Array level optimizations
169
170 /** Class that defines the entry methods that a Converse level strategy must
171     define. To write a new strategy inherit from this class and define the
172     virtual methods. Every strategy can also define its own constructor and
173     have any number of arguments. */
174
175 class Strategy : public PUP::able {
176  protected:
177
178
179     short type;
180     /// 1 if the strategy is bracketed, 0 otherwise
181     short isStrategyBracketed;
182     //int myInstanceID; DEPRECATED in favor of myHandle / A handle used by the
183     //user to identify this strategy. This is a wrapper to the real handle which
184     //is virtual.
185     ComlibInstanceHandle myHandle;
186     /* Used for pure converse strategies which need to deliver their message
187         directly to a converse handler (and not to higher languages). This will
188         be used as final deliverer. */
189     // DEPRECATED! The destination should be read from the header of the envelope
190     //int destinationHandler;
191
192     inline int getInstance() {return myHandle;}
193
194  public:
195     Strategy();
196     Strategy(CkMigrateMessage *m) : PUP::able(m) {
197       // By default assume that the class is self contained, if a higher
198       // language class desires, it can change the following two fields.
199       //converseStrategy = this;
200       //higherLevel = this;
201     }
202
203     // Is the knowledge of bracketized necessary? Currently it is used only to
204     // register the strategy to the ComlibArrayListener...
205     inline void setBracketed(){isStrategyBracketed = 1;}
206     inline int isBracketed(){return isStrategyBracketed;}
207
208     //virtual void bracketedCountingError() {}
209
210     /// This function is called to update the knowledge hold by a strategy which
211     /// cares about migratable objects. count is of size CkNumPes() and has the
212     /// following format:
213     /// 0 if proc "i" has no objects,
214     /// 1 if proc "i" has only source objects,
215     /// 2 if proc "i" has only destination objects,
216     /// 3 if proc "i" has both source and destination objects
217     virtual void bracketedUpdatePeKnowledge(int *count) {}
218
219     /// Called for each message
220     virtual void insertMessage(MessageHolder *msg)=0;// {}
221     
222     /** Called after all messages have been deposited in this processor. This
223         corresponds to a call to ComlibEnd(cinst), where cinst is the
224         ComlibInstanceHandle returned when registering the Strategy with Comlib.
225         In higher levels this may need many ComlibEnd calls before invoking
226         doneInserting. */
227     virtual void doneInserting() {}
228
229     //inline void setInstance(int instid){myInstanceID = instid;}
230     //inline int getInstance(){return myInstanceID;}
231
232     inline int getType() {return type;}
233     // TO DEPRECATE! we shouldn't change the type after creation
234     inline void setType(int t) {type = t;}
235
236     /// Return a handle to this strategy
237     ComlibInstanceHandle getHandle() {return myHandle;}
238
239     /** Called when a message is received in the strategy handler */
240     virtual void handleMessage(void *msg)=0;// {}
241     
242     /** This method can be used to deliver a message through the correct class */
243     virtual void deliver(char* msg, int size) {
244       CmiAbort("Strategy::deliverer: If used, should be first redefined\n");
245     };
246
247     /** Called when a subsystem scheme (like in bracketed EachToMany) terminates
248         the requested routing operation */
249     virtual void notifyDone() {}
250
251     /** Called on processor 0 after the strategy has been packed for
252         propagation. In this way the strategy can leave some portion not fully
253         initialized and initialize it after it has been packed. This gives the
254         possibility to propagate some data everywhere before doing processor
255         specific handling. */
256     virtual void finalizeCreation() {}
257
258     /** Each strategy must define his own Pup interface. */
259     virtual void pup(PUP::er &p);
260     //PUPable_decl(Strategy);
261     PUPable_abstract(Strategy);
262 };
263
264 /** Enables a list of strategies to be stored in a message through the PUPable
265     framework. */
266 class StrategyWrapper {
267  public:
268   Strategy **strategy;
269   int *position;
270   CmiBool *replace;
271   int nstrats;
272   //int total_nstrats;
273
274   StrategyWrapper() : nstrats(0), position(NULL), strategy(NULL) {}
275   StrategyWrapper(int count);
276   ~StrategyWrapper();
277   void pup(PUP::er &p);
278 };
279
280
281
282 /// Definition of error modes that are used when detecting migration of elements for a strategy
283 enum CountingErrorMode { NORMAL_MODE = 0, 
284                          ERROR_MODE = 1, 
285                          CONFIRM_MODE = 2,   
286                          ERROR_FIXED_MODE = 3  };
287
288 enum CountingServerErrorMode { STARTUP_MODE_SERVER = 100,
289                                NORMAL_MODE_SERVER, 
290                                ERROR_MODE_SERVER,
291                                CONFIRM_MODE_SERVER,  
292                                ERROR_FIXED_MODE_SERVER,
293                                NON_SERVER_MODE_SERVER    };
294
295
296 enum DiscoveryErrorMode { NORMAL_DISCOVERY_MODE = 200, 
297                           STARTED_DISCOVERY_MODE = 201, 
298                           FINISHED_DISCOVERY_MODE = 202   };
299
300 /** Information about each instance of a strategy.
301  
302     Each StrategyTableEntry points to a strategy, as well as containing 
303     information about which state the strategy instance is in.
304
305     Strategies can change during the execution of the program but the
306     StrategyTableEntry stores some persistent information for the
307     strategy. The communication library on receiving a message, calls
308     the strategy in this table given by the strategy id in the message.
309     
310     With the philosophy that strategies are not recreated, but only updated
311         during the execution of the program, this struct should be useless?
312 */
313
314 class StrategyTableEntry {
315 public:
316   Strategy *strategy;
317
318   /// A flag to specify if the strategy is active or suspended
319   int isReady;
320   /// A flag to specify if the strategy is newly created and not yet synchronized
321   int isNew;
322   /// A flag to specify if the strategy is currently being synchronized
323   int isInSync;
324
325   
326   /** 
327    A flag that specifies whether outgoing messages should be buffered, 
328    currently only used in the bracketed strategies when an error has been 
329    detected. Once the error has been corrected, no longer are the outgoing messages 
330    buffered.
331    
332    errorDelaySendBuffer (see below) is the name of the queue of messages buffered 
333    while this variable is 1.
334    
335    Currently the following methods respect the wishes of this variable: 
336                 ComlibManager::multicast()
337     
338   */
339   int bufferOutgoing;
340   
341   
342   /** 
343    A flag to specify that this bracketed strategy is in an error mode,
344    due to an object migration causing more objects to call BeginIteration 
345    on one of the PEs than was expected. The detecting PE immediately enter the error
346    mode state, while other PEs will be notified of the error, and they will then 
347    enter the error state.
348    
349    This flag represents the state of the DFA followed by all processors. See the
350    hand drawn document describing these states and their transitions.
351       
352    There are three stated:
353      0) Normal mode: everything is fine
354      1) Error mode: miscount detected, trying to fix it
355      2) Confirm mode: a count has matched, trying to confirm it
356   
357   */
358   CountingErrorMode errorMode;
359   
360   /** 
361    The state of the coordinator (PE 0 of the a chare group).
362   */
363   CountingServerErrorMode errorModeServer;
364   
365   
366   /// A flag to specify what stage of Discovery process is underway for the PE
367   DiscoveryErrorMode discoveryMode;
368   
369
370   /// A flag to specify that the bracketed strategy is fully setup, and it can operate normally.
371   /// A value of 0 means strategy is fully setup
372   int bracketedSetupFinished;
373
374   /// A buffer for all the messages to this strategy while the strategy is suspended
375   CkQ<MessageHolder*> tmplist;
376
377   int numBufferReleaseReady;
378   
379   int numElements;   //< Count how many src(?) elements reside here
380
381   //    Used to ensure strategies work in presence of migration
382   int nBeginItr;     //< #elements that called begin iteration
383   int nEndItr;       //< #elements that called end iteration
384   int call_doneInserting; //< All elements deposited their data
385
386
387   int lastKnownIteration;
388
389   // values used during bracketed error/confirm mode
390   int nEndSaved;        //< during error mode, number sent to processor 0
391   int totalEndCounted;  //< on processor 0, total amount of endIterations counted
392   int nProcSync;         //< on processor 0, number of processors already in the count
393
394   // values used during the discovery process to count the number of objects
395   // valid only on processor 0
396
397   /// list of where objects are, will be broadcasted at the end, the list is
398   /// CkNumPes() elements long + 2. These two elements are: peList[CkNumPes()]
399   /// number of source objects discovered, peList[CkNumPes()+1] number of
400   /// destination objects discovered. This trick eliminates two integer
401   /// variables
402   int *peList;
403   
404   
405   /// The number of PEs that have confirmed the count to ComlibManager::bracketedCountConfirmed
406   int peConfirmCounter;
407   /// This was formerly a static variable in ComlibManager::bracketedCountConfirmed()
408   int total; 
409  
410   
411   void reset();
412   
413
414   char *errorModeString();
415   char *errorModeServerString();
416   char *discoveryModeString();
417
418
419   StrategyTableEntry();
420   
421 };
422
423 typedef CkVec<StrategyTableEntry> StrategyTable;
424
425
426 #endif
427
428 /*@}*/