Merge branch 'conditionalDelivery' into charm
[charm.git] / src / conv-ccs / ccs-builtins.C
1 /*****************************************************************************
2  * A few useful built-in CCS handlers.
3  *****************************************************************************/
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <string.h>
9
10 #include "converse.h"
11 #include "ckhashtable.h"
12 #include "pup.h"
13 #include "pup_toNetwork.h"
14 #include "debug-charm.h"
15 #include "conv-ccs.h"
16 #include "sockRoutines.h"
17 #include "queueing.h"
18 #include "ccs-builtins.h"
19
20 #ifdef __MINGW_H
21 #include "process.h"
22 #endif
23
24 #if CMK_CCS_AVAILABLE
25
26 void ccs_getinfo(char *msg);
27
28 /**********************************************
29   "ccs_killport"-- takes one 4-byte big-endian port number
30     Register a "client kill port".  When this program exits,
31     it will connect to this TCP port and write "die\n\0" it.
32 */
33
34 typedef struct killPortStruct{
35   skt_ip_t ip;
36   unsigned int port;
37   struct killPortStruct *next;
38 } killPortStruct;
39 /*Only 1 kill list per node-- no Cpv needed*/
40 static killPortStruct *killList=NULL;
41
42 static void ccs_killport(char *msg)
43 {
44   killPortStruct *oldList=killList;
45   int port=ChMessageInt(*(ChMessageInt_t *)(msg+CmiReservedHeaderSize));
46   skt_ip_t ip;
47   unsigned int connPort;
48   CcsCallerId(&ip,&connPort);
49   killList=(killPortStruct *)malloc(sizeof(killPortStruct));
50   killList->ip=ip;
51   killList->port=port;
52   killList->next=oldList;
53   CmiFree(msg);
54 }
55 /*Send any registered clients kill messages before we exit*/
56 static int noMoreErrors(int c,const char *m) {return -1;}
57 extern "C" void CcsImpl_kill(void)
58 {
59   skt_set_abort(noMoreErrors);
60   while (killList!=NULL)
61   {
62     SOCKET fd=skt_connect(killList->ip,killList->port,20);
63     if (fd!=INVALID_SOCKET) {
64       skt_sendN(fd,"die\n",strlen("die\n")+1);
65       skt_close(fd);
66     }
67     killList=killList->next;
68   }
69 }
70
71 /**********************************************
72   "ccs_killpe"-- kills the executing processor
73     Used for fault-tolerance testing: terminate the processor.
74 */
75
76 #include <signal.h>
77
78 static void ccs_killpe(char *msg) {
79 #if CMK_HAS_KILL
80   kill(getpid(), 9);
81 #else
82   CmiAbort("ccs_killpe() not supported!");
83 #endif
84 }
85
86 /*************************************************
87 List interface:
88    This lets different parts of a Charm++ program register 
89 "list retrieval functions", which expose some aspect of a
90 running program.  Example lists include: all readonly globals, 
91 messages waiting in a queue, or all extant array elements.
92
93   "ccs_list_len" (4-byte character count, null-terminated ASCII string)
94 Return the number of items currently in the list at the given path.
95
96   "ccs_list_items.bin" (4-byte start, 4-byte end+1,4-byte extra
97 data count n, n-byte extra data, 4-byte character count c, c-byte
98 ASCII request string [without NULL terminator])
99 Return the given items (from start to end) of the given queue, 
100 formatted as raw network binary data.
101
102   "ccs_list_items.fmt" [parameters as for .bin]
103 Return the given items, formatted as tagged network binary data.
104
105   "ccs_list_items.txt" [parameters as for .bin]
106 Return the given items, formatted as ASCII text.
107 */
108
109 static void CpdListBoundsCheck(CpdListAccessor *l,int &lo,int &hi)
110 {
111   if (l->checkBoundary()) {
112     int len=l->getLength();
113     if (lo<0) lo=0;
114     if (hi>len) hi=len;
115   }
116 }
117
118 typedef CkHashtableTslow<const char *,CpdListAccessor *> CpdListTable_t;
119 CpvStaticDeclare(CpdListTable_t *,cpdListTable);
120
121 /**
122   Return the list at this (null-terminated ASCII) path.
123 */
124 static CpdListAccessor *CpdListLookup(const char *path)
125 {
126   CpdListAccessor *acc=CpvAccess(cpdListTable)->get(path);
127   if (acc==NULL) {
128     CmiError("CpdListAccessor> Unrecognized list path '%s'\n",path);
129     return NULL;
130   }
131   return acc;
132 }
133
134 /**
135   Return a CpdListAccessor, given a network string containing the 
136   list path.  A network string is a big-endian 32-bit "length" 
137   field, followed by a null-terminated ASCII string of that length.
138 */
139 static CpdListAccessor *CpdListLookup(const ChMessageInt_t *lenAndPath)
140 {
141   static const int CpdListMaxLen=80;
142   int len=ChMessageInt(lenAndPath[0]);
143   const char *path=(const char *)(lenAndPath+1);
144   char pathBuf[CpdListMaxLen+1]; //Temporary null-termination buffer
145   if ((len<0) || (len>CpdListMaxLen)) {
146     CmiError("CpdListAccessor> Invalid list path length %d!\n",len);
147     return NULL; //Character count is invalid
148   }
149   strncpy(pathBuf,path,len);
150   pathBuf[len]=0; //Ensure string is null-terminated
151   return CpdListLookup(pathBuf);
152 }
153
154 //CCS External access routines:
155
156 //Get the length of the given list:
157 static void CpdList_ccs_list_len(char *msg)
158 {
159   const ChMessageInt_t *req=(const ChMessageInt_t *)(msg+CmiReservedHeaderSize);
160   CpdListAccessor *acc=CpdListLookup(req);
161   if (acc!=NULL) {
162     ChMessageInt_t reply=ChMessageInt_new(acc->getLength());
163     CcsSendReply(sizeof(reply),(void *)&reply);
164   }
165   CmiFree(msg);
166 }
167
168 //Read a list contents request header:
169 //  first item to send, 4-byte network integer
170 //  last item+1 to send, 4-byte network integer
171 //  extra data length, 4-byte network integer
172 //  extra data, list-defined bytes
173 //  list path length, 4-byte network integer (character count)
174 //  list path name, null-terminated ASCII
175 static CpdListAccessor *CpdListHeader_ccs_list_items(char *msg,
176              CpdListItemsRequest &h)
177 {
178   int msgLen=CmiSize((void *)msg)-CmiReservedHeaderSize;
179   CpdListAccessor *ret=NULL;
180   const ChMessageInt_t *req=(const ChMessageInt_t *)(msg+CmiReservedHeaderSize);
181   h.lo=ChMessageInt(req[0]); // first item to send
182   h.hi=ChMessageInt(req[1]); // last item to send+1
183   h.extraLen=ChMessageInt(req[2]); // extra data length
184   if (h.extraLen>=0 
185   && ((int)(3*sizeof(ChMessageInt_t)+h.extraLen))<msgLen) {
186     h.extra=(void *)(req+3);  // extra data
187     ret=CpdListLookup((ChMessageInt_t *)(h.extraLen+(char *)h.extra));
188     if (ret!=NULL) CpdListBoundsCheck(ret,h.lo,h.hi);
189   }
190   return ret;
191 }
192
193
194 // Pup this cpd list's items under this request.
195 static void pupCpd(PUP::er &p, CpdListAccessor *acc, CpdListItemsRequest &req)
196 {
197       p.syncComment(PUP::sync_begin_array,"CpdList");
198       acc->pup(p,req);
199       p.syncComment(PUP::sync_end_array);
200 }
201
202 static void CpdList_ccs_list_items_txt(char *msg)
203 {
204   CpdListItemsRequest req;
205   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
206   if(acc == NULL) CmiPrintf("ccs-builtins> Null Accessor--bad list name (txt)\n");
207   if (acc!=NULL) {
208     int bufLen;
209     { 
210       PUP::sizerText p; pupCpd(p,acc,req); bufLen=p.size(); 
211     }
212     char *buf=new char[bufLen];
213     { 
214       PUP::toText p(buf); pupCpd(p,acc,req);
215       if (p.size()!=bufLen)
216         CmiError("ERROR! Sizing/packing length mismatch for %s list pup function!\n",
217                 acc->getPath());
218     }
219     CcsSendReply(bufLen,(void *)buf);
220     delete[] buf;
221   }
222   CmiFree(msg);
223 }
224
225 static void CpdList_ccs_list_items_set(char *msg)
226 {
227   CpdListItemsRequest req;
228   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
229   if(acc == NULL) CmiPrintf("ccs-builtins> Null Accessor--bad list name (set)\n");
230   else {
231     PUP_toNetwork_unpack p(req.extra);
232     pupCpd(p,acc,req);
233     if (p.size()!=req.extraLen)
234         CmiPrintf("Size mismatch during ccs_list_items.set: client sent %d bytes, but %d bytes used!\n",
235                 req.extraLen,p.size());
236   }
237   CmiFree(msg);
238 }
239
240 /** gather information about the machine we're currently running on */
241 void CpdMachineArchitecture(char *msg) {
242   char reply[8]; // where we store our reply
243   reply[0]=CHARMDEBUG_MAJOR;
244   reply[1]=CHARMDEBUG_MINOR;
245   // decide if we are 32 bit (1) or 64 bit (2)
246   reply[2] = 0;
247   if (sizeof(char*) == 4) reply[2] = 1;
248   else if (sizeof(char*) == 8) reply[2] = 2;
249   // decide if we are little endian (1) or big endian (2)
250   reply[3] = 0;
251   int value = 1;
252   char firstByte = *((char*)&value);
253   if (firstByte == 1) reply[3] = 1;
254   else reply[3] = 2;
255   // add the third bit if we are in bigsim
256 #if CMK_BLUEGENE_CHARM
257   reply[3] |= 4;
258 #endif
259   // get the size of an "int"
260   reply[4] = sizeof(int);
261   // get the size of an "long"
262   reply[5] = sizeof(long);
263 #if CMK_LONG_LONG_DEFINED
264   // get the size of an "long long"
265   reply[6] = sizeof(long long);
266 #else
267   // Per Filippo, the debugger will be fine with this. It should never
268   // come up, since configure didn't detect support for `long long` on
269   // the machine.
270   reply[6] = 0;
271 #endif
272   // get the size of an "bool"
273   reply[7] = sizeof(bool);
274   CcsSendReply(8, (void*)reply);
275   CmiFree(msg);
276 }
277
278 static void CpdList_ccs_list_items_fmt(char *msg)
279 {
280   CpdListItemsRequest req;
281   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
282   if (acc!=NULL) {
283     int bufLen;
284     { 
285       PUP_toNetwork_sizer ps;
286       PUP_fmt p(ps); 
287       pupCpd(p,acc,req);
288       bufLen=ps.size(); 
289     }
290     char *buf=new char[bufLen];
291     { 
292       PUP_toNetwork_pack pp(buf); 
293       PUP_fmt p(pp);
294       pupCpd(p,acc,req);
295       if (pp.size()!=bufLen)
296         CmiError("ERROR! Sizing/packing length mismatch for %s list pup function (%d sizing, %d packing)\n",
297                 acc->getPath(),bufLen,pp.size());
298     }
299     CcsSendReply(bufLen,(void *)buf);
300     delete[] buf;
301   }
302   CmiFree(msg);
303 }
304
305
306
307
308 //Introspection object-- extract a list of CpdLists!
309 class CpdList_introspect : public CpdListAccessor {
310   CpdListTable_t *tab;
311 public:
312   CpdList_introspect(CpdListTable_t *tab_) :tab(tab_) { }
313   virtual const char *getPath(void) const { return "converse/lists";}
314   virtual size_t getLength(void) const {
315     size_t len=0;
316     CkHashtableIterator *it=tab->iterator();
317     while (NULL!=it->next()) len++;
318     delete it;
319     return len;
320   }
321   virtual void pup(PUP::er &p,CpdListItemsRequest &req) {
322     CkHashtableIterator *it=tab->iterator();
323     void *objp;
324     int curObj=0;
325     while (NULL!=(objp=it->next())) {
326       if (curObj>=req.lo && curObj<req.hi) {
327         CpdListAccessor *acc=*(CpdListAccessor **)objp;
328         char *pathName=(char *)acc->getPath();
329         beginItem(p,curObj);
330         p.comment("name");
331         p(pathName,strlen(pathName));
332       }
333       curObj++;
334     }
335   }
336 };
337
338
339
340
341 #endif /*CMK_CCS_AVAILABLE*/
342 /*We have to include these virtual functions, even when CCS is
343 disabled, to avoid bizarre link-time errors.*/
344
345 CpdListAccessor::~CpdListAccessor() { }
346 CpdSimpleListAccessor::~CpdSimpleListAccessor() { }
347 const char *CpdSimpleListAccessor::getPath(void) const {return path;}
348 size_t CpdSimpleListAccessor::getLength(void) const {return length;}
349 void CpdSimpleListAccessor::pup(PUP::er &p,CpdListItemsRequest &req) 
350 {
351         for (int i=req.lo;i<req.hi;i++) {
352                 beginItem(p,i);
353                 (*pfn)(p,i);
354         }
355 }
356
357 static void CpdListBeginItem_impl(PUP::er &p,int itemNo)
358 {
359         p.syncComment(PUP::sync_item);
360 }
361
362 extern "C" void CpdListBeginItem(pup_er p,int itemNo)
363 {
364   CpdListBeginItem_impl(*(PUP::er *)p,itemNo);
365 }
366
367 void CpdListAccessor::beginItem(PUP::er &p,int itemNo)
368 {
369   CpdListBeginItem_impl(p,itemNo);
370 }
371
372 // C++ and C client API
373 void CpdListRegister(CpdListAccessor *acc)
374 #if CMK_CCS_AVAILABLE
375 {
376   CpvAccess(cpdListTable)->put(acc->getPath())=acc;
377 }
378 #else
379 { }
380 #endif
381
382 extern "C" void CpdListRegister_c(const char *path,
383             CpdListLengthFn_c len,void *lenParam,
384             CpdListItemsFn_c items,void *itemsParam,int checkBoundary)
385 #if CMK_CCS_AVAILABLE
386 {
387   CpdListRegister(new CpdListAccessor_c(path,
388              len,lenParam,items,itemsParam,checkBoundary!=0?true:false));
389 }
390 #else
391 { }
392 #endif
393
394 #if CMK_CCS_AVAILABLE
395
396
397 // Initialization       
398
399 static void CpdListInit(void) {
400   CpvInitialize(CpdListTable_t *,cpdListTable);
401   CpvAccess(cpdListTable)=new CpdListTable_t(31,0.5,
402               CkHashFunction_string,CkHashCompare_string);
403   CpdListRegister(new CpdList_introspect(CpvAccess(cpdListTable)));
404
405   CcsRegisterHandler("ccs_list_len",(CmiHandler)CpdList_ccs_list_len);
406   CcsRegisterHandler("ccs_list_items.txt",(CmiHandler)CpdList_ccs_list_items_txt);
407   CcsRegisterHandler("ccs_list_items.fmt",(CmiHandler)CpdList_ccs_list_items_fmt);
408   CcsRegisterHandler("ccs_list_items.set",(CmiHandler)CpdList_ccs_list_items_set);
409   CcsRegisterHandler("ccs_machine_architecture",(CmiHandler)CpdMachineArchitecture);
410 }
411
412 #if CMK_WEB_MODE
413 /******************************************************
414 Web performance monitoring interface:
415         Clients will register for performance data with 
416 processor 0 by calling the "perf_monitor" CCS request.  
417 Every WEB_INTERVAL (few seconds), this code
418 calls all registered web performance functions on all processors.  
419 The resulting integers are sent back to the client as a 
420 CCS reply.  
421
422 The current reply format is ASCII and rather nasty:
423 it's the string "perf" followed by space-separated list
424 of the performance functions for each processor.  By default,
425 only two performance functions are registered: the current 
426 processor utilization, in percent; and the current queue length.
427
428 The actual call sequence is:
429 CCS Client->CWebHandler->...  (processor 0)
430   ...->CWeb_Collect->... (all processors)
431 ...->CWeb_Reduce->CWeb_Deliver (processor 0 again)
432 */
433
434 #if 0
435 #  define WEBDEBUG(x) CmiPrintf x
436 #else
437 #  define WEBDEBUG(x) /*empty*/
438 #endif
439
440 #define WEB_INTERVAL 1000 /*Time, in milliseconds, between performance snapshots*/
441 #define MAXFNS 20 /*Largest number of performance functions to expect*/
442
443 typedef struct {
444         char hdr[CmiReservedHeaderSize];
445         int fromPE;/*Source processor*/
446         int perfData[MAXFNS];/*Performance numbers*/
447 } CWeb_CollectedData;
448
449 /*This needs to be made into a list of registered clients*/
450 static int hasApplet=0;
451 static CcsDelayedReply appletReply;
452
453 typedef int (*CWebFunction)(void);
454 static CWebFunction CWebPerformanceFunctionArray[MAXFNS];
455 static int CWebNoOfFns;
456 static int CWeb_ReduceIndex;
457 static int CWeb_CollectIndex;
458
459 /*Deliver the reduced web performance data to the waiting client:
460 */
461 static int collectedCount;
462 static CWeb_CollectedData **collectedValues;
463
464 static void CWeb_Deliver(void)
465 {
466   int i,j;
467
468   if (hasApplet) {
469     WEBDEBUG(("CWeb_Deliver to applet\n"));
470     /*Send the performance data off to the applet*/
471     char *reply=(char *)malloc(6+14*CmiNumPes()*CWebNoOfFns);
472     sprintf(reply,"perf");
473   
474     for(i=0; i<CmiNumPes(); i++){
475       for (j=0;j<CWebNoOfFns;j++)
476       {
477         char buf[20];
478         sprintf(buf," %d",collectedValues[i]->perfData[j]);
479         strcat(reply,buf);
480       }
481     }
482     CcsSendDelayedReply(appletReply,strlen(reply) + 1, reply);
483     free(reply);
484     hasApplet=0;
485   }
486   else
487     WEBDEBUG(("CWeb_Deliver (NO APPLET)\n"));
488   
489   /* Free saved performance data */
490   for(i = 0; i < CmiNumPes(); i++){
491     CmiFree(collectedValues[i]);
492     collectedValues[i] = 0;
493   }
494   collectedCount = 0;
495 }
496
497 /*On PE 0, this handler accumulates all the performace data
498 */
499 static void CWeb_Reduce(void *msg){
500   CWeb_CollectedData *cur,*prev;
501   int src;
502   if(CmiMyPe() != 0){
503     CmiAbort("CWeb performance data sent to wrong processor...\n");
504   }
505   WEBDEBUG(("CWeb_Reduce"));
506   cur=(CWeb_CollectedData *)msg;
507   src=cur->fromPE;
508   prev = collectedValues[src]; /* Previous value, ideally 0 */
509   collectedValues[src] = cur;
510   if(prev == 0) collectedCount++;
511   else CmiFree(prev); /*<- caused by out-of-order perf. data delivery*/
512
513   if(collectedCount == CmiNumPes()){
514     CWeb_Deliver();
515   }
516 }
517
518 /*On each PE, this handler collects the performance data
519 and sends it to PE 0.
520 */
521 static void CWeb_Collect(void)
522 {
523   CWeb_CollectedData *msg;
524   int i;
525
526   WEBDEBUG(("CWeb_Collect on %d\n",CmiMyPe()));
527   msg = (CWeb_CollectedData *)CmiAlloc(sizeof(CWeb_CollectedData));
528   msg->fromPE = CmiMyPe();
529   
530   /* Evaluate each performance function*/
531   for(i = 0; i < CWebNoOfFns; i++)
532     msg->perfData[i] = CWebPerformanceFunctionArray[i] ();
533
534   /* Send result off to node 0 */  
535   CmiSetHandler(msg, CWeb_ReduceIndex);
536   CmiSyncSendAndFree(0, sizeof(CWeb_CollectedData), msg);
537
538   /* Re-call this function after a delay */
539   CcdCallFnAfter((CcdVoidFn)CWeb_Collect, 0, WEB_INTERVAL);
540 }
541
542 extern "C" void CWebPerformanceRegisterFunction(CWebFunction fn)
543 {
544   if (CmiMyRank()!=0) return; /* Should only register from rank 0 */
545   if (CWebNoOfFns>=MAXFNS) CmiAbort("Registered too many CWebPerformance functions!");
546   CWebPerformanceFunctionArray[CWebNoOfFns] = fn;
547   CWebNoOfFns++;
548 }
549
550 /*This is called on PE 0 by clients that wish
551 to receive performance data.
552 */
553 static void CWebHandler(void){
554   if(CcsIsRemoteRequest()) {
555     static int startedCollection=0;
556     
557     WEBDEBUG(("CWebHandler request on %d\n",CmiMyPe()));    
558     hasApplet=1;
559     appletReply=CcsDelayReply();
560     
561     if(startedCollection == 0){
562       WEBDEBUG(("Starting data collection on every processor\n"));    
563       int i;
564       startedCollection=1;
565       collectedCount=0;
566       collectedValues = (CWeb_CollectedData **)malloc(sizeof(void *) * CmiNumPes());
567       for(i = 0; i < CmiNumPes(); i++)
568         collectedValues[i] = 0;
569       
570       /*Start collecting data on each processor*/
571       for(i = 0; i < CmiNumPes(); i++){
572         char *msg = (char *)CmiAlloc(CmiReservedHeaderSize);
573         CmiSetHandler(msg, CWeb_CollectIndex);
574         CmiSyncSendAndFree(i, CmiReservedHeaderSize,msg);
575       }
576     }
577   }
578 }
579
580 /** This "usage" section keeps track of percent of wall clock time
581 spent actually processing messages on each processor.   
582 It's a simple performance measure collected by the CWeb framework.
583 **/
584 struct CWebModeStats {
585 public:
586         double beginTime; ///< Start of last collection interval
587         double startTime; ///< Start of last busy time
588         double usedTime; ///< Total busy time in last collection interval
589         int PROCESSING; ///< If 1, processor is busy
590 };
591 CpvStaticDeclare(CWebModeStats *,cwebStats);
592
593 /* Called to begin a collection interval
594 */
595 static void usageReset(CWebModeStats *stats,double curWallTime)
596 {
597    stats->beginTime=curWallTime;
598    stats->usedTime = 0.;
599 }
600
601 /* Called when processor becomes busy
602 */
603 static void usageStart(CWebModeStats *stats,double curWallTime)
604 {
605    stats->startTime  = curWallTime;
606    stats->PROCESSING = 1;
607 }
608
609 /* Called when processor becomes idle
610 */
611 static void usageStop(CWebModeStats *stats,double curWallTime)
612 {
613    stats->usedTime   += curWallTime - stats->startTime;
614    stats->PROCESSING = 0;
615 }
616
617 /* Call this when the program is started
618  -> Whenever traceModuleInit would be called
619  -> -> see conv-core/convcore.c
620 */
621 static void initUsage()
622 {
623    CpvInitialize(CWebModeStats *, cwebStats);
624    CWebModeStats *stats=new CWebModeStats;
625    CpvAccess(cwebStats)=stats;
626    usageReset(stats,CmiWallTimer());
627    usageStart(stats,CmiWallTimer());
628    CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)usageStart,stats);
629    CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)usageStop,stats);    
630 }
631
632 static int getUsage(void)
633 {
634    int usage = 0;
635    double time      = CmiWallTimer();
636    CWebModeStats *stats=CpvAccess(cwebStats);
637    double totalTime = time - stats->beginTime;
638
639    if(stats->PROCESSING)
640    { /* Lock in current CPU usage */
641       usageStop(stats,time); usageStart(stats,time);
642    }
643    if(totalTime > 0.)
644       usage = (int)(0.5 + 100 *stats->usedTime/totalTime);
645    usageReset(stats,time);
646
647    return usage;
648 }
649
650 static int getSchedQlen(void)
651 {
652   return(CqsLength((Queue)CpvAccess(CsdSchedQueue)));
653 }
654
655 #endif /*CMK_WEB_MODE*/
656
657 #if ! CMK_WEB_MODE
658 static void CWeb_Invalid(void)
659 {
660   CmiAbort("Invalid web mode handler invoked!\n");
661 }
662 #endif
663
664 void CWebInit(void)
665 {
666 #if CMK_WEB_MODE
667   CcsRegisterHandler("perf_monitor", (CmiHandler)CWebHandler);
668   
669   CWeb_CollectIndex=CmiRegisterHandler((CmiHandler)CWeb_Collect);
670   CWeb_ReduceIndex=CmiRegisterHandler((CmiHandler)CWeb_Reduce);
671   
672   initUsage();
673   CWebPerformanceRegisterFunction(getUsage);
674   CWebPerformanceRegisterFunction(getSchedQlen);
675 #else
676   /* always maintain the consistent CmiHandler table */
677   /* which is good for heterogeneous clusters */
678   CmiRegisterHandler((CmiHandler)CWeb_Invalid);
679   CmiRegisterHandler((CmiHandler)CWeb_Invalid);
680 #endif
681 }
682
683
684 extern "C" void CcsBuiltinsInit(char **argv)
685 {
686   CcsRegisterHandler("ccs_getinfo",(CmiHandler)ccs_getinfo);
687   CcsRegisterHandler("ccs_killport",(CmiHandler)ccs_killport);
688   CcsRegisterHandler("ccs_killpe",(CmiHandler)ccs_killpe);
689   CWebInit();
690   CpdListInit();
691 }
692
693
694 #endif /*CMK_CCS_AVAILABLE*/
695
696 void PUP_fmt::fieldHeader(typeCode_t typeCode,int nItems) {
697     // Compute and write intro byte:
698     lengthLen_t ll;
699     if (nItems==1) ll=lengthLen_single;
700     else if (nItems<256) ll=lengthLen_byte;
701     else ll=lengthLen_int;
702     // CmiPrintf("Intro byte: l=%d t=%d\n",(int)ll,(int)typeCode);
703     byte intro=(((int)ll)<<4)+(int)typeCode;
704     p(intro);
705     // Compute and write length:
706     switch(ll) {
707     case lengthLen_single: break; // Single item
708     case lengthLen_byte: {
709         byte l=nItems;
710         p(l);
711         } break;
712     case lengthLen_int: {
713         p(nItems); 
714         } break; 
715     };
716 }
717
718 void PUP_fmt::comment(const char *message) {
719         int nItems=strlen(message);
720         fieldHeader(typeCode_comment,nItems);
721         p((char *)message,nItems);
722 }
723 void PUP_fmt::synchronize(unsigned int m) {
724         fieldHeader(typeCode_sync,1);
725         p(m);
726 }
727 void PUP_fmt::bytes(void *ptr,int n,size_t itemSize,PUP::dataType t) {
728         switch(t) {
729         case PUP::Tchar:
730         case PUP::Tuchar:
731         case PUP::Tbyte:
732                 fieldHeader(typeCode_byte,n);
733                 p.bytes(ptr,n,itemSize,t);
734                 break;
735         case PUP::Tshort: case PUP::Tint:
736         case PUP::Tushort: case PUP::Tuint:
737         case PUP::Tbool:
738                 fieldHeader(typeCode_int,n);
739                 p.bytes(ptr,n,itemSize,t);
740                 break;
741         // treat "long" and "pointer" as 8-bytes, in conformity with pup_toNetwork.C
742         case PUP::Tlong: case PUP::Tlonglong:
743         case PUP::Tulong: case PUP::Tulonglong:
744                 fieldHeader(typeCode_long,n);
745                 p.bytes(ptr,n,itemSize,t);
746                 break;
747         case PUP::Tfloat:
748                 fieldHeader(typeCode_float,n);
749                 p.bytes(ptr,n,itemSize,t);
750                 break;
751         case PUP::Tdouble: case PUP::Tlongdouble:
752                 fieldHeader(typeCode_double,n);
753                 p.bytes(ptr,n,itemSize,t);
754                 break;
755     case PUP::Tpointer:
756         fieldHeader(typeCode_pointer,n);
757         p.bytes(ptr,n,itemSize,t);
758         break;
759         default: CmiAbort("Unrecognized type code in PUP_fmt::bytes");
760         };
761 }
762
763