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