Made Boolean type RT_Boolean to prevent picking up a different boolean
[dyninst.git] / rtinst / src / RTposix.c
1 /*
2  * Copyright (c) 1993, 1994 Barton P. Miller, Jeff Hollingsworth,
3  *     Bruce Irvin, Jon Cargille, Krishna Kunchithapadam, Karen
4  *     Karavanic, Tia Newhall, Mark Callaghan.  All rights reserved.
5  * 
6  * This software is furnished under the condition that it may not be
7  * provided or otherwise made available to, or used by, any other
8  * person, except as provided for by the terms of applicable license
9  * agreements.  No title to or ownership of the software is hereby
10  * transferred.  The name of the principals may not be used in any
11  * advertising or publicity related to this software without specific,
12  * written prior authorization.  Any use of this software must include
13  * the above copyright notice.
14  *
15  */
16
17
18 \f
19
20
21 /************************************************************************
22  * RTposix.c: runtime instrumentation functions for generic posix.
23 ************************************************************************/
24
25
26 \f
27
28
29 /************************************************************************
30  * header files.
31 ************************************************************************/
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <memory.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/time.h>
42 #include <unistd.h>
43
44 #include <math.h>
45
46 #include "kludges.h"
47 #include "rtinst/h/rtinst.h"
48 #include "rtinst/h/trace.h"
49
50
51 \f
52
53
54 /************************************************************************
55  * symbolic constants.
56 ************************************************************************/
57
58 static const double MILLION = 1000000.0;
59
60
61 \f
62
63
64 /************************************************************************
65  * external functions.
66 ************************************************************************/
67
68 extern void   DYNINSTos_init(void);
69 extern time64 DYNINSTgetCPUtime(void);
70 extern time64 DYNINSTgetWalltime(void);
71
72
73 \f
74
75
76 /************************************************************************
77  * time64 DYNINSTgetUserTime(void)
78  *
79  * get the user time for "an" LWP of the monitored process.
80 ************************************************************************/
81
82 time64
83 DYNINSTgetUserTime(void) {
84     return DYNINSTgetCPUtime();
85 }
86
87
88 \f
89
90
91 /************************************************************************
92  * void DYNINSTbreakPoint(void)
93  *
94  * stop oneself.
95 ************************************************************************/
96
97 void
98 DYNINSTbreakPoint(void) {
99     kill(getpid(), SIGSTOP);
100 }
101
102
103 \f
104
105
106 /************************************************************************
107  * void DYNINSTstartProcessTimer(tTimer* timer)
108 ************************************************************************/
109
110 void
111 DYNINSTstartProcessTimer(tTimer* timer) {
112     if (timer->counter == 0) {
113         timer->start     = DYNINSTgetUserTime();
114         timer->normalize = MILLION;
115     }
116     timer->counter++;
117 }
118
119
120 \f
121
122
123 /************************************************************************
124  * void DYNINSTstopProcessTimer(tTimer* timer)
125 ************************************************************************/
126
127 void
128 DYNINSTstopProcessTimer(tTimer* timer) {
129     if (!timer->counter) {
130         return;
131     }
132
133     if (timer->counter == 1) {
134         time64 now = DYNINSTgetUserTime();
135
136         timer->snapShot = now - timer->start + timer->total;
137         timer->mutex    = 1;
138         timer->counter  = 0;
139         timer->total    = DYNINSTgetUserTime() - timer->start + timer->total;
140         timer->mutex    = 0;
141
142         if (now < timer->start) {
143             printf("id=%d, snapShot=%f total=%f, \n start=%f  now=%f\n",
144                    timer->id.id, (double)timer->snapShot, (double)timer->total, 
145                    (double)timer->start, (double)now);
146             printf("process timer rollback\n"); fflush(stdout);
147             abort();
148         }
149     }
150     else {
151         timer->counter--;
152     }
153 }
154
155
156 \f
157
158
159 /************************************************************************
160  * void DYNINSTstartWallTimer(tTimer* timer)
161 ************************************************************************/
162
163 void
164 DYNINSTstartWallTimer(tTimer* timer) {
165     if (timer->counter == 0) {
166         timer->start     = DYNINSTgetWalltime();
167         timer->normalize = MILLION;
168     }
169     timer->counter++;
170 }
171
172
173 \f
174
175
176 /************************************************************************
177  * void DYNINSTstopWallTimer(tTimer* timer)
178 ************************************************************************/
179
180 void
181 DYNINSTstopWallTimer(tTimer* timer) {
182     if (!timer->counter) {
183         return;
184     }
185
186     if (timer->counter == 1) {
187         time64 now = DYNINSTgetWalltime();
188
189         timer->snapShot = now - timer->start + timer->total;
190         timer->mutex    = 1;
191         timer->counter  = 0;
192         timer->total    = DYNINSTgetWalltime() - timer->start + timer->total;
193         timer->mutex    = 0;
194
195         if (now < timer->start) {
196             printf("wall timer rollback\n"); fflush(stdout);
197             abort();
198         }
199     }
200     else {
201         timer->counter--;
202     }
203 }
204
205
206 \f
207
208
209 /************************************************************************
210  * void DYNINSTpauseProcess(void)
211  * void DYNINSTcontinueProcess(void)
212  *
213  * pause and continue process.
214 ************************************************************************/
215
216 static volatile int DYNINSTpauseDone = 0;
217
218 void
219 DYNINSTpauseProcess(void) {
220     DYNINSTpauseDone = 0;
221     while (!DYNINSTpauseDone) {
222     }
223 }
224
225 void
226 DYNINSTcontinueProcess(void) {
227     DYNINSTpauseDone = 1;
228 }
229
230
231 \f
232
233
234 /************************************************************************
235  * void DYNINST_install_ualarm(unsigned value, unsigned interval)
236  *
237  * an implementation of "ualarm" using the "setitimer" syscall.
238 ************************************************************************/
239
240 static void
241 DYNINST_install_ualarm(unsigned value, unsigned interval) {
242     struct itimerval it;
243
244     it.it_value.tv_sec     = value    / 1000000;
245     it.it_value.tv_usec    = value    % 1000000;
246     it.it_interval.tv_sec  = interval / 1000000;
247     it.it_interval.tv_usec = interval % 1000000;
248
249     if (setitimer(ITIMER_REAL, &it, 0) == -1) {
250         perror("setitimer");
251         abort();
252     }
253 }
254
255
256 \f
257
258
259 /************************************************************************
260  * global data for DYNINST functions.
261 ************************************************************************/
262
263 double DYNINSTdata[SYN_INST_BUF_SIZE/sizeof(double)];
264 double DYNINSTglobalData[SYN_INST_BUF_SIZE/sizeof(double)];
265
266
267 \f
268
269
270 /************************************************************************
271  * float DYNINSTcyclesPerSecond(void)
272  *
273  * need a well-defined method for finding the CPU cycle speed
274  * on each CPU.
275 ************************************************************************/
276
277 #define NOPS_4  asm("nop"); asm("nop"); asm("nop"); asm("nop")
278 #define NOPS_16 NOPS_4; NOPS_4; NOPS_4; NOPS_4
279
280 static float
281 DYNINSTcyclesPerSecond(void) {
282     int            i;
283     time64         start_cpu;
284     time64         end_cpu;
285     double         elapsed;
286     double         speed;
287     const unsigned LOOP_LIMIT = 50000;
288
289     start_cpu = DYNINSTgetCPUtime();
290     for (i = 0; i < LOOP_LIMIT; i++) {
291         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
292         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
293         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
294         NOPS_16; NOPS_16; NOPS_16; NOPS_16;
295     }
296     end_cpu = DYNINSTgetCPUtime();
297     elapsed = (double) end_cpu - start_cpu;
298     speed   = (MILLION*256*LOOP_LIMIT)/elapsed;
299
300     /* printf("elapsed = %f\n", elapsed); */
301     /* printf("speed   = %f\n", speed); */
302
303     return speed;
304 }
305
306
307 \f
308
309
310 /************************************************************************
311  * void saveFPUstate(float* base)
312  * void restoreFPUstate(float* base)
313  *
314  * save and restore state of FPU on signals.  these are null functions
315  * for most well designed and implemented systems.
316 ************************************************************************/
317
318 static void
319 saveFPUstate(float* base) {
320 }
321
322 static void
323 restoreFPUstate(float* base) {
324 }
325
326
327 \f
328
329 /* The current observed cost since the last call to 
330  *      DYNINSTgetObservedCycles(false) 
331  */
332 unsigned DYNINSTobsCostLow;
333
334 /************************************************************************
335  * int64 DYNINSTgetObservedCycles(RT_Boolean in_signal)
336  *
337  * report the observed cost of instrumentation in machine cycles.
338  *
339  * We keep cost as a 64 bit int, but the code generated by dyninst is
340  *   a 32 bit counter (for speed).  So this function also converts the
341  *   cost into a 64 bit value.
342  ************************************************************************/
343 static int64 DYNINSTgetObservedCycles(RT_Boolean in_signal) 
344 {
345     static int64    value = 0;
346
347     if (in_signal) {
348         return value;
349     }
350
351     /* update the 64 bit version of the counter */
352     value += DYNINSTobsCostLow;
353
354     /* reset the low counter */
355     DYNINSTobsCostLow = 0;
356     return value;
357 }
358
359
360 \f
361
362
363 /************************************************************************
364  * void DYNINSTsampleValues(void)
365  *
366  * dummy function for sampling timers and counters.  the actual code
367  * is added by dynamic instrumentation from the paradyn daemons.
368 ************************************************************************/
369
370 static int DYNINSTnumReported = 0;
371
372 void
373 DYNINSTsampleValues(void) {
374     DYNINSTnumReported++;
375 }
376
377
378 \f
379
380
381 /************************************************************************
382  * void DYNINSTflushTrace(void)
383  *
384  * flush any accumalated traces.
385 ************************************************************************/
386
387 static FILE* DYNINSTtraceFp = 0;
388
389 static void
390 DYNINSTflushTrace(void) {
391     if (DYNINSTtraceFp) fflush(DYNINSTtraceFp);
392 }
393
394
395 \f
396
397
398 /************************************************************************
399  * void DYNINSTgenerateTraceRecord(traceStream sid, short type,
400  *                                 short length, void* data, int flush)
401 ************************************************************************/
402
403 static time64 startWall = 0;
404
405 void
406 DYNINSTgenerateTraceRecord(traceStream sid, short type, short length,
407     void *eventData, int flush) {
408     int             ret;
409     static unsigned pipe_gone = 0;
410     traceHeader     header;
411     int             count;
412     char            buffer[1024];
413
414     if (pipe_gone) {
415         return;
416     }
417
418     header.wall    = DYNINSTgetWalltime() - startWall;
419     header.process = DYNINSTgetCPUtime();
420
421     length = ALIGN_TO_WORDSIZE(length);
422
423     header.type   = type;
424     header.length = length;
425
426     count = 0;
427     memcpy(&buffer[count], &sid, sizeof(traceStream));
428     count += sizeof(traceStream);
429
430     memcpy(&buffer[count], &header, sizeof(header));
431     count += sizeof(header);
432
433     count = ALIGN_TO_WORDSIZE(count);
434     memcpy(&buffer[count], eventData, length);
435     count += length;
436
437     errno = 0;
438
439     if (!DYNINSTtraceFp || (type == TR_EXIT)) {
440         DYNINSTtraceFp = fdopen(dup(CONTROLLER_FD), "w");
441     }
442
443     ret = fwrite(buffer, count, 1, DYNINSTtraceFp);
444     if (ret != 1) {
445         printf("unable to write trace record, errno=%d\n", errno);
446         printf("disabling further data logging, pid=%d\n", (int) getpid());
447         fflush(stdout);
448         pipe_gone = 1;
449     }
450     if (flush) DYNINSTflushTrace();
451 }
452
453
454 \f
455
456
457 /************************************************************************
458  * void DYNINSTreportBaseTramps(void)
459  *
460  * report the cost of base trampolines.
461 ************************************************************************/
462
463 static float DYNINSTcyclesToUsec  = 0;
464 static time64 DYNINSTlastWallTime = 0;
465 static time64 DYNINSTlastCPUTime  = 0;
466
467 void
468 DYNINSTreportBaseTramps() {
469     costUpdate sample;
470     time64     currentCPU;
471     time64     currentWall;
472     time64     elapsedWallTime;
473     time64     currentPauseTime;
474
475     sample.slotsExecuted = 0;
476     sample.observedCost  = ((double) DYNINSTgetObservedCycles(1)) *
477         (DYNINSTcyclesToUsec / MILLION);
478
479
480     currentCPU       = DYNINSTgetCPUtime();
481     currentWall      = DYNINSTgetWalltime();
482     elapsedWallTime  = currentWall - DYNINSTlastWallTime;
483     currentPauseTime = elapsedWallTime - (currentCPU - DYNINSTlastCPUTime);
484
485     sample.pauseTime  = ((double) currentPauseTime);
486     sample.pauseTime /= 1000000.0;
487
488     DYNINSTlastWallTime = currentWall;
489     DYNINSTlastCPUTime  = currentCPU;
490
491     DYNINSTgenerateTraceRecord(0, TR_COST_UPDATE, sizeof(sample), &sample, 0);
492 }
493
494
495 \f
496
497
498 /************************************************************************
499  * void DYNINSTalarmExpire(void)
500  *
501  * called periodically by signal handlers.  report sampled data back
502  * to the paradyn daemons.  when the program exits, DYNINSTsampleValues
503  * should be called directly.
504 ************************************************************************/
505
506 #define N_FP_REGS 33
507
508 static volatile int DYNINSTsampleMultiple    = 1;
509 static int          DYNINSTnumSampled        = 0;
510 static int          DYNINSTtotalAlarmExpires = 0;
511 static time64       DYNINSTtotalSampleTime   = 0;
512
513 void
514 DYNINSTalarmExpire(int signo) {
515     time64     start_cpu;
516     time64     end_cpu;
517     static int in_sample = 0;
518     float      fp_context[N_FP_REGS];
519
520     if (in_sample) {
521         return;
522     }
523     in_sample = 1;
524
525     DYNINSTtotalAlarmExpires++;
526     if ((++DYNINSTnumSampled % DYNINSTsampleMultiple) == 0) {
527         saveFPUstate(fp_context);
528         start_cpu = DYNINSTgetCPUtime();
529
530         /* to keep observed cost accurate due to 32-cycle rollover */
531         (void) DYNINSTgetObservedCycles(0);
532
533         DYNINSTsampleValues();
534         DYNINSTreportBaseTramps();
535         DYNINSTflushTrace();
536
537         end_cpu = DYNINSTgetCPUtime();
538         DYNINSTtotalSampleTime += (end_cpu - start_cpu);
539         restoreFPUstate(fp_context);
540     }
541
542     in_sample = 0;
543 }
544
545
546 \f
547
548
549 /************************************************************************
550  * void DYNINSTinit(int doskip)
551  *
552  * initialize the DYNINST library.  this function is called at the start
553  * of the application program.
554  *
555  * the first this to do is to call the os specific initialization
556  * function.
557 ************************************************************************/
558
559 static float  DYNINSTsamplingRate   = 0;
560 static int    DYNINSTtotalSamples   = 0;
561 static tTimer DYNINSTelapsedCPUTime;
562 static tTimer DYNINSTelapsedTime;
563
564 void
565 DYNINSTinit(int doskip) {
566     struct sigaction act;
567     unsigned         val;
568     const char*      interval;
569
570     DYNINSTos_init();
571
572     startWall = 0;
573
574     DYNINSTcyclesToUsec = MILLION/DYNINSTcyclesPerSecond();
575     DYNINSTlastCPUTime  = DYNINSTgetCPUtime();
576     DYNINSTlastWallTime = DYNINSTgetWalltime();
577
578     act.sa_handler = DYNINSTalarmExpire;
579     act.sa_flags   = 0;
580 #if defined(SA_INTERRUPT)
581     act.sa_flags  |= SA_INTERRUPT;
582 #endif /* defined(SA_INTERRUPT) */
583     sigfillset(&act.sa_mask);
584
585     if (sigaction(SIGALRM, &act, 0) == -1) {
586         perror("sigaction(SIGALRM)");
587         abort();
588     }
589
590     val = 500000;
591     interval = getenv("DYNINSTsampleInterval");
592     if (interval) {
593         val = atoi(interval);
594     }
595     DYNINSTsamplingRate = val/MILLION;
596
597     DYNINST_install_ualarm(val, val);
598
599     /* printf("Time at main %g us\n", (double) DYNINSTgetCPUtime()); */
600     if (!doskip) {
601         DYNINSTbreakPoint();
602     }
603
604     DYNINSTstartWallTimer(&DYNINSTelapsedTime);
605     DYNINSTstartProcessTimer(&DYNINSTelapsedCPUTime);
606 }
607
608
609 \f
610
611
612 /************************************************************************
613  * void DYNINSTexit(void)
614  *
615  * handle `exit' in the application. current nothing is done.
616 ************************************************************************/
617
618 void
619 DYNINSTexit(void) {
620 }
621
622
623 \f
624
625
626 /************************************************************************
627  * void DYNINSTreportTimer(tTimer* timer)
628  *
629  * report the timer `timer' to the paradyn daemon.
630 ************************************************************************/
631
632 void
633 DYNINSTreportTimer(tTimer *timer) {
634     time64 now = 0;
635     time64 total;
636     traceSample sample;
637
638     if (timer->mutex) {
639         total = timer->snapShot;
640     }
641     else if (timer->counter) {
642         /* timer is running */
643         if (timer->type == processTime) {
644             now = DYNINSTgetUserTime();
645         } else {
646             now = DYNINSTgetWalltime();
647         }
648         total = now - timer->start + timer->total;
649     }
650     else {
651         total = timer->total;
652     }
653
654     if (total < timer->lastValue) {
655         if (timer->type == processTime) {
656             printf("process ");
657         }
658         else {
659             printf("wall ");
660         }
661         printf("time regressed timer %d, total = %f, last = %f\n",
662             timer->id.id, (float) total, (float) timer->lastValue);
663         if (timer->counter) {
664             printf("timer was active\n");
665         } else {
666             printf("timer was inactive\n");
667         }
668         printf("mutex=%d, counter=%d, sampled=%d, snapShot=%f\n",
669             (int) timer->mutex, (int) timer->counter, (int) timer->sampled,
670             (double) timer->snapShot);
671         printf("now = %f, start = %f, total = %f\n",
672             (double) now, (double) timer->start, (double) timer->total);
673         fflush(stdout);
674         abort();
675     }
676
677     timer->lastValue = total;
678
679     sample.id = timer->id;
680     sample.value = ((double) total) / (double) timer->normalize;
681     DYNINSTtotalSamples++;
682
683     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample, 0);
684     /* printf("raw sample %d = %f\n", sample.id.id, sample.value); */
685 }
686
687
688 \f
689
690
691 /************************************************************************
692  * void DYNINSTfork(void* arg, int pid)
693  *
694  * track a fork() system call, and report to the paradyn daemon.
695 ************************************************************************/
696
697 void
698 DYNINSTfork(void* arg, int pid) {
699     int sid = 0;
700     traceFork forkRec;
701
702     printf("fork called with pid = %d\n", pid);
703     fflush(stdout);
704     if (pid > 0) {
705         forkRec.ppid   = getpid();
706         forkRec.pid    = pid;
707         forkRec.npids  = 1;
708         forkRec.stride = 0;
709         DYNINSTgenerateTraceRecord(sid,TR_FORK,sizeof(forkRec), &forkRec, 1);
710     } else {
711         DYNINSTinit(1);
712     }
713 }
714
715
716 \f
717
718
719 /************************************************************************
720  * void DYNINSTprintCost(void)
721  *
722  * print a detailed summary of the cost of the application's run.
723 ************************************************************************/
724
725 void
726 DYNINSTprintCost(void) {
727     FILE *fp;
728     time64 now;
729     int64 value;
730     struct endStatsRec stats;
731
732     DYNINSTstopProcessTimer(&DYNINSTelapsedCPUTime);
733     DYNINSTstopWallTimer(&DYNINSTelapsedTime);
734
735     value = DYNINSTgetObservedCycles(0);
736     stats.instCycles = value;
737
738     value *= DYNINSTcyclesToUsec;
739
740     stats.alarms      = DYNINSTtotalAlarmExpires;
741     stats.numReported = DYNINSTnumReported;
742     stats.instTime    = ((double) value)/MILLION;
743     stats.handlerCost = ((double) DYNINSTtotalSampleTime)/MILLION;
744
745     now = DYNINSTgetCPUtime();
746     stats.totalCpuTime  = ((double) DYNINSTelapsedCPUTime.total)/MILLION;
747     stats.totalWallTime = ((double) DYNINSTelapsedTime.total/MILLION);
748
749     stats.samplesReported = DYNINSTtotalSamples;
750     stats.samplingRate    = DYNINSTsamplingRate;
751
752     stats.userTicks = 0;
753     stats.instTicks = 0;
754
755     fp = fopen("stats.out", "w");
756
757     fprintf(fp, "DYNINSTtotalAlarmExpires %d\n", stats.alarms);
758     fprintf(fp, "DYNINSTnumReported %d\n", stats.numReported);
759     fprintf(fp,"Raw cycle count = %f\n", (double) stats.instCycles);
760     fprintf(fp,"Total instrumentation cost = %f\n", stats.instTime);
761     fprintf(fp,"Total handler cost = %f\n", stats.handlerCost);
762     fprintf(fp,"Total cpu time of program %f\n", stats.totalCpuTime);
763     fprintf(fp,"Elapsed wall time of program %f\n",
764         stats.totalWallTime/1000000.0);
765     fprintf(fp,"total data samples %d\n", stats.samplesReported);
766     fprintf(fp,"sampling rate %f\n", stats.samplingRate);
767     fprintf(fp,"Application program ticks %d\n", stats.userTicks);
768     fprintf(fp,"Instrumentation ticks %d\n", stats.instTicks);
769
770     fclose(fp);
771
772     /* record that we are done -- should be somewhere better. */
773     DYNINSTgenerateTraceRecord(0, TR_EXIT, sizeof(stats), &stats, 1);
774 }
775
776
777 \f
778
779
780 /************************************************************************
781  * void DYNINSTrecordTag(int tag)
782  *
783  * mark a new tag in tag list.
784 ************************************************************************/
785
786 static int DYNINSTtagCount = 0;
787 static int DYNINSTtagLimit = 1000;
788 static int DYNINSTtags[1000];
789
790 void
791 DYNINSTrecordTag(int tag) {
792     int i;
793
794     for (i=0; i < DYNINSTtagCount; i++) {
795         if (DYNINSTtags[i] == tag) return;
796     }
797
798     if (DYNINSTtagCount == DYNINSTtagLimit) abort();
799     DYNINSTtags[DYNINSTtagCount++] = tag;
800 }
801
802
803 \f
804
805
806 /************************************************************************
807  * void DYNINSTreportNewTags(void)
808  *
809  * inform the paradyn daemons of new message tags.
810 ************************************************************************/
811
812 void
813 DYNINSTreportNewTags(void) {
814     int i;
815     static int lastTagCount;
816     struct _newresource newRes;
817
818     for (i=lastTagCount; i < DYNINSTtagCount; i++) {
819         memset(&newRes, '\0', sizeof(newRes));
820         sprintf(newRes.name, "SyncObject/MsgTag/%d", DYNINSTtags[i]);
821         strcpy(newRes.abstraction, "BASE");
822         DYNINSTgenerateTraceRecord(0, TR_NEW_RESOURCE, 
823             sizeof(struct _newresource), &newRes, 1);
824     }
825     lastTagCount = DYNINSTtagCount;
826 }
827
828
829 \f
830
831
832 /************************************************************************
833  * void DYNINSTreportCounter(intCounter* counter)
834  *
835  * report value of counter to paradynd.
836 ************************************************************************/
837
838 void
839 DYNINSTreportCounter(intCounter* counter) {
840     traceSample sample;
841
842     sample.value = counter->value;
843     sample.id    = counter->id;
844     DYNINSTtotalSamples++;
845
846     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample, 0);
847 }
848
849
850 \f
851
852
853 /************************************************************************
854  * DYNINST test functions.
855 ************************************************************************/
856
857 void DYNINSTsimplePrint(void) {
858     printf("inside dynamic inst function\n");
859 }
860
861 void DYNINSTentryPrint(int arg) {
862     printf("enter %d\n", arg);
863 }
864
865 void DYNINSTcallFrom(int arg) {
866     printf("call from %d\n", arg);
867 }
868
869 void DYNINSTcallReturn(int arg) {
870     printf("return to %d\n", arg);
871 }
872
873 void DYNINSTexitPrint(int arg) {
874     printf("exit %d\n", arg);
875 }
876
877
878 \f
879
880
881 /************************************************************************
882  * void DYNINSTreportCost(intCounter* counter)
883  *
884  * report the cost (from the cost model).
885 ************************************************************************/
886
887 void
888 DYNINSTreportCost(intCounter *counter) {
889     int64         value;
890     double        cost;
891     static double prev_cost = 0;
892     traceSample   sample;
893
894     value = DYNINSTgetObservedCycles(1);
895     cost  = ((double) value) * (DYNINSTcyclesToUsec / MILLION);
896     if (cost < prev_cost) {
897         fprintf(stderr, "Fatal Error: cost counter went backwards\n");
898         fflush(stderr);
899         abort();
900     }
901
902     prev_cost = cost;
903
904     sample.value = cost;
905     sample.id    = counter->id;
906     DYNINSTtotalSamples++;
907
908     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof sample, &sample, 0);
909 }