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