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