Coverage Report

Created: 2026-10-29 22:51

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