Increased the new tags limit (a simple define)
[dyninst.git] / rtinst / src / RTinst.c
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42
43 /************************************************************************
44  *
45  * RTinst.c: platform independent runtime instrumentation functions
46  *
47  ************************************************************************/
48
49 #ifdef SHM_SAMPLING
50 #include <sys/types.h>
51 #include <sys/ipc.h>
52 #include <sys/shm.h>
53 #endif
54
55 #include <assert.h>
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <memory.h>
59 #include <signal.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <math.h>
64
65 #include "kludges.h"
66 #include "rtinst/h/rtinst.h"
67 #include "rtinst/h/trace.h"
68 #include "util/h/sys.h"
69
70 #if defined(sparc_sun_solaris2_4)
71 #include <thread.h>
72 #endif
73
74 #ifdef PARADYN_MPI
75 #include "/usr/lpp/ppe.poe/include/mpi.h"
76 //#include <mpi.h>
77 #endif
78
79 #if defined(SHM_SAMPLING)
80 extern void makeNewShmSegCopy();
81 #endif
82
83 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
84 void DYNINST_initialize_hash(unsigned total);
85 void DYNINST_initialize_free(unsigned total);
86 unsigned DYNINST_hash_insert(unsigned k);
87 unsigned DYNINST_hash_lookup(unsigned k);
88 unsigned DYNINST_initialize_done=0;
89 #endif
90
91 /* sunos's header files don't have these: */
92 #ifdef sparc_sun_sunos4_1_3
93 extern int socket(int, int, int);
94 extern int connect(int, struct sockaddr *, int);
95 extern int fwrite(void *, int, int, FILE *);
96 extern int setvbuf(FILE *, char *, int, int);
97 #ifdef SHM_SAMPLING
98 extern int shmget(key_t, unsigned, unsigned);
99 extern void *shmat(int, void *, int);
100 extern int shmdt(void*);
101 extern int shmctl(int, int, struct shmid_ds *);
102 #endif
103 #endif
104
105 extern void   DYNINSTos_init(int calledByFork, int calledByAttach);
106 extern time64 DYNINSTgetCPUtime(void);
107 extern time64 DYNINSTgetWalltime(void);
108
109 /* platform dependent functions */
110 extern void DYNINSTbreakPoint(void);
111 extern void DYNINST_install_ualarm(unsigned interval);
112 extern void DYNINSTinitTrace(int);
113 extern void DYNINSTflushTrace(void);
114 extern int DYNINSTwriteTrace(void *, unsigned);
115 extern void DYNINSTcloseTrace(void);
116 extern void *DYNINST_shm_init(int, int, int *);
117
118 void DYNINSTprintCost(void);
119 int DYNINSTTGroup_CreateUniqueId(int);
120
121 /************************************************************************/
122
123 static float  DYNINSTsamplingRate   = 0;
124 static int    DYNINSTtotalSamples   = 0;
125 static tTimer DYNINSTelapsedCPUTime;
126 static tTimer DYNINSTelapsedTime;
127
128 static int DYNINSTnumReported = 0;
129 static time64 startWall = 0;
130 static float DYNINSTcyclesToUsec  = 0;
131 static time64 DYNINSTtotalSampleTime = 0;
132
133 /************************************************************************/
134
135 #define DYNINSTTagsLimit      1000
136 #define DYNINSTTagGroupsLimit 100
137 #define DYNINSTNewTagsLimit   50 // don't want to overload the system
138
139 typedef struct DynInstTag_st {
140   int   TagGroupId;
141   int   TGUniqueId;
142   int   NumTags;
143   int   TagTable[DYNINSTTagsLimit];
144
145   struct DynInstTag_st* Next;
146 } DynInstTagSt;
147
148 typedef struct {
149   int            TagHierarchy; /* True if hierarchy, false single level */
150   int            NumGroups;     /* Number of groups, tag arrays */
151   /* Group table, each index pointing to an array of tags */
152   DynInstTagSt*  GroupTable[DYNINSTTagGroupsLimit]; 
153
154   /* [0] is tagId, [1] is groupId, [2] is 1 if it is a new group else 0 */
155   int            NewTags[DYNINSTNewTagsLimit][3];
156   int            NumNewTags;
157 } DynInstTagGroupSt;
158
159 static DynInstTagGroupSt  TagGroupInfo;
160
161 /************************************************************************/
162
163 #ifdef SHM_SAMPLING
164 /* these vrbles are global so that fork() knows the attributes of the
165    shm segs we've been using */
166 int DYNINST_shmSegKey;
167 int DYNINST_shmSegNumBytes;
168 int DYNINST_shmSegShmId; /* needed? */
169 void *DYNINST_shmSegAttachedPtr;
170 #endif
171 static int the_paradyndPid; /* set in DYNINSTinit(); pass to connectToDaemon();
172                                needed if we fork */
173 #ifndef SHM_SAMPLING
174 static int DYNINSTin_sample = 0;
175 #endif
176
177 static const double MILLION = 1000000.0;
178
179 #ifdef USE_PROF
180 int DYNINSTbufsiz;
181 int DYNINSTprofile;
182 int DYNINSTprofScale;
183 int DYNINSTtoAddr;
184 short *DYNINSTprofBuffer;
185 #endif
186
187
188 #ifdef COSTTEST
189 time64 DYNINSTtest[10]={0,0,0,0,0,0,0,0,0,0};
190 int DYNINSTtestN[10]={0,0,0,0,0,0,0,0,0,0};
191 #endif
192
193 double DYNINSTdata[SYN_INST_BUF_SIZE/sizeof(double)];
194 /* As DYNINSTinit() completes, it has information to pass back
195    to paradynd.  The data can differ; more stuff is needed
196    when SHM_SAMPLING is defined, for example.  But in any event,
197    the following gives us a general framework.  When DYNINSTinit()
198    is about to complete, we used to send a TR_START trace record back and then
199    DYNINSTbreakPoint().  But we've seen strange behavior; sometimes
200    the breakPoint is received by paradynd first.  The following should
201    work all the time:  DYNINSTinit() writes to the following vrble
202    and does a DYNINSTbreakPoint(), instead of sending a trace
203    record.  Paradynd reads this vrble using ptrace(), and thus has
204    the info that it needs.
205    Note: we use this framework for DYNINSTfork(), too -- so the TR_FORK
206    record is now obsolete, along with the TR_START record.
207    Additionally, we use this framework for DYNINSTexec() -- so the
208    TR_EXEC record is now obsolete, too */
209 struct DYNINST_bootstrapStruct DYNINST_bootstrap_info;
210
211
212 #ifndef SHM_SAMPLING
213 /* This could be static, but gdb has can't find them if they are.  
214    jkh 5/8/95 */
215 int64    DYNINSTvalue = 0;
216 unsigned DYNINSTlastLow;
217 unsigned DYNINSTobsCostLow;
218 #endif
219
220 #define N_FP_REGS 33
221
222 volatile int DYNINSTsampleMultiple    = 1;
223    /* written to by dynRPC::setSampleRate() (paradynd/dynrpc.C)
224       (presumably, upon a fold) */
225
226 #ifndef SHM_SAMPLING
227 static int          DYNINSTnumSampled        = 0;
228 static int          DYNINSTtotalAlarmExpires = 0;
229 #endif
230
231 /************************************************************************
232  * void DYNINSTstartProcessTimer(tTimer* timer)
233 ************************************************************************/
234 void
235 DYNINSTstartProcessTimer(tTimer* timer) {
236     /* WARNING: write() could be instrumented to call this routine, so to avoid
237        some serious infinite recursion, avoid calling anything that might directly
238        or indirectly call write() in this routine; e.g. printf()!!!!! */
239
240 #ifdef COSTTEST
241     time64 startT,endT;
242 #endif
243
244 #ifndef SHM_SAMPLING
245     /* if "write" is instrumented to start/stop timers, then a timer could be
246        (incorrectly) started/stopped every time a sample is written back */
247
248     if (DYNINSTin_sample)
249        return;
250 #endif
251
252 #ifdef COSTTEST
253     startT=DYNINSTgetCPUtime();
254 #endif
255
256 /* For shared-mem sampling only: bump protector1, do work, then bump protector2 */
257 #ifdef SHM_SAMPLING
258     assert(timer->protector1 == timer->protector2);
259     timer->protector1++;
260     /* How about some kind of inline asm that flushes writes when the architecture
261        is using some kind of relaxed multiprocessor consistency? */
262 #endif
263
264     /* Note that among the data vrbles, counter is incremented last; in particular,
265        after start has been written.  This avoids a nasty little race condition in
266        sampling where count is 1 yet start is undefined (or using an old value) when
267        read, which usually leads to a rollback.  --ari */
268     if (timer->counter == 0) {
269         timer->start     = DYNINSTgetCPUtime();
270     }
271     timer->counter++;
272
273 #ifdef SHM_SAMPLING
274     timer->protector2++; /* alternatively, timer->protector2 = timer->protector1 */
275     assert(timer->protector1 == timer->protector2);
276 #else
277     timer->normalize = MILLION; /* I think this vrble is obsolete & can be removed */
278 #endif
279
280
281 #ifdef COSTTEST
282     endT=DYNINSTgetCPUtime();
283     DYNINSTtest[0]+=endT-startT;
284     DYNINSTtestN[0]++;
285 #endif
286 }
287
288
289 /************************************************************************
290  * void DYNINSTstopProcessTimer(tTimer* timer)
291 ************************************************************************/
292 void
293 DYNINSTstopProcessTimer(tTimer* timer) {
294     /* WARNING: write() could be instrumented to call this routine, so to avoid
295        some serious infinite recursion, avoid calling anything that might directly
296        or indirectly call write() in this routine; e.g. printf()!!!!! */
297
298 #ifdef COSTTEST
299     time64 startT,endT;
300 #endif
301
302 #ifndef SHM_SAMPLING
303     /* if "write" is instrumented to start/stop timers, then a timer could be
304        (incorrectly) started/stopped every time a sample is written back */
305
306     if (DYNINSTin_sample)
307        return;       
308 #endif
309
310 #ifdef COSTTEST
311     startT=DYNINSTgetCPUtime();
312 #endif
313
314 #ifdef SHM_SAMPLING
315     assert(timer->protector1 == timer->protector2);
316     timer->protector1++;
317
318     if (timer->counter == 0)
319        ; /* a strange condition; shouldn't happen.  Should we make it an assert fail? */
320     else {
321        if (timer->counter == 1) {
322           const time64 now = DYNINSTgetCPUtime();
323           timer->total += (now - timer->start);
324
325           if (now < timer->start) {
326              fprintf(stderr, "rtinst: cpu timer rollback.\n");
327              abort();
328           }
329        }
330        timer->counter--;
331     }
332
333     timer->protector2++; /* alternatively, timer->protector2=timer->protector1 */
334     assert(timer->protector1 == timer->protector2);
335 #else
336     if (timer->counter == 0)
337        ; /* should we make this an assert fail? */
338     else if (timer->counter == 1) {
339         time64 now = DYNINSTgetCPUtime();
340
341         timer->snapShot = timer->total + (now - timer->start);
342
343         timer->mutex    = 1;
344         /*                 
345          * The reason why we do the following line in that way is because
346          * a small race condition: If the sampling alarm goes off
347          * at this point (before timer->mutex=1), then time will go backwards 
348          * the next time a sample is take (if the {wall,process} timer has not
349          * been restarted).
350          *
351          */
352
353         timer->total = DYNINSTgetCPUtime() - timer->start + timer->total; 
354
355         if (now < timer->start) {
356             printf("id=%d, snapShot=%f total=%f, \n start=%f  now=%f\n",
357                    timer->id.id, (double)timer->snapShot,
358                    (double)timer->total, 
359                    (double)timer->start, (double)now);
360             printf("process timer rollback\n"); fflush(stdout);
361
362             abort();
363         }
364         timer->counter = 0;
365         timer->mutex = 0;
366     }
367     else {
368       timer->counter--;
369     }
370 #endif
371
372 #ifdef COSTTEST
373     endT=DYNINSTgetCPUtime();
374     DYNINSTtest[1]+=endT-startT;
375     DYNINSTtestN[1]++;
376 #endif 
377 }
378
379
380
381
382
383 /************************************************************************
384  * void DYNINSTstartWallTimer(tTimer* timer)
385 ************************************************************************/
386 void
387 DYNINSTstartWallTimer(tTimer* timer) {
388     /* WARNING: write() could be instrumented to call this routine, so to avoid
389        some serious infinite recursion, avoid calling anything that might directly
390        or indirectly call write() in this routine; e.g. printf()!!!!! */
391
392 #ifdef COSTTEST
393     time64 startT, endT;
394 #endif
395
396 #ifndef SHM_SAMPLING
397     /* if "write" is instrumented to start/stop timers, then a timer could be
398        (incorrectly) started/stopped every time a sample is written back */
399
400     if (DYNINSTin_sample) {
401        return;
402     }
403 #endif
404
405 #ifdef COSTTEST
406     startT=DYNINSTgetCPUtime();
407 #endif
408
409 #ifdef SHM_SAMPLING
410     assert(timer->protector1 == timer->protector2);
411     timer->protector1++;
412 #endif
413
414     /* Note that among the data vrbles, counter is incremented last; in particular,
415        after start has been written.  This avoids a nasty little race condition in
416        sampling where count is 1 yet start is undefined (or using an old value) when
417        read, which usually leads to a rollback.  --ari */
418     if (timer->counter == 0) {
419         timer->start     = DYNINSTgetWalltime();
420     }
421     timer->counter++;
422
423 #ifdef SHM_SAMPLING
424     timer->protector2++; /* or, timer->protector2 = timer->protector1 */
425     assert(timer->protector1 == timer->protector2);
426 #else
427     timer->normalize = MILLION; /* I think this vrble is obsolete & can be removed */
428 #endif
429
430 #ifdef COSTTEST
431     endT=DYNINSTgetCPUtime();
432     DYNINSTtest[2]+=endT-startT;
433     DYNINSTtestN[2]++;
434 #endif 
435 }
436
437
438 /************************************************************************
439  * void DYNINSTstopWallTimer(tTimer* timer)
440 ************************************************************************/
441 void
442 DYNINSTstopWallTimer(tTimer* timer) {
443 #ifdef COSTTEST
444     time64 startT, endT;
445 #endif
446
447 #ifndef SHM_SAMPLING
448     /* if "write" is instrumented to start timers, a timer could be started */
449     /* when samples are being written back */
450
451     if (DYNINSTin_sample)
452        return;
453 #endif
454
455 #ifdef COSTTEST
456     startT=DYNINSTgetCPUtime();
457 #endif
458
459 #ifdef SHM_SAMPLING
460     assert(timer->protector1 == timer->protector2);
461     timer->protector1++;
462
463     if (timer->counter == 0)
464        ; /* a strange condition; should we make it an assert fail? */
465     else if (--timer->counter == 0) {
466        const time64 now = DYNINSTgetWalltime();
467
468        timer->total += (now - timer->start);
469
470        if (now < timer->start) {
471           fprintf(stderr, "rtinst wall timer rollback.\n");
472           abort();
473        }
474     }
475     
476     timer->protector2++; /* or, timer->protector2 = timer->protector1 */
477     assert(timer->protector1 == timer->protector2);
478 #else
479     if (timer->counter == 0)
480        ; /* a strange condition; should we make it an assert fail? */
481     else if (timer->counter == 1) {
482         time64 now = DYNINSTgetWalltime();
483
484         timer->snapShot = now - timer->start + timer->total;
485         timer->mutex    = 1;
486         /*                 
487          * The reason why we do the following line in that way is because
488          * a small race condition: If the sampling alarm goes off
489          * at this point (before timer->mutex=1), then time will go backwards 
490          * the next time a sample is take (if the {wall,process} timer has not
491          * been restarted).
492          */
493         timer->total    = DYNINSTgetWalltime() - timer->start + timer->total;
494         if (now < timer->start) {
495             printf("id=%d, snapShot=%f total=%f, \n start=%f  now=%f\n",
496                    timer->id.id, (double)timer->snapShot,
497                    (double)timer->total, 
498                    (double)timer->start, (double)now);
499             printf("wall timer rollback\n"); 
500             fflush(stdout);
501
502             abort();
503         }
504         timer->counter  = 0;
505         timer->mutex    = 0;
506     }
507     else {
508         timer->counter--;
509     }
510 #endif
511
512 #ifdef COSTTEST
513     endT=DYNINSTgetCPUtime();
514     DYNINSTtest[3]+=endT-startT;
515     DYNINSTtestN[3]++;
516 #endif 
517 }
518
519
520
521 /************************************************************************
522  * float DYNINSTcyclesPerSecond(void)
523  *
524  * need a well-defined method for finding the CPU cycle speed
525  * on each CPU.
526 ************************************************************************/
527 #if defined(i386_unknown_nt4_0)
528 #define NOPS_4  { __asm add eax, 0 __asm add eax, 0 __asm add eax, 0 __asm add eax, 0 }
529 #elif defined(rs6000_ibm_aix4_1)
530 #define NOPS_4  asm("oril 0,0,0"); asm("oril 0,0,0"); asm("oril 0,0,0"); asm("oril 0,0,0")
531 #else
532 #define NOPS_4  asm("nop"); asm("nop"); asm("nop"); asm("nop")
533 #endif
534 #define NOPS_16 NOPS_4; NOPS_4; NOPS_4; NOPS_4
535 /* Note: the following should probably be moved into arch-specific files,
536    since different platforms could have very different ways of implementation.
537    Consider, hypothetically, an OS that let you get cycles per second with a simple
538    system call */
539 static float
540 DYNINSTcyclesPerSecond(void) {
541     int            i;
542     time64         start_cpu;
543     time64         end_cpu;
544     double         elapsed;
545     double         speed;
546     const unsigned LOOP_LIMIT = 500000;
547
548     start_cpu = DYNINSTgetCPUtime();
549     for (i = 0; i < LOOP_LIMIT; i++) {
550         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
551         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
552         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
553         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
554     }
555     end_cpu = DYNINSTgetCPUtime();
556     elapsed = (double) (end_cpu - start_cpu);
557     speed   = (double) (MILLION*256*LOOP_LIMIT)/elapsed;
558
559 #ifdef i386_unknown_solaris2_5
560     /* speed for the pentium is being overestimated by a factor of 2 */
561     speed /= 2;
562 #endif
563     return speed;
564 }
565
566
567 /************************************************************************
568  * void saveFPUstate(float* base)
569  * void restoreFPUstate(float* base)
570  *
571  * save and restore state of FPU on signals.  these are null functions
572  * for most well designed and implemented systems.
573 ************************************************************************/
574 static void
575 saveFPUstate(float* base) {
576 #ifdef i386_unknown_solaris2_5
577     /* kludge for the pentium: we need to reset the FPU here, or we get 
578        strange results on fp operations.
579     */
580     asm("finit");
581 #endif
582 }
583
584 static void
585 restoreFPUstate(float* base) {
586 }
587
588
589
590 /* The current observed cost since the last call to 
591  *      DYNINSTgetObservedCycles(false) 
592  */
593 /************************************************************************
594  * int64 DYNINSTgetObservedCycles(RT_Boolean in_signal)
595  *
596  * report the observed cost of instrumentation in machine cycles.
597  *
598  * We keep cost as a 64 bit int, but the code generated by dyninst is
599  *   a 32 bit counter (for speed).  So this function also converts the
600  *   cost into a 64 bit value.
601  *
602  * We can't reset the low part of the counter since there might be an
603  *   update of the counter going on while we are checking it.  So instead,
604  *   we keep track of the last value of the low counter we saw, and update
605  *   the high counter by the diference.  We also need to check that the
606  *   delta is not negative (which happens when the low counter roles over).
607  ************************************************************************/
608 #ifndef SHM_SAMPLING
609 int64 DYNINSTgetObservedCycles(RT_Boolean in_signal) 
610 {
611     if (in_signal) {
612         return DYNINSTvalue;
613     }
614
615     /* update the 64 bit version of the counter */
616     if (DYNINSTobsCostLow < DYNINSTlastLow) {
617         /* counter wrap around */
618         /* note the calc here assume 32 bit int, but if ints are 64bit, then
619            it won't wrap in the first place */
620         DYNINSTvalue += (((unsigned) 0xffffffff) - DYNINSTlastLow) + 
621             DYNINSTobsCostLow + 1;
622     } else {
623         DYNINSTvalue += (DYNINSTobsCostLow - DYNINSTlastLow);
624     }
625
626     DYNINSTlastLow = DYNINSTobsCostLow;
627     return DYNINSTvalue;
628 }
629 #endif
630
631
632 /************************************************************************
633  * void DYNINSTsampleValues(void)
634  *
635  * dummy function for sampling timers and counters.  the actual code
636  * is added by dynamic instrumentation from the paradyn daemon.
637 ************************************************************************/
638 #ifndef SHM_SAMPLING
639 void
640 DYNINSTsampleValues(void) {
641     DYNINSTnumReported++;
642 }
643 #endif
644
645
646
647 /************************************************************************
648  * void DYNINSTgenerateTraceRecord(traceStream sid, short type,
649  *   short length, void* data, int flush,time64 wall_time,time64 process_time)
650 ************************************************************************/
651 void
652 DYNINSTgenerateTraceRecord(traceStream sid, short type, short length,
653                            void *eventData, int flush,
654                            time64 wall_time, time64 process_time) {
655     static unsigned pipe_gone = 0;
656     static unsigned inDYNINSTgenerateTraceRecord = 0;
657     traceHeader     header;
658     int             count;
659     char            buffer[1024];
660
661     if (inDYNINSTgenerateTraceRecord) return;
662     inDYNINSTgenerateTraceRecord = 1;
663
664     if (pipe_gone) {
665         inDYNINSTgenerateTraceRecord = 0;
666         return;
667     }
668
669     header.wall    = wall_time - startWall;
670     header.process = process_time;
671 #ifdef ndef
672     if(type == TR_SAMPLE){
673          traceSample *s = (traceSample*)eventData;
674          printf("wall time = %f processTime = %f value = %f\n",
675                 (double)(header.wall/1000000.0), 
676                 (double)(header.process/1000000.0),
677                 s->value);
678     }
679 #endif
680
681     length = ALIGN_TO_WORDSIZE(length);
682
683     header.type   = type;
684     header.length = length;
685
686     count = 0;
687     memcpy(&buffer[count], &sid, sizeof(traceStream));
688     count += sizeof(traceStream);
689
690     memcpy(&buffer[count], &header, sizeof(header));
691     count += sizeof(header);
692
693     count = ALIGN_TO_WORDSIZE(count);
694     memcpy(&buffer[count], eventData, length);
695     count += length;
696
697     
698     if (!DYNINSTwriteTrace(buffer, count))
699       pipe_gone = 1;
700
701     if (flush) DYNINSTflushTrace();
702
703     inDYNINSTgenerateTraceRecord = 0;
704 }
705
706
707 /************************************************************************
708  * void DYNINSTreportBaseTramps(void)
709  *
710  * report the cost of base trampolines.
711 ************************************************************************/
712 #ifndef SHM_SAMPLING
713 void
714 DYNINSTreportBaseTramps() {
715     // NOTE: this routine has a misleading name; how about DYNINSTsampleObsCost().
716
717     costUpdate sample;
718
719     //
720     // Adding the cost corresponding to the alarm when it goes off.
721     // This value includes the time spent inside the routine (DYNINSTtotal-
722     // sampleTime) plus the time spent during the context switch (121 usecs
723     // for SS-10, sunos)
724     //
725
726     sample.obsCostIdeal  = ((((double) DYNINSTgetObservedCycles(1) *
727                               (double)DYNINSTcyclesToUsec) + 
728                              DYNINSTtotalSampleTime + 121) / 1000000.0);
729
730 #ifdef notdef
731     if (DYNINSTprofile) {
732         int i;
733         int limit;
734         int pageSize;
735         int startInst;
736         extern void DYNINSTfirst();
737
738
739         limit = DYNINSTbufsiz;
740         /* first inst code - assumes data area above code space in virtual
741          * address */
742         startInst = (int) &DYNINSTfirst;
743         for (i=0; i < limit; i ++) {
744             if (i * DYNINSTtoAddr > startInst) {
745                 instTicks += DYNINSTprofBuffer[i];
746             }
747         }
748
749         sample.obsCostLow  = ((double) instTicks ) /100.0;
750         sample.obsCostHigh = sample.obsCostLow + sample.obsCostIdeal;
751     }
752 #endif
753
754     DYNINSTgenerateTraceRecord(0, TR_COST_UPDATE, sizeof(sample), &sample, 0,
755                                DYNINSTgetWalltime(), DYNINSTgetCPUtime());
756 }
757 #endif
758
759
760 /************************************************************************
761  * static void DYNINSTreportSamples(void)
762  *
763  * report samples to paradyn daemons. Called by DYNINSTinit, DYNINSTexit,
764  * and DYNINSTalarmExpires.
765 ************************************************************************/
766 #ifndef SHM_SAMPLING
767 static void 
768 DYNINSTreportSamples(void) {
769     time64     start_cpu;
770     float      fp_context[N_FP_REGS];
771
772     ++DYNINSTin_sample;
773
774     saveFPUstate(fp_context);
775     start_cpu = DYNINSTgetCPUtime();
776
777     /* to keep observed cost accurate due to 32-cycle rollover */
778     (void) DYNINSTgetObservedCycles(0);
779
780     DYNINSTsampleValues();
781     DYNINSTreportBaseTramps();
782     DYNINSTflushTrace();
783
784     DYNINSTtotalSampleTime += (DYNINSTgetCPUtime() - start_cpu);
785     restoreFPUstate(fp_context);
786     --DYNINSTin_sample;
787 }
788 #endif
789
790
791 /************************************************************************
792  * void DYNINSTalarmExpire(void)
793  *
794  * called periodically by signal handlers.  report sampled data back
795  * to the paradyn daemons.  when the program exits, DYNINSTsampleValues
796  * should be called directly.
797 ************************************************************************/
798 /************************************************************************
799  * DYNINSTalarmExpire is changed so that it will restart the sytem call
800  * if that called is interrupted on HP
801  * Duplicated for the same reason above.
802  ************************************************************************/
803 #ifndef SHM_SAMPLING
804 void
805 #if !defined(hppa1_1_hp_hpux)
806 DYNINSTalarmExpire(int signo) {
807 #else 
808 DYNINSTalarmExpire(int signo, int code, struct sigcontext *scp) {
809 #endif
810
811 #ifdef COSTTEST
812     time64 startT, endT;
813 #endif
814
815     if (DYNINSTin_sample) {
816         return;
817     }
818     DYNINSTin_sample = 1;
819
820 #ifdef COSTTEST
821     startT=DYNINSTgetCPUtime();
822 #endif
823
824     DYNINSTtotalAlarmExpires++;
825
826     /* This piece of code is needed because DYNINSTalarmExpire's are always called
827        at the initial pace (every .2 secs, I believe), whereas we only want to do
828        stuff at the current pace (initially every .2 secs but less frequently after
829        "folds").  We could just adjust the rate of SIGALRM, so this isn't
830        needed. */
831
832     if ((++DYNINSTnumSampled % DYNINSTsampleMultiple) == 0) {
833       DYNINSTreportSamples();
834     }
835
836     DYNINSTin_sample = 0;
837
838 #if defined(hppa1_1_hp_hpux)
839     scp->sc_syscall_action = SIG_RESTART;
840 #endif
841
842
843 #ifdef COSTTEST
844     endT=DYNINSTgetCPUtime();
845     DYNINSTtest[4]+=endT-startT;
846     DYNINSTtestN[4]++;
847 #endif 
848 }
849 #endif
850
851
852 static void shmsampling_printf(const char *fmt, ...) {
853 #ifdef SHM_SAMPLING_DEBUG
854    va_list args;
855    va_start(args, fmt);
856
857    vfprintf(stderr, fmt, args);
858
859    va_end(args);
860
861    fflush(stderr);
862 #endif
863 }
864
865 /************************************************************************
866  * void DYNINSTinit()
867  *
868  * initialize the DYNINST library.  this function is called at the start
869  * of the application program, as well as after a fork, and after an
870  * attach.
871  *
872  ************************************************************************/
873 void DYNINSTinit(int theKey, int shmSegNumBytes, int paradyndPid)
874 {
875   /* If first 2 params are -1 then we're being called by DYNINSTfork(). */
876   /* If first 2 params are 0 then it just means we're not shm sampling */
877   /* If 3d param is negative, then we're called from attach
878      (and we use -paradyndPid as paradynd's pid).  If 3d param
879      is positive, then we're not called from attach (and we use +paradyndPid
880      as paradynd's pid). */
881   
882   int calledFromFork = (theKey == -1);
883   int calledFromAttach = (paradyndPid < 0);
884   
885 #ifndef SHM_SAMPLING
886   unsigned         val;
887 #endif
888   
889   int dx;
890   
891 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
892   traceThrSelf traceRec;
893 #endif
894   
895 #ifdef SHM_SAMPLING_DEBUG
896   char thehostname[80];
897   extern int gethostname(char*,int);
898   
899   (void)gethostname(thehostname, 80);
900   thehostname[79] = '\0';
901   
902   shmsampling_printf("WELCOME to DYNINSTinit (%s, pid=%d), args are %d, %d, %d\n",
903                      thehostname, (int)getpid(), theKey, shmSegNumBytes,
904                      paradyndPid);
905 #endif
906   
907   if (calledFromAttach)
908     paradyndPid = -paradyndPid;
909   
910   the_paradyndPid = paradyndPid; /* important -- needed in case we fork() */
911   
912   TagGroupInfo.TagHierarchy = 0; /* FALSE; */
913   TagGroupInfo.NumGroups = 0;
914   TagGroupInfo.NumNewTags = 0;
915   for(dx=0; dx < DYNINSTTagGroupsLimit; dx++) {
916     TagGroupInfo.GroupTable[dx] = NULL;
917   } 
918
919 #ifdef SHM_SAMPLING
920   if (!calledFromFork) {
921     DYNINST_shmSegKey = theKey;
922     DYNINST_shmSegNumBytes = shmSegNumBytes;
923     
924     DYNINST_shmSegAttachedPtr = DYNINST_shm_init(theKey, shmSegNumBytes, 
925                                                  &DYNINST_shmSegShmId);
926   }
927 #endif
928   
929   /*
930      In accordance with usual stdio rules, stdout is line-buffered and stderr is
931      non-buffered.  Unfortunately, stdio is a little clever and when it detects
932      stdout/stderr redirected to a pipe/file/whatever, it changes to fully-buffered.
933      This indeed occurs with us (see paradynd/src/process.C to see how a program's
934      stdout/stderr are redirected to a pipe). So we reset back to the desired
935      "bufferedness" here.  See stdio.h for these calls.  When attaching, stdio
936      isn't under paradynd control, so we don't do this stuff.
937
938      Note! Since we are messing with stdio stuff here, it should go without
939      saying that DYNINSTinit() (or at least this part of it) shouldn't be
940      invoked until stdio has been initialized!
941   */
942   
943   if (!calledFromAttach) {
944     setvbuf(stdout, NULL, _IOLBF, 0);
945     /* make stdout line-buffered.  "setlinebuf(stdout)" is cleaner but HP
946        doesn't seem to have it */
947     setvbuf(stderr, NULL, _IONBF, 0);
948     /* make stderr non-buffered */
949   }
950   
951   DYNINSTos_init(calledFromFork, calledFromAttach);
952   /* is this needed when calledFromFork?  Depends on what it does, which is in turn
953      os-dependent...so, calledFromFork should probably be passed to this routine. */
954   /* Initialize TagGroupInfo */
955   
956   startWall = 0;
957   
958   if (!calledFromFork)
959     DYNINSTcyclesToUsec = MILLION/DYNINSTcyclesPerSecond();
960   
961 #ifndef SHM_SAMPLING
962   /* assign sampling rate to be default value in util/h/sys.h */
963   val = BASESAMPLEINTERVAL;
964   
965   DYNINSTsamplingRate = val/MILLION;
966   
967 #endif
968   
969 #ifdef USE_PROF
970   {
971     extern int end;
972     
973     DYNINSTprofScale = sizeof(short);
974     DYNINSTtoAddr = sizeof(short);
975     DYNINSTbufsiz = (((unsigned int) &end)/DYNINSTprofScale) + 1;
976     DYNINSTprofBuffer = (short *) calloc(sizeof(short), DYNINSTbufsiz);
977     profil(DYNINSTprofBuffer, DYNINSTbufsiz*sizeof(short), 0, 0xffff);
978     DYNINSTprofile = 1;
979   }
980 #endif
981   
982   DYNINSTstartWallTimer(&DYNINSTelapsedTime);
983   DYNINSTstartProcessTimer(&DYNINSTelapsedCPUTime);
984   
985   /* Fill in info for paradynd to receive: */
986   
987   DYNINST_bootstrap_info.ppid = -1; /* not needed really */
988   
989   if (!calledFromFork) {
990 #ifdef SHM_SAMPLING
991     shmsampling_printf("DYNINSTinit setting appl_attachedAtPtr in bs_record to %x\n",
992                        (unsigned)DYNINST_shmSegAttachedPtr);
993     DYNINST_bootstrap_info.appl_attachedAtPtr = DYNINST_shmSegAttachedPtr;
994 #endif
995   }
996   
997   DYNINST_bootstrap_info.pid = getpid();
998 #if !defined(i386_unknown_nt4_0)
999   if (calledFromFork)
1000     DYNINST_bootstrap_info.ppid = getppid();
1001 #else
1002   DYNINST_bootstrap_info.ppid = 0;
1003 #endif
1004
1005   /* We do this field last as a way to synchronize; paradynd will ignore what it
1006      sees in this structure until the event field is nonzero */
1007   if (calledFromFork)
1008     DYNINST_bootstrap_info.event = 2; /* 2 --> end of DYNINSTinit (forked process) */
1009   else if (calledFromAttach)
1010     DYNINST_bootstrap_info.event = 3; /* 3 --> end of DYNINSTinit (attached proc) */
1011   else                             
1012     DYNINST_bootstrap_info.event = 1; /* 1 --> end of DYNINSTinit (normal or when
1013                                          called by exec'd proc) */
1014   
1015   
1016   /* If attaching, now's the time where we set up the trace stream connection fd */
1017   if (calledFromAttach) {
1018     int pid = getpid();
1019 #if !defined(i386_unknown_nt4_0)
1020     int ppid = getppid();
1021 #else
1022     int ppid = 0;
1023 #endif
1024     unsigned attach_cookie = 0x22222222;
1025     
1026     DYNINSTinitTrace(paradyndPid);
1027     
1028     DYNINSTwriteTrace(&attach_cookie, sizeof(attach_cookie));
1029     DYNINSTwriteTrace(&pid, sizeof(pid));
1030     DYNINSTwriteTrace(&ppid, sizeof(ppid));
1031 #ifdef SHM_SAMPLING
1032     DYNINSTwriteTrace(&DYNINST_shmSegKey, sizeof(DYNINST_shmSegKey));
1033     DYNINSTwriteTrace(&DYNINST_shmSegAttachedPtr, sizeof(DYNINST_shmSegAttachedPtr));
1034 #endif
1035     DYNINSTflushTrace();
1036   }
1037   else if (!calledFromFork) {
1038     /* either normal startup or startup via a process having exec'd */
1039 #if !defined(i386_unknown_nt4_0)
1040       /* trace stream is already open */
1041       DYNINSTinitTrace(-1);
1042 #else
1043       /* need to get a connection to daemon */
1044       int cookie = 0;
1045       int pid = getpid();
1046       int ppid = paradyndPid;
1047       DYNINSTinitTrace(paradyndPid);
1048       DYNINSTwriteTrace(&cookie, sizeof(cookie));
1049       DYNINSTwriteTrace(&pid, sizeof(pid));
1050       DYNINSTwriteTrace(&ppid, sizeof(ppid));
1051 #endif
1052   }
1053   else
1054     /* calledByFork -- DYNINSTfork already called DYNINSTinitTrace */
1055     ;
1056   
1057 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1058   if (!DYNINST_initialize_done) {
1059     DYNINST_initialize_free(MAX_NUMBER_OF_THREADS);
1060     DYNINST_initialize_hash(MAX_NUMBER_OF_THREADS);
1061     traceRec.pos = DYNINST_hash_insert(DYNINSTthreadSelf());
1062     DYNINST_initialize_done=1;
1063   } else {
1064     traceRec.pos = DYNINST_hash_lookup(DYNINSTthreadSelf());
1065   }
1066   traceRec.tid = DYNINSTthreadSelf();
1067   traceRec.ppid = getpid();
1068   DYNINSTgenerateTraceRecord(0, TR_THRSELF, sizeof(traceRec), &traceRec, 1,
1069                              DYNINSTgetWalltime(),
1070                              DYNINSTgetCPUtime());
1071 #endif
1072   
1073   /* Now, we stop ourselves.  When paradynd receives the forwarded signal,
1074      it will read from DYNINST_bootstrap_info */
1075   
1076   shmsampling_printf("DYNINSTinit (pid=%d) --> about to DYNINSTbreakPoint()\n",
1077                      (int)getpid());
1078   
1079   DYNINSTbreakPoint();
1080
1081   /* The next instruction is necessary to avoid a race condition when we
1082      link the thread library. This is just a hack to get the hw counters
1083      to work and it should be fixed - naim 4/9/97 */
1084   /* usleep(1000000); */
1085   
1086   /* After the break, we clear DYNINST_bootstrap_info's event field, leaving the
1087      others there */
1088   DYNINST_bootstrap_info.event = 0; /* 0 --> nothing */
1089   
1090   shmsampling_printf("leaving DYNINSTinit (pid=%d) --> the process is running freely now\n", (int)getpid());
1091    
1092 #ifndef SHM_SAMPLING
1093   /* what good does this do here? */
1094   /* We report samples here to set the starting time for metrics that were
1095      enabled before the user press run, so we don't loose any samples - mjrg
1096      */
1097   DYNINSTreportSamples();
1098
1099   /* Install alarm only when exiting DYNINSTinit to avoid alarm going off
1100      before DYNINSTinit is done */
1101   /* Do we need to re-create the alarm signal stuff when calledFromFork is true? */
1102   DYNINST_install_ualarm(val);
1103
1104 #endif
1105 }
1106
1107
1108 /************************************************************************
1109  * void DYNINSTexit(void)
1110  *
1111  * handle `exit' in the application. 
1112  * report samples and print cost.
1113 ************************************************************************/
1114 void
1115 DYNINSTexit(void) {
1116     static int done = 0;
1117     if (done) return;
1118     done = 1;
1119
1120 #ifndef SHM_SAMPLING
1121     DYNINSTreportSamples();
1122 #endif
1123
1124     /* NOTE: For shm sampling, we should do more here.  For example, we should
1125        probably disconnect from the shm segments.
1126        Note that we don't have to inform paradynd of the exit; it will find out
1127        soon enough on its own, due to the waitpid() it does and/or finding an
1128        end-of-file on one of our piped file descriptors. */
1129
1130     DYNINSTprintCost();
1131 }
1132
1133
1134
1135 /************************************************************************
1136  * void DYNINSTfork(void* arg, int pid)
1137  *
1138  * track a fork() system call, and report to the paradyn daemon.
1139  *
1140  * Instrumented by paradynd to be called at the exit point of fork().  So, the address
1141  * space (including the instrumentation heap) has already been duplicated, though some
1142  * meta-data still needs to be manually duplicated by paradynd.  Note that for
1143  * shm_sampling, a fork() just increases the reference count for the shm segment.
1144  * This is not what we want, so we need to (1) detach from the old segment, (2) create
1145  * a new shm segment and attach to it in the *same* virtual addr spot as the old
1146  * one (otherwise, references to the shm segment will be out of date!), and (3) let
1147  * let paradynd know what segment key numbers we have chosen for the new segments, so
1148  * that it may attach to them (paradynd may also set some values w/in the segments such
1149  * as mid's).
1150  * 
1151  * Who sends the initial trace record to paradynd?  The child creates the new shm seg
1152  * and thus only the child can inform paradynd of the chosen keys.  One might argue that
1153  * the child does't have a traceRecord connection yet, but fork() should dup() all fd's
1154  * and take care of that limitation...
1155 ************************************************************************/
1156 /* debug code should call forkexec_printf as a way of avoiding
1157    putting #ifdef FORK_EXEC_DEBUG around their fprintf(stderr, ...) statements,
1158    which can lead to horribly ugly code --ari */
1159 /* similar for SHM_SAMPLING_DEBUG */
1160 void forkexec_printf(const char *fmt, ...) {
1161 #ifdef FORK_EXEC_DEBUG
1162    va_list args;
1163    va_start(args, fmt);
1164
1165    vfprintf(stderr, fmt, args);
1166
1167    va_end(args);
1168
1169    fflush(stderr);
1170 #endif
1171 }
1172
1173 #if !defined(i386_unknown_nt4_0)
1174 void
1175 DYNINSTfork(int pid) {
1176     //forkexec_printf("DYNINSTfork called with pid = %d\n", pid);
1177     printf("DYNINSTfork -- WELCOME -- called with pid = %d\n", pid);
1178     fflush(stdout);
1179
1180     if (pid > 0) {
1181        /* We used to send TR_FORK trace record here, in the parent.  But shm sampling
1182           requires the child to do this, so we moved the code there... */
1183        /* See metric.C for an explanation why it's important for the parent to
1184           be paused (not just the child) while propagating metric instances.
1185           Here's the short explanation: to initialize some of the timers and counters,
1186           the child will copy some fields from the parent, and for the child to get
1187           values from the parent after the fork would be a bad thing.  --ari */
1188
1189        forkexec_printf("DYNINSTfork parent; about to DYNINSTbreakPoint\n");
1190        fflush(stderr);
1191
1192        DYNINSTbreakPoint();
1193     } else if (pid == 0) {
1194        /* we are the child process */
1195         int pid = getpid();
1196         int ppid = getppid();
1197
1198         //char *traceEnv;
1199
1200         forkexec_printf("DYNINSTfork CHILD -- welcome\n");
1201         fflush(stderr);
1202
1203 #ifdef SHM_SAMPLING
1204         /* Here, we need to detach from the old shm segment, create a new one
1205            (in the same virtual memory location as the old one), and attach 
1206            to it */
1207         makeNewShmSegCopy();
1208 #endif
1209
1210         /* Here is where we used to send a TR_FORK trace record.  But we've found
1211            that sending a trace record followed by a DYNINSTbreakPoint had unpredictable
1212            results -- sometimes the breakPoint would get delivered to paradynd first.
1213            So idea #2 was to fill in DYNINST_bootstrapStruct and then do a breakpoint.
1214            But the breakPoint won't get forwarded to paradynd because paradynd hasn't
1215            yet attached to the child process.
1216            So idea #3 (the current one) is to just send all that information along the
1217            new connection (whereas we used to just send the pid).
1218
1219            NOTE: soon attach will probably be implemented in a similar way -- by
1220                  writing to the connection.
1221          */
1222
1223         /* set up a connection to the daemon for the trace stream.  (The child proc
1224            gets a different connection from the parent proc) */
1225         forkexec_printf("dyninst-fork child closing old connections...\n");
1226         DYNINSTcloseTrace();
1227
1228         forkexec_printf("dyninst-fork child opening new connection.\n");
1229         assert(the_paradyndPid > 0);
1230         DYNINSTinitTrace(the_paradyndPid);
1231
1232         forkexec_printf("dyninst-fork child pid %d opened new connection...now sending pid etc. along it\n", (int)getpid());
1233
1234         {
1235           unsigned fork_cookie = 0x11111111;
1236           DYNINSTwriteTrace(&fork_cookie, sizeof(fork_cookie));
1237         }
1238
1239         DYNINSTwriteTrace(&pid, sizeof(pid));
1240         DYNINSTwriteTrace(&ppid, sizeof(ppid));
1241 #ifdef SHM_SAMPLING
1242         DYNINSTwriteTrace(&DYNINST_shmSegKey, sizeof(DYNINST_shmSegKey));
1243         DYNINSTwriteTrace(&DYNINST_shmSegAttachedPtr, sizeof(DYNINST_shmSegAttachedPtr));
1244 #endif
1245         DYNINSTflushTrace();
1246
1247         forkexec_printf("dyninst-fork child pid %d sent pid; now doing DYNINSTbreakPoint() to wait for paradynd to initialize me.\n", (int)getpid());
1248
1249         DYNINSTbreakPoint();
1250
1251         forkexec_printf("dyninst-fork child past DYNINSTbreakPoint()...calling DYNINSTinit(-1,-1)\n");
1252
1253         DYNINSTinit(-1, -1, the_paradyndPid);
1254            /* -1 params indicate called from DYNINSTfork */
1255
1256         forkexec_printf("dyninst-fork child done...running freely.\n");
1257     }
1258 }
1259 #endif
1260
1261
1262 void
1263 DYNINSTexec(char *path) {
1264     /* paradynd instruments programs to call this routine on ENTRY to exec
1265        (so the exec hasn't yet taken place).  All that we do here is inform paradynd
1266        of the (pending) exec, and pause ourselves.  Paradynd will continue us after
1267        digesting the info...then, presumably, a TRAP will be generated, as the exec
1268        syscall completes. */
1269
1270     forkexec_printf("execve called, path = %s\n", path);
1271
1272     if (strlen(path) + 1 > sizeof(DYNINST_bootstrap_info.path)) {
1273       fprintf(stderr, "DYNINSTexec failed...path name too long\n");
1274       abort();
1275     }
1276
1277     /* We used to send a TR_EXEC record here and then DYNINSTbreakPoint().
1278        But we've seen a race condition -- sometimes the break-point is delivered
1279        to paradynd before the trace record.  So instead, we fill in
1280        DYNINST_bootstrap_info and then do a breakpoint.  This approach is the same
1281        as the end of DYNINSTinit. */
1282     DYNINST_bootstrap_info.event = 4;
1283     DYNINST_bootstrap_info.pid = getpid();
1284     strcpy(DYNINST_bootstrap_info.path, path);
1285
1286     /* The following turns OFF the alarm signal (the 0,0 parameters); when
1287        DYNINSTinit() runs again for the exec'd process, it'll be turned back on.  This
1288        stuff is necessary to avoid the process dying on an uncaught sigalarm while
1289        processing the exec */
1290 #ifndef SHM_SAMPLING
1291     DYNINST_install_ualarm(0);
1292 #endif
1293
1294     forkexec_printf("DYNINSTexec before breakpoint\n");
1295
1296     DYNINSTbreakPoint();
1297
1298     /* after the breakpoint, clear DYNINST_bootstrap_info */
1299     DYNINST_bootstrap_info.event = 0; /* 0 --> nothing */
1300
1301     forkexec_printf("DYNINSTexec after breakpoint...allowing the exec to happen now\n");
1302 }
1303
1304
1305 void
1306 DYNINSTexecFailed() {
1307     time64 process_time = DYNINSTgetCPUtime();
1308     time64 wall_time = DYNINSTgetWalltime();
1309     int pid = getpid();
1310
1311     forkexec_printf("DYNINSTexecFAILED\n");
1312
1313     DYNINSTgenerateTraceRecord(0, TR_EXEC_FAILED, sizeof(int), &pid, 1,
1314                                process_time, wall_time);
1315
1316 #ifndef SHM_SAMPLING
1317     DYNINST_install_ualarm(BASESAMPLEINTERVAL);
1318 #endif
1319 }
1320
1321
1322
1323 /************************************************************************
1324  * void DYNINSTprintCost(void)
1325  *
1326  * print a detailed summary of the cost of the application's run.
1327 ************************************************************************/
1328 void
1329 DYNINSTprintCost(void) {
1330     FILE *fp;
1331     time64 now;
1332     int64 value;
1333     struct endStatsRec stats;
1334     time64 wall_time; 
1335
1336     DYNINSTstopProcessTimer(&DYNINSTelapsedCPUTime);
1337     DYNINSTstopWallTimer(&DYNINSTelapsedTime);
1338
1339 #ifndef SHM_SAMPLING
1340     value = DYNINSTgetObservedCycles(0);
1341 #else
1342     value = *(unsigned*)((char*)DYNINST_bootstrap_info.appl_attachedAtPtr + 12);
1343 #endif
1344     stats.instCycles = value;
1345
1346     value *= DYNINSTcyclesToUsec;
1347
1348 #ifndef SHM_SAMPLING
1349     stats.alarms      = DYNINSTtotalAlarmExpires;
1350 #else
1351     stats.alarms      = 0;
1352 #endif
1353     stats.numReported = DYNINSTnumReported;
1354     stats.instTime    = (double)value/(double)MILLION;
1355     stats.handlerCost = (double)DYNINSTtotalSampleTime/(double)MILLION;
1356
1357     now = DYNINSTgetCPUtime();
1358     wall_time = DYNINSTgetWalltime();
1359     stats.totalCpuTime  = (double)DYNINSTelapsedCPUTime.total/(double)MILLION;
1360     stats.totalWallTime = (double)DYNINSTelapsedTime.total/(double)MILLION;
1361
1362     stats.samplesReported = DYNINSTtotalSamples;
1363     stats.samplingRate    = DYNINSTsamplingRate;
1364
1365     stats.userTicks = 0;
1366     stats.instTicks = 0;
1367
1368
1369     fp = fopen("stats.out", "w");
1370
1371 #ifdef USE_PROF
1372     if (DYNINSTprofile) {
1373         int i;
1374         int limit;
1375         int pageSize;
1376         int startInst;
1377         extern void DYNINSTfirst();
1378
1379
1380         limit = DYNINSTbufsiz;
1381         /* first inst code - assumes data area above code space in virtual
1382          * address */
1383         startInst = (int) &DYNINSTfirst;
1384         fprintf(fp, "startInst = %x\n", startInst);
1385         fprintf(fp, "limit = %x\n", limit * DYNINSTprofScale);
1386         for (i=0; i < limit; i++) {
1387 #ifdef notdef
1388             if (DYNINSTprofBuffer[i]) {
1389                 fprintf(fp, "%x %d\n", i * DYNINSTtoAddr, 
1390                         DYNINSTprofBuffer[i]);
1391             }
1392 #endif
1393             if (i * DYNINSTtoAddr > startInst) {
1394                 stats.instTicks += DYNINSTprofBuffer[i];
1395             } else {
1396                 stats.userTicks += DYNINSTprofBuffer[i];
1397             }
1398         }
1399
1400         /* fwrite(DYNINSTprofBuffer, DYNINSTbufsiz, 1, fp); */
1401         fprintf(fp, "stats.instTicks %d\n", stats.instTicks);
1402         fprintf(fp, "stats.userTicks %d\n", stats.userTicks);
1403     }
1404 #endif
1405
1406 #ifdef notdef
1407     fprintf(fp, "DYNINSTtotalAlarmExpires %d\n", stats.alarms);
1408     fprintf(fp, "DYNINSTnumReported %d\n", stats.numReported);
1409     fprintf(fp,"Raw cycle count = %f\n", (double) stats.instCycles);
1410     fprintf(fp,"Total instrumentation cost = %f\n", stats.instTime);
1411     fprintf(fp,"Total handler cost = %f\n", stats.handlerCost);
1412     fprintf(fp,"Total cpu time of program %f\n", stats.totalCpuTime);
1413     fprintf(fp,"Elapsed wall time of program %f\n",
1414         stats.totalWallTime/1000000.0);
1415     fprintf(fp,"total data samples %d\n", stats.samplesReported);
1416     fprintf(fp,"sampling rate %f\n", stats.samplingRate);
1417     fprintf(fp,"Application program ticks %d\n", stats.userTicks);
1418     fprintf(fp,"Instrumentation ticks %d\n", stats.instTicks);
1419
1420     fclose(fp);
1421 #endif
1422
1423     /* record that the exec is done -- should be somewhere better. */
1424     DYNINSTgenerateTraceRecord(0, TR_EXIT, sizeof(stats), &stats, 1,
1425                                wall_time,now);
1426 }
1427
1428
1429
1430 /************************************************************************
1431  * void DYNINSTreportNewTags(void)
1432  *
1433  * inform the paradyn daemons of new message tags.  Invoked
1434  * periodically by DYNINSTsampleValues (or directly from DYNINSTrecordTag,
1435  * if SHM_SAMPLING).
1436 ************************************************************************/
1437 void DYNINSTreportNewTags(void)
1438 {
1439   int    dx;
1440   time64 process_time;
1441   time64 wall_time;
1442
1443   if(TagGroupInfo.NumNewTags > 0) {
1444     /* not used by consumer [createProcess() in perfStream.C], so can prob.
1445      * be set to a dummy value to save a little time.  */
1446     process_time = DYNINSTgetCPUtime();
1447     /* this _is_ needed; paradynd keeps the 'creation' time of each resource
1448      *  (resource.h) */
1449     wall_time = DYNINSTgetWalltime();
1450   }
1451
1452 #ifdef COSTTEST
1453   time64 startT,endT;
1454   startT=DYNINSTgetCPUtime();
1455 #endif
1456   
1457   for(dx=0; dx < TagGroupInfo.NumNewTags; dx++) {
1458     struct _newresource newRes;
1459     
1460     if((TagGroupInfo.TagHierarchy) && (TagGroupInfo.NewTags[dx][2])) {
1461       memset(&newRes, '\0', sizeof(newRes));
1462       sprintf(newRes.name, "SyncObject/Message/%d",
1463               TagGroupInfo.NewTags[dx][1]);
1464       strcpy(newRes.abstraction, "BASE");
1465       newRes.type = RES_TYPE_INT;
1466
1467       DYNINSTgenerateTraceRecord(0, TR_NEW_RESOURCE,
1468                                  sizeof(struct _newresource), &newRes, 1,
1469                                  wall_time,process_time);
1470     }
1471     
1472     memset(&newRes, '\0', sizeof(newRes));
1473     if(TagGroupInfo.TagHierarchy) {
1474       sprintf(newRes.name, "SyncObject/Message/%d/%d", 
1475               TagGroupInfo.NewTags[dx][1], TagGroupInfo.NewTags[dx][0]);
1476     } else {
1477       sprintf(newRes.name, "SyncObject/Message/%d", 
1478               TagGroupInfo.NewTags[dx][0]);
1479     }
1480     strcpy(newRes.abstraction, "BASE");
1481     newRes.type = RES_TYPE_INT;
1482
1483     DYNINSTgenerateTraceRecord(0, TR_NEW_RESOURCE, 
1484                                sizeof(struct _newresource), &newRes, 1,
1485                                wall_time,process_time);
1486   }
1487   TagGroupInfo.NumNewTags = 0;
1488   
1489 #ifdef COSTTEST
1490   endT=DYNINSTgetCPUtime();
1491   DYNINSTtest[8]+=endT-startT;
1492   DYNINSTtestN[8]++;
1493 #endif 
1494 }
1495
1496
1497 /************************************************************************
1498  * void DYNINSTrecordTag(int tagId) &&
1499  * void DYNINSTrecordTagAndGroup(int tagId, int groupId)
1500  *
1501  * mark a new tag in tag list.
1502  * Routines such as pvm_send() are instrumented to call us.
1503  * In the non-shm-sampling case, we just appent to DYNINSTtags, if this
1504  * tag hasn't been seen before.
1505  * In the shm-sampling case, we _also_ call DYNINSTreportNewTags().
1506  * One might worry about infinite recursion (DYNINSTreportNewTags() calls
1507  * DYNINSTgenerateTraceRecord which calls write() which can be instrumented
1508  * to call DYNINSTrecordTag().....) but I don't think there's a problem.
1509  * Let's trace it through, assuming write() is instrumented to call
1510  * DYNINSTrecordTag() on entry:
1511  * 
1512  * -- write() is called by the program, which calls DYNINSTrecordTag.
1513  * -- DYNINSTrecordTag calls DYNINSTreportNewTags, which 
1514  *    calls DYNINSTgenerateTraceRecord, which calls write.
1515  * -- write() is instrumented to call DYNINSTrecordTag, so it does.
1516  *    the tag equals that of the trace fd.  If it's been seen already,
1517  *    then DYNINSTrecordTag returns before calling DYNINSTgenerateTraceRecord.
1518  *    If not, then it gets reported and then (the next time write() gets
1519  *    implicitly called) ignored in all future calls.
1520  *
1521  * So in summary, infinite recursion is probably not a problem because
1522  * DYNINSTrecordTag returns before calling DYNINSTreportNewTags
1523  * (and hence DYNINSTgenerateTraceRecord) if the tag has been seen
1524  * before.
1525  ************************************************************************/
1526 void DYNINSTrecordTagGroupInfo(int tagId, int tagDx,
1527                                int groupId, int groupDx)
1528 {
1529   DynInstTagSt* tagSt;
1530   int           dx;
1531   int           newGroup;
1532   
1533   if(TagGroupInfo.NumNewTags == DYNINSTNewTagsLimit) return;
1534
1535   tagSt = TagGroupInfo.GroupTable[groupDx];
1536   while((tagSt != NULL) && (tagSt->TagGroupId != groupId)) {
1537     tagSt = tagSt->Next;
1538   }
1539   if(tagSt == NULL) {
1540     tagSt = (DynInstTagSt *) malloc(sizeof(DynInstTagSt));
1541     assert(tagSt != NULL);
1542
1543     tagSt->TagGroupId = groupId;
1544     tagSt->TGUniqueId = DYNINSTTGroup_CreateUniqueId(groupId);
1545     tagSt->NumTags = 0;
1546     for(dx=0; dx < DYNINSTTagsLimit; dx++) {
1547       /* -99 has nothing special about it, just a num/tag which is not used. 
1548        * -1 can't be used since it is used to label collective messages within
1549        * a group
1550        */         
1551       tagSt->TagTable[dx] = -99;
1552     }
1553     tagSt->Next = TagGroupInfo.GroupTable[groupDx];
1554     TagGroupInfo.GroupTable[groupDx] = tagSt;
1555     TagGroupInfo.NumGroups++;
1556     newGroup = 1;
1557   } else {
1558     assert(tagSt->TagGroupId == groupId);
1559     newGroup = 0;
1560   }
1561
1562   if(tagSt->NumTags == DYNINSTTagsLimit) return;
1563
1564   dx = tagDx;
1565   while((tagSt->TagTable[dx] != tagId) && (tagSt->TagTable[dx] != -99)) {
1566     dx++;
1567     if(dx == DYNINSTTagsLimit) dx = 0;
1568     assert(dx != tagId);
1569   }
1570
1571   if(tagSt->TagTable[dx] == tagId) return;
1572
1573   assert(tagSt->TagTable[dx] == -99);
1574   tagSt->TagTable[dx] = tagId;
1575   tagSt->NumTags++;
1576   
1577   TagGroupInfo.NewTags[TagGroupInfo.NumNewTags][0] = tagId;
1578   TagGroupInfo.NewTags[TagGroupInfo.NumNewTags][1] = tagSt->TGUniqueId;
1579   TagGroupInfo.NewTags[TagGroupInfo.NumNewTags][2] = newGroup;
1580   TagGroupInfo.NumNewTags++;
1581
1582 #ifdef SHM_SAMPLING
1583   /* Usually, DYNINSTreportNewTags() is invoked only periodically, by
1584    * DYNINSTalarmExpire.  But since that routine no longer exists, we need
1585    * another way for it to be called.  Let's just call it directly here; I
1586    * don't think it'll be too expensive (unless a program declares a new
1587    * tag every fraction of a second!)  I also don't think there will be an
1588    * infinite recursion problem; see comment above.
1589    */
1590   DYNINSTreportNewTags();
1591 #endif    
1592 }
1593
1594
1595 void DYNINSTrecordTag(int tagId)
1596 {
1597   assert(tagId >= 0);
1598   assert(TagGroupInfo.TagHierarchy == 0); /* FALSE); */
1599   DYNINSTrecordTagGroupInfo(tagId, tagId % DYNINSTTagsLimit,
1600                             -1, 0);
1601 }
1602
1603 void DYNINSTrecordTagAndGroup(int tagId, int groupId)
1604 {
1605   assert(tagId >= 0);
1606   assert(groupId >= 0);
1607   TagGroupInfo.TagHierarchy = 1; /* TRUE; */
1608   DYNINSTrecordTagGroupInfo(tagId, (tagId % DYNINSTTagsLimit),
1609                             groupId, (groupId % DYNINSTTagGroupsLimit));
1610 }
1611
1612 void DYNINSTrecordGroup(int groupId)
1613 {
1614   assert(groupId >= 0);
1615   TagGroupInfo.TagHierarchy = 1;  /* TRUE; */
1616   DYNINSTrecordTagGroupInfo(-1, 0,
1617                             groupId, (groupId % DYNINSTTagGroupsLimit));
1618 }
1619
1620
1621 /************************************************************************
1622  * void DYNINSTreportCounter(intCounter* counter)
1623  *
1624  * report value of counter to paradynd.
1625 ************************************************************************/
1626 #ifndef SHM_SAMPLING
1627 void
1628 DYNINSTreportCounter(intCounter* counter) {
1629     traceSample sample;
1630
1631 #ifdef COSTTEST
1632     time64 endT;
1633     time64 startT=DYNINSTgetCPUtime();
1634 #endif
1635     time64 process_time = DYNINSTgetCPUtime();
1636     time64 wall_time = DYNINSTgetWalltime();
1637     sample.value = counter->value;
1638        /* WARNING: changes "int" to "float", with the associated problems of
1639                     normalized number gaps; hence, the value has likely changed
1640                     a bit (more for higher integers, say in the millions). */
1641     sample.id    = counter->id;
1642     DYNINSTtotalSamples++;
1643
1644     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample, 0,
1645                                wall_time, process_time);
1646
1647 #ifdef COSTTEST
1648     endT=DYNINSTgetCPUtime();
1649     DYNINSTtest[6]+=endT-startT;
1650     DYNINSTtestN[6]++;
1651 #endif 
1652
1653 }
1654 #endif
1655
1656
1657 /************************************************************************
1658  * void DYNINSTreportTimer(tTimer* timer)
1659  *
1660  * report the timer `timer' to the paradyn daemon.
1661 ************************************************************************/
1662 #ifndef SHM_SAMPLING
1663 void
1664 DYNINSTreportTimer(tTimer *timer) {
1665     time64 total;
1666     traceSample sample;
1667
1668 #ifdef COSTTEST
1669     time64 endT;
1670     time64 startT = DYNINSTgetCPUtime();
1671 #endif
1672
1673     time64 process_time = DYNINSTgetCPUtime();
1674     time64 wall_time = DYNINSTgetWalltime();
1675     if (timer->mutex) {
1676         total = timer->snapShot;
1677         //printf("id %d using snapshot value of %f\n", timer->id.id, (double)total);
1678     }
1679     else if (timer->counter) {
1680         /* timer is running */
1681         time64 now;
1682         if (timer->type == processTime) {
1683             now = process_time;
1684         } else {
1685             now = wall_time;
1686         }
1687         total = now - timer->start + timer->total;
1688         //printf("id %d using added-to-total value of %f\n", timer->id.id, (double)total);
1689     }
1690     else {
1691         total = timer->total;
1692         //printf("using %d total value of %f\n", timer->id.id, (double)total);
1693     }
1694
1695     if (total < timer->lastValue) {
1696         if (timer->type == processTime) {
1697             printf("process ");
1698         }
1699         else {
1700             printf("wall ");
1701         }
1702         printf("time regressed timer %d, total = %f, last = %f\n",
1703             timer->id.id, (float) total, (float) timer->lastValue);
1704         if (timer->counter) {
1705             printf("timer was active\n");
1706         } else {
1707             printf("timer was inactive\n");
1708         }
1709         printf("mutex=%d, counter=%d, snapShot=%f\n",
1710             (int) timer->mutex, (int) timer->counter,
1711             (double) timer->snapShot);
1712         printf("start = %f, total = %f\n",
1713                (double) timer->start, (double) timer->total);
1714         fflush(stdout);
1715         abort();
1716     }
1717
1718     timer->lastValue = total;
1719
1720     sample.id = timer->id;
1721     if (timer->normalize == 0) {
1722        fprintf(stderr, "DYNINSTreportTimer WARNING: timer->normalize is 0!!\n");
1723     }
1724
1725     sample.value = ((double) total) / (double) timer->normalize;
1726     // check for nan now?
1727        // NOTE: The type of sample.value is float, not double, so some precision
1728        //       is lost here.  Besides, wouldn't it be better to send the raw
1729        //       "total", with no loss in precision; especially since timer->normalize
1730        //       always seems to be 1 million? (Well, it differs for cm5)
1731     DYNINSTtotalSamples++;
1732
1733 #ifdef ndef
1734     printf("raw sample %d = %f time = %f\n", sample.id.id, sample.value,
1735                                 (double)(now/1000000.0));  
1736 #endif
1737
1738     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample, 0,
1739                                 wall_time,process_time);
1740
1741 #ifdef COSTTEST
1742     endT=DYNINSTgetCPUtime();
1743     DYNINSTtest[5]+=endT-startT;
1744     DYNINSTtestN[5]++;
1745 #endif 
1746 }
1747 #endif
1748
1749
1750
1751 /************************************************************************
1752  * DYNINST test functions.
1753  *
1754  * Since these routines aren't used regularly, shouldn't they be surrounded
1755  * with an ifdef? --ari
1756 ************************************************************************/
1757 void DYNINSTsimplePrint(void) {
1758     printf("inside dynamic inst function\n");
1759 }
1760
1761 void DYNINSTentryPrint(int arg) {
1762     printf("enter %d\n", arg);
1763 }
1764
1765 void DYNINSTcallFrom(int arg) {
1766     printf("call from %d\n", arg);
1767 }
1768
1769 void DYNINSTcallReturn(int arg) {
1770     printf("return to %d\n", arg);
1771 }
1772
1773 void DYNINSTexitPrint(int arg) {
1774     printf("exit %d\n", arg);
1775 }
1776
1777 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1778
1779 unsigned DYNINSTthreadTable[MAX_NUMBER_OF_THREADS][MAX_NUMBER_OF_LEVELS];
1780
1781 struct elemList {
1782   unsigned pos;
1783   struct elemList *next;
1784 };
1785
1786 struct elemList *DYNINST_freeList=NULL;
1787
1788 void DYNINST_add_free(unsigned pos)
1789 {
1790   struct elemList *tmp;
1791   tmp = (struct elemList *) malloc(sizeof(struct elemList));
1792   tmp->pos = pos;
1793   tmp->next = DYNINST_freeList;
1794   DYNINST_freeList = tmp;
1795 }
1796
1797 unsigned DYNINST_get_free()
1798 {
1799   unsigned pos;
1800   struct elemList *tmp;
1801   if (DYNINST_freeList) {
1802     pos = DYNINST_freeList->pos;
1803     tmp = DYNINST_freeList;
1804     DYNINST_freeList = DYNINST_freeList->next;
1805     free(tmp);
1806     return(pos);
1807   }
1808   abort();
1809 }
1810
1811 void DYNINST_initialize_free(unsigned total)
1812 {
1813   struct elemList *tmp;
1814   int i;
1815   for (i=0;i<total;i++) {
1816     tmp = (struct elemList *) malloc(sizeof(struct elemList));   
1817     tmp->pos = i;
1818     tmp->next = DYNINST_freeList;
1819     DYNINST_freeList = tmp;
1820   }
1821 }
1822
1823 #define HASH(x) (x % MAX_NUMBER_OF_THREADS)
1824
1825 struct nlist {
1826   unsigned key;
1827   unsigned val;
1828   struct nlist *next;
1829 };
1830
1831 struct nlist *DYNINST_ThreadTable[MAX_NUMBER_OF_THREADS];
1832 unsigned DYNINST_currentNumberOfThreads=0;
1833
1834 void DYNINST_initialize_hash(unsigned total)
1835 {
1836   int i;
1837   for (i=0;i<total;i++) DYNINST_ThreadTable[i]=NULL;
1838 }
1839
1840 unsigned DYNINST_hash_lookup(unsigned k)
1841 {
1842   unsigned pos;
1843   struct nlist *p;
1844   pos = HASH(k);
1845   p=DYNINST_ThreadTable[pos];
1846   while (p!=NULL) {
1847     if (p->key==k) break;
1848     else p=p->next;
1849   }
1850   assert(p!=NULL);
1851   return(p->val);
1852 }
1853
1854 unsigned DYNINST_hash_insert(unsigned k)
1855 {
1856   unsigned pos;
1857   struct nlist *p, *tmp;
1858   pos = HASH(k);
1859   p=DYNINST_ThreadTable[pos];
1860   if (p != NULL) {
1861     while (p!=NULL) {
1862       tmp=p;
1863       if (p->key==k) break;
1864       else p=p->next;
1865     }
1866     assert(p==NULL);
1867     assert(++DYNINST_currentNumberOfThreads<MAX_NUMBER_OF_THREADS);
1868     p = (struct nlist *) malloc(sizeof(struct nlist));
1869     p->next=NULL;
1870     p->key=k;
1871     p->val=DYNINST_get_free();
1872     tmp->next=p;
1873   } else {
1874     assert(++DYNINST_currentNumberOfThreads<MAX_NUMBER_OF_THREADS);
1875     p = (struct nlist *) malloc(sizeof(struct nlist));
1876     p->next=NULL;
1877     p->key=k;
1878     p->val=DYNINST_get_free();
1879     DYNINST_ThreadTable[pos]=p;
1880   }
1881   return(p->val);
1882 }
1883
1884 void DYNINST_hash_delete(unsigned k)
1885 {
1886   unsigned pos;
1887   struct nlist *p=NULL, *tmp=NULL;
1888   pos = HASH(k);
1889   p=DYNINST_ThreadTable[pos];
1890   assert(p);
1891   if (p->key==k) {
1892     DYNINST_ThreadTable[pos] = p->next;
1893     DYNINST_add_free(tmp->val);
1894     free(p);
1895   }
1896   else {
1897     while (p!=NULL) {
1898       if (p->key==k) break;
1899       else {
1900         tmp=p;
1901         p=p->next;
1902       }
1903     }
1904     assert(p!=NULL && tmp!=NULL);
1905     tmp->next = p->next;
1906     DYNINST_add_free(p->val);
1907     free(p);
1908   }
1909   DYNINST_currentNumberOfThreads--;
1910 }
1911
1912 /************************************************************************
1913  * void DYNINSTthreadCreate()
1914  *
1915  * track a thr_create() system call, and report to the paradyn daemon.
1916  ************************************************************************/
1917 void
1918 DYNINSTthreadCreate(int *tid) {
1919     traceThread traceRec;
1920     time64 process_time = DYNINSTgetCPUtime();
1921     time64 wall_time = DYNINSTgetWalltime();
1922     traceRec.ppid   = getpid();
1923     traceRec.tid    = *tid;
1924     traceRec.ntids  = 1;
1925     traceRec.stride = 0;
1926     DYNINSTgenerateTraceRecord(0,TR_THREAD,sizeof(traceRec), &traceRec, 1,
1927                                wall_time,process_time);
1928     hash_insert(*tid);
1929 }
1930 #endif
1931
1932
1933 /************************************************************************
1934  *
1935  ************************************************************************/
1936 int DYNINSTTGroup_CreateUniqueId(int commId)
1937 {
1938 #ifdef PARADYN_MPI
1939   MPI_Group commGroup;
1940   MPI_Group worldGroup;
1941   int       ranks1[1];
1942   int       ranks2[1];
1943   int       rc;
1944
1945   // assert(commId < (1<<16));
1946   assert(commId < 100000);
1947   
1948   rc = MPI_Comm_group(commId, &commGroup);
1949   assert(rc == 0);
1950   rc = MPI_Comm_group(MPI_COMM_WORLD, &worldGroup);
1951   assert(rc == 0);
1952   
1953   ranks1[0] = 0;
1954   rc = MPI_Group_translate_ranks(commGroup, 1, ranks1, worldGroup, ranks2);
1955   assert(rc == 0);
1956
1957   assert(ranks2[0] != MPI_UNDEFINED);
1958   // assert(ranks2[0] < (1 << 16));
1959   // return(commId + (ranks2[0] * (1<<16)));
1960   assert(ranks2[0] < 20000);
1961   return(commId + (ranks2[0] * 100000));
1962 #else
1963   return(commId);
1964 #endif
1965 }
1966
1967
1968
1969 /************************************************************************
1970  *
1971  ************************************************************************/
1972 int DYNINSTTGroup_CreateLocalId(int tgUniqueId)
1973 {
1974 #ifdef PARADYN_MPI
1975   // return(tgUniqueId | ((1<<16)-1));
1976   return(tgUniqueId % 100000);
1977 #else
1978   return(tgUniqueId);
1979 #endif
1980 }
1981
1982
1983 /************************************************************************
1984  *
1985  ************************************************************************/
1986 int DYNINSTTGroup_FindUniqueId(int groupId)
1987 {
1988   int           groupDx = groupId % DYNINSTTagGroupsLimit;
1989   DynInstTagSt* tagSt;
1990
1991   for(tagSt = TagGroupInfo.GroupTable[groupDx]; tagSt != NULL;
1992       tagSt = tagSt->Next) {
1993     if(tagSt->TagGroupId == groupId) return(tagSt->TGUniqueId);
1994   }
1995   return(-1);
1996 }
1997
1998
1999 int DYNINSTTwoComparesAndedExpr(int arg1, int arg2, int arg3, int arg4)
2000 {
2001   return((arg1 == arg2) && (arg3 == arg4));
2002 }
2003
2004 int DYNINSTCountElmsInArray(int* array, int num)
2005 {
2006   int sum = 0;
2007
2008   for(num--; num >= 0; num--) {
2009     sum += array[num];
2010   }
2011   return(sum);
2012 }
2013
2014 int DYNINSTSub(int num1, int num2)
2015 {
2016   return(num1-num2);
2017 }
2018
2019 int DYNINSTAdd(int num1, int num2)
2020 {
2021   return(num1+num2);
2022 }
2023
2024 int DYNINSTMult(int num1, int num2)
2025 {
2026   return(num1*num2);
2027 }
2028
2029 int DYNINSTArrayField(int* array, int index)
2030 {
2031   return(array[index]);
2032 }