Moved CcsReply to middle-ccs so it works both in bigsim and in normal 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[6]; // where we store our reply
243   // decide if we are 32 bit (1) or 64 bit (2)
244   reply[0] = 0;
245   if (sizeof(char*) == 4) reply[0] = 1;
246   else if (sizeof(char*) == 8) reply[0] = 2;
247   // decide if we are little endian (1) or big endian (2)
248   reply[1] = 0;
249   int value = 1;
250   char firstByte = *((char*)&value);
251   if (firstByte == 1) reply[1] = 1;
252   else reply[1] = 2;
253   // add the third bit if we are in bigsim
254 #if CMK_BLUEGENE_CHARM
255   reply[1] |= 4;
256 #endif
257   // get the size of an "int"
258   reply[2] = sizeof(int);
259   // get the size of an "long"
260   reply[3] = sizeof(long);
261 #if CMK_LONG_LONG_DEFINED
262   // get the size of an "long long"
263   reply[4] = sizeof(long long);
264 #else
265   // Per Filippo, the debugger will be fine with this. It should never
266   // come up, since configure didn't detect support for `long long` on
267   // the machine.
268   reply[4] = 0;
269 #endif
270   // get the size of an "bool"
271   reply[5] = sizeof(bool);
272   CcsSendReply(6, (void*)reply);
273   CmiFree(msg);
274 }
275
276 static void CpdList_ccs_list_items_fmt(char *msg)
277 {
278   CpdListItemsRequest req;
279   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
280   if (acc!=NULL) {
281     int bufLen;
282     { 
283       PUP_toNetwork_sizer ps;
284       PUP_fmt p(ps); 
285       pupCpd(p,acc,req);
286       bufLen=ps.size(); 
287     }
288     char *buf=new char[bufLen];
289     { 
290       PUP_toNetwork_pack pp(buf); 
291       PUP_fmt p(pp);
292       pupCpd(p,acc,req);
293       if (pp.size()!=bufLen)
294         CmiError("ERROR! Sizing/packing length mismatch for %s list pup function (%d sizing, %d packing)\n",
295                 acc->getPath(),bufLen,pp.size());
296     }
297     CcsSendReply(bufLen,(void *)buf);
298     delete[] buf;
299   }
300   CmiFree(msg);
301 }
302
303
304
305
306 //Introspection object-- extract a list of CpdLists!
307 class CpdList_introspect : public CpdListAccessor {
308   CpdListTable_t *tab;
309 public:
310   CpdList_introspect(CpdListTable_t *tab_) :tab(tab_) { }
311   virtual const char *getPath(void) const { return "converse/lists";}
312   virtual size_t getLength(void) const {
313     size_t len=0;
314     CkHashtableIterator *it=tab->iterator();
315     while (NULL!=it->next()) len++;
316     delete it;
317     return len;
318   }
319   virtual void pup(PUP::er &p,CpdListItemsRequest &req) {
320     CkHashtableIterator *it=tab->iterator();
321     void *objp;
322     int curObj=0;
323     while (NULL!=(objp=it->next())) {
324       if (curObj>=req.lo && curObj<req.hi) {
325         CpdListAccessor *acc=*(CpdListAccessor **)objp;
326         char *pathName=(char *)acc->getPath();
327         beginItem(p,curObj);
328         p.comment("name");
329         p(pathName,strlen(pathName));
330       }
331       curObj++;
332     }
333   }
334 };
335
336
337
338
339 #endif /*CMK_CCS_AVAILABLE*/
340 /*We have to include these virtual functions, even when CCS is
341 disabled, to avoid bizarre link-time errors.*/
342
343 CpdListAccessor::~CpdListAccessor() { }
344 CpdSimpleListAccessor::~CpdSimpleListAccessor() { }
345 const char *CpdSimpleListAccessor::getPath(void) const {return path;}
346 size_t CpdSimpleListAccessor::getLength(void) const {return length;}
347 void CpdSimpleListAccessor::pup(PUP::er &p,CpdListItemsRequest &req) 
348 {
349         for (int i=req.lo;i<req.hi;i++) {
350                 beginItem(p,i);
351                 (*pfn)(p,i);
352         }
353 }
354
355 static void CpdListBeginItem_impl(PUP::er &p,int itemNo)
356 {
357         p.syncComment(PUP::sync_item);
358 }
359
360 extern "C" void CpdListBeginItem(pup_er p,int itemNo)
361 {
362   CpdListBeginItem_impl(*(PUP::er *)p,itemNo);
363 }
364
365 void CpdListAccessor::beginItem(PUP::er &p,int itemNo)
366 {
367   CpdListBeginItem_impl(p,itemNo);
368 }
369
370 // C++ and C client API
371 void CpdListRegister(CpdListAccessor *acc)
372 #if CMK_CCS_AVAILABLE
373 {
374   CpvAccess(cpdListTable)->put(acc->getPath())=acc;
375 }
376 #else
377 { }
378 #endif
379
380 extern "C" void CpdListRegister_c(const char *path,
381             CpdListLengthFn_c len,void *lenParam,
382             CpdListItemsFn_c items,void *itemsParam,int checkBoundary)
383 #if CMK_CCS_AVAILABLE
384 {
385   CpdListRegister(new CpdListAccessor_c(path,
386              len,lenParam,items,itemsParam,checkBoundary!=0?true:false));
387 }
388 #else
389 { }
390 #endif
391
392 #if CMK_CCS_AVAILABLE
393
394
395 // Initialization       
396
397 static void CpdListInit(void) {
398   CpvInitialize(CpdListTable_t *,cpdListTable);
399   CpvAccess(cpdListTable)=new CpdListTable_t(31,0.5,
400               CkHashFunction_string,CkHashCompare_string);
401   CpdListRegister(new CpdList_introspect(CpvAccess(cpdListTable)));
402
403   CcsRegisterHandler("ccs_list_len",(CmiHandler)CpdList_ccs_list_len);
404   CcsRegisterHandler("ccs_list_items.txt",(CmiHandler)CpdList_ccs_list_items_txt);
405   CcsRegisterHandler("ccs_list_items.fmt",(CmiHandler)CpdList_ccs_list_items_fmt);
406   CcsRegisterHandler("ccs_list_items.set",(CmiHandler)CpdList_ccs_list_items_set);
407   CcsRegisterHandler("ccs_machine_architecture",(CmiHandler)CpdMachineArchitecture);
408 }
409
410 #if CMK_WEB_MODE
411 /******************************************************
412 Web performance monitoring interface:
413         Clients will register for performance data with 
414 processor 0 by calling the "perf_monitor" CCS request.  
415 Every WEB_INTERVAL (few seconds), this code
416 calls all registered web performance functions on all processors.  
417 The resulting integers are sent back to the client as a 
418 CCS reply.  
419
420 The current reply format is ASCII and rather nasty:
421 it's the string "perf" followed by space-separated list
422 of the performance functions for each processor.  By default,
423 only two performance functions are registered: the current 
424 processor utilization, in percent; and the current queue length.
425
426 The actual call sequence is:
427 CCS Client->CWebHandler->...  (processor 0)
428   ...->CWeb_Collect->... (all processors)
429 ...->CWeb_Reduce->CWeb_Deliver (processor 0 again)
430 */
431
432 #if 0
433 #  define WEBDEBUG(x) CmiPrintf x
434 #else
435 #  define WEBDEBUG(x) /*empty*/
436 #endif
437
438 #define WEB_INTERVAL 1000 /*Time, in milliseconds, between performance snapshots*/
439 #define MAXFNS 20 /*Largest number of performance functions to expect*/
440
441 typedef struct {
442         char hdr[CmiReservedHeaderSize];
443         int fromPE;/*Source processor*/
444         int perfData[MAXFNS];/*Performance numbers*/
445 } CWeb_CollectedData;
446
447 /*This needs to be made into a list of registered clients*/
448 static int hasApplet=0;
449 static CcsDelayedReply appletReply;
450
451 typedef int (*CWebFunction)(void);
452 static CWebFunction CWebPerformanceFunctionArray[MAXFNS];
453 static int CWebNoOfFns;
454 static int CWeb_ReduceIndex;
455 static int CWeb_CollectIndex;
456
457 /*Deliver the reduced web performance data to the waiting client:
458 */
459 static int collectedCount;
460 static CWeb_CollectedData **collectedValues;
461
462 static void CWeb_Deliver(void)
463 {
464   int i,j;
465
466   if (hasApplet) {
467     WEBDEBUG(("CWeb_Deliver to applet\n"));
468     /*Send the performance data off to the applet*/
469     char *reply=(char *)malloc(6+14*CmiNumPes()*CWebNoOfFns);
470     sprintf(reply,"perf");
471   
472     for(i=0; i<CmiNumPes(); i++){
473       for (j=0;j<CWebNoOfFns;j++)
474       {
475         char buf[20];
476         sprintf(buf," %d",collectedValues[i]->perfData[j]);
477         strcat(reply,buf);
478       }
479     }
480     CcsSendDelayedReply(appletReply,strlen(reply) + 1, reply);
481     free(reply);
482     hasApplet=0;
483   }
484   else
485     WEBDEBUG(("CWeb_Deliver (NO APPLET)\n"));
486   
487   /* Free saved performance data */
488   for(i = 0; i < CmiNumPes(); i++){
489     CmiFree(collectedValues[i]);
490     collectedValues[i] = 0;
491   }
492   collectedCount = 0;
493 }
494
495 /*On PE 0, this handler accumulates all the performace data
496 */
497 static void CWeb_Reduce(void *msg){
498   CWeb_CollectedData *cur,*prev;
499   int src;
500   if(CmiMyPe() != 0){
501     CmiAbort("CWeb performance data sent to wrong processor...\n");
502   }
503   WEBDEBUG(("CWeb_Reduce"));
504   cur=(CWeb_CollectedData *)msg;
505   src=cur->fromPE;
506   prev = collectedValues[src]; /* Previous value, ideally 0 */
507   collectedValues[src] = cur;
508   if(prev == 0) collectedCount++;
509   else CmiFree(prev); /*<- caused by out-of-order perf. data delivery*/
510
511   if(collectedCount == CmiNumPes()){
512     CWeb_Deliver();
513   }
514 }
515
516 /*On each PE, this handler collects the performance data
517 and sends it to PE 0.
518 */
519 static void CWeb_Collect(void)
520 {
521   CWeb_CollectedData *msg;
522   int i;
523
524   WEBDEBUG(("CWeb_Collect on %d\n",CmiMyPe()));
525   msg = (CWeb_CollectedData *)CmiAlloc(sizeof(CWeb_CollectedData));
526   msg->fromPE = CmiMyPe();
527   
528   /* Evaluate each performance function*/
529   for(i = 0; i < CWebNoOfFns; i++)
530     msg->perfData[i] = CWebPerformanceFunctionArray[i] ();
531
532   /* Send result off to node 0 */  
533   CmiSetHandler(msg, CWeb_ReduceIndex);
534   CmiSyncSendAndFree(0, sizeof(CWeb_CollectedData), msg);
535
536   /* Re-call this function after a delay */
537   CcdCallFnAfter((CcdVoidFn)CWeb_Collect, 0, WEB_INTERVAL);
538 }
539
540 extern "C" void CWebPerformanceRegisterFunction(CWebFunction fn)
541 {
542   if (CmiMyRank()!=0) return; /* Should only register from rank 0 */
543   if (CWebNoOfFns>=MAXFNS) CmiAbort("Registered too many CWebPerformance functions!");
544   CWebPerformanceFunctionArray[CWebNoOfFns] = fn;
545   CWebNoOfFns++;
546 }
547
548 /*This is called on PE 0 by clients that wish
549 to receive performance data.
550 */
551 static void CWebHandler(void){
552   if(CcsIsRemoteRequest()) {
553     static int startedCollection=0;
554     
555     WEBDEBUG(("CWebHandler request on %d\n",CmiMyPe()));    
556     hasApplet=1;
557     appletReply=CcsDelayReply();
558     
559     if(startedCollection == 0){
560       WEBDEBUG(("Starting data collection on every processor\n"));    
561       int i;
562       startedCollection=1;
563       collectedCount=0;
564       collectedValues = (CWeb_CollectedData **)malloc(sizeof(void *) * CmiNumPes());
565       for(i = 0; i < CmiNumPes(); i++)
566         collectedValues[i] = 0;
567       
568       /*Start collecting data on each processor*/
569       for(i = 0; i < CmiNumPes(); i++){
570         char *msg = (char *)CmiAlloc(CmiReservedHeaderSize);
571         CmiSetHandler(msg, CWeb_CollectIndex);
572         CmiSyncSendAndFree(i, CmiReservedHeaderSize,msg);
573       }
574     }
575   }
576 }
577
578 /** This "usage" section keeps track of percent of wall clock time
579 spent actually processing messages on each processor.   
580 It's a simple performance measure collected by the CWeb framework.
581 **/
582 struct CWebModeStats {
583 public:
584         double beginTime; ///< Start of last collection interval
585         double startTime; ///< Start of last busy time
586         double usedTime; ///< Total busy time in last collection interval
587         int PROCESSING; ///< If 1, processor is busy
588 };
589 CpvStaticDeclare(CWebModeStats *,cwebStats);
590
591 /* Called to begin a collection interval
592 */
593 static void usageReset(CWebModeStats *stats,double curWallTime)
594 {
595    stats->beginTime=curWallTime;
596    stats->usedTime = 0.;
597 }
598
599 /* Called when processor becomes busy
600 */
601 static void usageStart(CWebModeStats *stats,double curWallTime)
602 {
603    stats->startTime  = curWallTime;
604    stats->PROCESSING = 1;
605 }
606
607 /* Called when processor becomes idle
608 */
609 static void usageStop(CWebModeStats *stats,double curWallTime)
610 {
611    stats->usedTime   += curWallTime - stats->startTime;
612    stats->PROCESSING = 0;
613 }
614
615 /* Call this when the program is started
616  -> Whenever traceModuleInit would be called
617  -> -> see conv-core/convcore.c
618 */
619 static void initUsage()
620 {
621    CpvInitialize(CWebModeStats *, cwebStats);
622    CWebModeStats *stats=new CWebModeStats;
623    CpvAccess(cwebStats)=stats;
624    usageReset(stats,CmiWallTimer());
625    usageStart(stats,CmiWallTimer());
626    CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)usageStart,stats);
627    CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)usageStop,stats);    
628 }
629
630 static int getUsage(void)
631 {
632    int usage = 0;
633    double time      = CmiWallTimer();
634    CWebModeStats *stats=CpvAccess(cwebStats);
635    double totalTime = time - stats->beginTime;
636
637    if(stats->PROCESSING)
638    { /* Lock in current CPU usage */
639       usageStop(stats,time); usageStart(stats,time);
640    }
641    if(totalTime > 0.)
642       usage = (int)(0.5 + 100 *stats->usedTime/totalTime);
643    usageReset(stats,time);
644
645    return usage;
646 }
647
648 static int getSchedQlen(void)
649 {
650   return(CqsLength((Queue)CpvAccess(CsdSchedQueue)));
651 }
652
653 #endif /*CMK_WEB_MODE*/
654
655 #if ! CMK_WEB_MODE
656 static void CWeb_Invalid(void)
657 {
658   CmiAbort("Invalid web mode handler invoked!\n");
659 }
660 #endif
661
662 void CWebInit(void)
663 {
664 #if CMK_WEB_MODE
665   CcsRegisterHandler("perf_monitor", (CmiHandler)CWebHandler);
666   
667   CWeb_CollectIndex=CmiRegisterHandler((CmiHandler)CWeb_Collect);
668   CWeb_ReduceIndex=CmiRegisterHandler((CmiHandler)CWeb_Reduce);
669   
670   initUsage();
671   CWebPerformanceRegisterFunction(getUsage);
672   CWebPerformanceRegisterFunction(getSchedQlen);
673 #else
674   /* always maintain the consistent CmiHandler table */
675   /* which is good for heterogeneous clusters */
676   CmiRegisterHandler((CmiHandler)CWeb_Invalid);
677   CmiRegisterHandler((CmiHandler)CWeb_Invalid);
678 #endif
679 }
680
681
682 extern "C" void CcsBuiltinsInit(char **argv)
683 {
684   CcsRegisterHandler("ccs_getinfo",(CmiHandler)ccs_getinfo);
685   CcsRegisterHandler("ccs_killport",(CmiHandler)ccs_killport);
686   CcsRegisterHandler("ccs_killpe",(CmiHandler)ccs_killpe);
687   CWebInit();
688   CpdListInit();
689 }
690
691
692 #endif /*CMK_CCS_AVAILABLE*/
693
694 void PUP_fmt::fieldHeader(typeCode_t typeCode,int nItems) {
695     // Compute and write intro byte:
696     lengthLen_t ll;
697     if (nItems==1) ll=lengthLen_single;
698     else if (nItems<256) ll=lengthLen_byte;
699     else ll=lengthLen_int;
700     // CmiPrintf("Intro byte: l=%d t=%d\n",(int)ll,(int)typeCode);
701     byte intro=(((int)ll)<<4)+(int)typeCode;
702     p(intro);
703     // Compute and write length:
704     switch(ll) {
705     case lengthLen_single: break; // Single item
706     case lengthLen_byte: {
707         byte l=nItems;
708         p(l);
709         } break;
710     case lengthLen_int: {
711         p(nItems); 
712         } break; 
713     };
714 }
715
716 void PUP_fmt::comment(const char *message) {
717         int nItems=strlen(message);
718         fieldHeader(typeCode_comment,nItems);
719         p((char *)message,nItems);
720 }
721 void PUP_fmt::synchronize(unsigned int m) {
722         fieldHeader(typeCode_sync,1);
723         p(m);
724 }
725 void PUP_fmt::bytes(void *ptr,int n,size_t itemSize,PUP::dataType t) {
726         switch(t) {
727         case PUP::Tchar:
728         case PUP::Tuchar:
729         case PUP::Tbyte:
730                 fieldHeader(typeCode_byte,n);
731                 p.bytes(ptr,n,itemSize,t);
732                 break;
733         case PUP::Tshort: case PUP::Tint:
734         case PUP::Tushort: case PUP::Tuint:
735         case PUP::Tbool:
736                 fieldHeader(typeCode_int,n);
737                 p.bytes(ptr,n,itemSize,t);
738                 break;
739         // treat "long" and "pointer" as 8-bytes, in conformity with pup_toNetwork.C
740         case PUP::Tlong: case PUP::Tlonglong:
741         case PUP::Tulong: case PUP::Tulonglong:
742                 fieldHeader(typeCode_long,n);
743                 p.bytes(ptr,n,itemSize,t);
744                 break;
745         case PUP::Tfloat:
746                 fieldHeader(typeCode_float,n);
747                 p.bytes(ptr,n,itemSize,t);
748                 break;
749         case PUP::Tdouble: case PUP::Tlongdouble:
750                 fieldHeader(typeCode_double,n);
751                 p.bytes(ptr,n,itemSize,t);
752                 break;
753     case PUP::Tpointer:
754         fieldHeader(typeCode_pointer,n);
755         p.bytes(ptr,n,itemSize,t);
756         break;
757         default: CmiAbort("Unrecognized type code in PUP_fmt::bytes");
758         };
759 }
760
761