Major CM5 commit: include syntax changes, some timer changes, removal
[dyninst.git] / rtinst / src / RTcm5_pn.c
1 /*
2  * This file contains the implementation of runtime dynamic instrumentation
3  *   functions for a TMC CM-5 machine.
4  *
5  *
6  * $Log: RTcm5_pn.c,v $
7  * Revision 1.11  1994/07/11 22:47:47  jcargill
8  * Major CM5 commit: include syntax changes, some timer changes, removal
9  * of old aggregation code, old pause code, added signal-driven sampling
10  * within node processes
11  *
12  * Revision 1.10  1993/12/14  17:27:21  jcargill
13  * Put sampleMultiple and length alignment fixes back, and one retry fix
14  *
15  * Revision 1.9  1993/12/14  16:35:27  hollings
16  * moved getProcessTime() out of the ifdef notdef.
17  *
18  * Revision 1.8  1993/12/13  19:47:06  hollings
19  * use assembly version of clock code.
20  *
21  * Revision 1.7  1993/10/19  15:29:58  hollings
22  * new simpler primitives.
23  *
24  * Revision 1.6  1993/10/07  19:09:12  jcargill
25  * Added true combines for global instrumentation
26  *
27  * Revision 1.5  1993/10/01  18:15:53  hollings
28  * Added filtering and resource discovery.
29  *
30  * Revision 1.4  1993/09/02  22:09:38  hollings
31  * fixed race condition caused be no re-trying sampling of process time.
32  *
33  * Revision 1.3  1993/08/26  23:07:34  hollings
34  * made initTraceLibPN called from DYNINSTinitTraceLib.
35  *
36  * Revision 1.2  1993/07/02  21:53:33  hollings
37  * removed unnecessary include files
38  *
39  * Revision 1.1  1993/07/02  21:49:35  hollings
40  * Initial revision
41  *
42  *
43  */
44 #include <stdlib.h>
45 /* #include <signal.h> */
46 #include <assert.h>
47
48 /* our include files */
49 #include "rtinst/h/rtinst.h"
50 #include "rtinst/h/trace.h"
51 #define extern
52 #include "traceio.h"
53 #undef extern
54
55 #include <cm/timers.h>
56 #include <cm/cmmd/amx.h>
57 #include <cm/cmmd/mp.h>
58 #include <cm/cmmd/cn.h>
59 #include <cm/cmmd/io.h>
60 #include <cm/cmmd/util.h>
61 #include <cm/cmmd/cmmd_constants.h>
62 #include <cm/cmmd.h>
63 #include <cmsys/cm_signal.h>
64 #define pe_obj
65 #include <cm/cmna.h>
66 #include <cmsys/ni_interface.h>
67
68 #include <stdio.h>
69 #include <string.h>
70 #include <sys/types.h>
71 #include <sys/stdtypes.h>
72 #include <sys/time.h>
73 #include <sys/timeb.h>
74 #include <dirent.h>
75 #include <sys/stat.h>
76 #include <sys/vfs.h>
77 #include <cm/cm_file.h>
78 #include <cm/cm_errno.h>
79 #include <errno.h>
80 #include <sys/un.h>
81 #include <sys/socket.h>
82 #include <netdb.h>
83 #include <netinet/in.h>
84 #include <fcntl.h>
85 #include <sys/filio.h>
86 #include <math.h>
87
88 #define NI_CLK_USEC 33
89 #define MILLION 1000000
90
91
92 char *TRACELIBcurrPtr;          /* current pointer in buffer  */
93 char *TRACELIBfreePtr;          /* pointer to next free byte in buffer */
94 char *TRACELIBendPtr;           /* last byte in trace buffer */
95 char *TRACELIBtraceBuffer;      /* beginning of trace buffer */
96 int TRACELIBmustRetry;          /* signal variable from consumer -> producer */
97
98 #ifdef notdef
99 time64 inline getProcessTime()
100 {
101     time64 end;
102     time64 ni_end;
103     time64 ni2;
104
105 retry:
106     CMOS_get_NI_time(&ni_end);
107     CMOS_get_time((CM_TIME) &end);
108     CMOS_get_NI_time(&ni2);
109     if (ni_end != ni2) goto retry;
110     return(end-ni_end);
111 }
112 #endif
113
114 struct timer_buf {
115     unsigned int high;
116     unsigned int sync;
117     time64   ni_time;
118 /*   instead of: */
119 /*     unsigned int ni_time_high; */
120 /*     unsigned int ni_time_low; */
121     unsigned int trap_start;
122     unsigned int trap_cnt;
123     unsigned int trap_time;
124 };
125
126 typedef union {
127     struct {
128         unsigned int high;
129         unsigned int low;
130     } parts;
131     time64 value;
132 } timeParts;
133
134 static volatile unsigned int *ni;
135 volatile struct timer_buf timerBuffer;
136
137 time64 DYNINSTgetCPUtime()
138 {
139      time64 now;
140
141      now = getProcessTime();
142      now /= NI_CLK_USEC * MILLION;
143
144      return(now);
145 }
146
147
148 inline time64 getProcessTime()
149 {
150     timeParts end;
151     time64 ni_end;
152
153 retry:
154     timerBuffer.sync = 1;
155     ni_end = timerBuffer.ni_time;
156     end.parts.high = timerBuffer.high;
157     end.parts.low = *ni;
158     if (timerBuffer.sync != 1) goto retry;
159     return(end.value-ni_end);
160 }
161
162 /* #ifdef notdef */
163 inline time64 getWallTime()
164 {
165     timeParts end;
166
167 retry:
168     timerBuffer.sync = 1;
169     end.parts.high = timerBuffer.high;
170     end.parts.low = *ni;
171     if (timerBuffer.sync != 1) goto retry;
172     return(end.value);
173 }
174
175 void DYNINSTstartWallTimer(tTimer *timer)
176 {
177     if (timer->counter == 0) {
178          timer->start = getWallTime();
179     }
180     /* this must be last to prevent race conditions with the sampler */
181     timer->counter++;
182 }
183
184 void DYNINSTstopWallTimer(tTimer *timer)
185 {
186     time64 now;
187
188     if (!timer->counter) return;
189
190     if (timer->counter == 1) {
191          now = getWallTime();
192          timer->snapShot = timer->total + now - timer->start;
193          timer->mutex = 1;
194          timer->counter = 0;
195          timer->total = timer->snapShot;
196          timer->mutex = 0;
197     } else {
198         timer->counter--;
199     }
200 }
201
202 void DYNINSTstartProcessTimer(tTimer *timer)
203 {
204     if (timer->counter == 0) {
205          timer->start = getProcessTime();
206     }
207     /* this must be last to prevent race conditions with the sampler */
208     timer->counter++;
209 }
210
211
212 void DYNINSTstopProcessTimer(tTimer *timer)
213 {
214     time64 end;
215     time64 elapsed;
216     tTimer timerTemp;
217
218     if (!timer->counter) return;
219
220     if (timer->counter == 1) {
221 retry:
222         end = getProcessTime();
223         elapsed = end - timer->start;
224         timer->snapShot = elapsed + timer->total;
225         timer->mutex = 1;
226         timer->counter = 0;
227         /* read proces time again in case the value was sampled between
228          *  last sample and mutex getting set.
229          */
230         if (timer->sampled) {
231             timer->sampled = 0;
232             goto retry;
233         }
234         timer->total = timer->snapShot;
235         timer->sampled = 0;
236         timer->mutex = 0;
237
238 #ifdef notdef
239         /* for debugging */
240         if (timer->total < 0) {
241             timerTemp = *timer;
242             abort();
243         }
244 #endif
245
246     } else {
247         timer->counter--;
248     }
249 }
250 /* #endif */
251
252 double previous[1000];
253
254 void set_timer_buf(volatile struct timer_buf *param)
255 {
256 /*     asm("set 50,%g1"); */
257     asm("set 29,%g1");
258     /* asm("set 23,%g1"); */
259     asm("retl");
260     asm("ta 0x8");
261 }
262
263
264
265 void DYNINSTreportTimer(tTimer *timer)
266 {
267     double temp;
268     double temp2;
269     time64 now;
270     time64 total;
271     tTimer timerTemp;
272     traceSample sample;
273
274
275     if (timer->mutex) {
276         total = timer->snapShot;
277         timer->sampled = 1;
278     } else if (timer->counter) {
279         /* timer is running */
280         if (timer->type == processTime) {
281             now = getProcessTime();
282             total = now - timer->start;
283         } else {
284             CMOS_get_time(&now);
285             total = (now - timer->start);
286         }
287         total += timer->total;
288     } else {
289         total = timer->total;
290     }
291
292     if (total < 0) {
293         timerTemp = *timer;
294         abort();
295     }
296
297     timer->normalize = NI_CLK_USEC * MILLION;
298     sample.value = total / (double) timer->normalize;
299     sample.id = timer->id;
300
301     temp = sample.value;
302     if (temp < previous[sample.id.id]) {
303         timerTemp = *timer;
304         temp2 = previous[sample.id.id];
305         abort();
306         while(1);
307     }
308     previous[sample.id.id] = temp;
309
310     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample);
311 }
312
313
314
315 static time64 startWall;
316 int DYNINSTnoHandlers;
317 static int DYNINSTinitDone;
318
319 #define NI_BASE       (0x20000000)
320 #define NI_TIME_A             (NI_BASE + 0x0070)
321
322 /*
323  * should be called before main in each process.
324  *
325  */
326 void DYNINSTinit()
327 {
328     char *interval;
329     struct itimerval timeInterval;
330     int sampleInterval;
331     struct timeval tv;
332     time64 startNItime;
333     extern void DYNINSTalarmExpire();
334     extern int DYNINSTsampleMultiple;
335
336     CMOS_get_time(&startNItime);
337     gettimeofday(&tv, NULL);
338
339     startWall = tv.tv_sec;
340     startWall *= MILLION;
341     startWall += tv.tv_usec;
342
343     /* change time base to ni time */
344     startWall *= NI_CLK_USEC;
345
346     startWall -= startNItime;
347
348 /*     printf ("startWall is %x%x\n", *(int *) &startWall,  */
349 /*          *((int *) &startWall) + 1); */
350
351     ni = (unsigned int *) NI_TIME_A;
352     set_timer_buf(&timerBuffer);
353
354     if (getenv("DYNINSTsampleMultiple")) {
355         DYNINSTsampleMultiple = atoi(getenv("DYNINSTsampleMultiple"));
356     }
357
358     /*
359      * Allocate a trace buffer for this node, and set up the buffer
360      * pointers.
361      */
362     TRACELIBcurrPtr = TRACELIBfreePtr = TRACELIBtraceBuffer = (char *) malloc (TRACE_BUF_SIZE);
363     TRACELIBendPtr = TRACELIBtraceBuffer + TRACE_BUF_SIZE - 1;
364
365
366     /*
367      * Set up the SIGALRM handler stuff so counters/timers get sampled and
368      * traces get puit into the traceBuffer every once in a while.
369      */
370
371     sampleInterval = 500000;     /* default is 500msec  */
372     interval = (char *) getenv("DYNINSTsampleInterval");
373     if (interval) {
374         sampleInterval = atoi(interval);
375     }
376     CMOS_signal (CM_SIGALRM, DYNINSTalarmExpire, ~0);
377     timeInterval.it_interval.tv_sec = ((int) (sampleInterval) / 1000000);
378     timeInterval.it_interval.tv_usec = sampleInterval % 1000000;
379     CMOS_setitimer (1, &timeInterval, NULL);
380     CMOS_ualarm (sampleInterval);
381
382     DYNINSTinitDone = 1;
383 }
384
385
386 void DYNINSTexit()
387 {
388 }
389
390
391 /*
392  * generate a trace record onto the named stream.
393  *
394  */
395 void DYNINSTgenerateTraceRecord(traceStream sid, short type, short length,
396     void *eventData)
397 {
398     int ret;
399     int count;
400     time64 pTime;
401     double newVal;
402     char buffer[1024];
403     traceHeader header;
404
405     if (!DYNINSTinitDone) return;
406
407     CMOS_get_time(&header.wall);
408     header.wall += startWall;
409     header.wall /= NI_CLK_USEC;
410
411     CMOS_get_times(&header.process, &pTime);
412     header.process -= pTime;
413     header.process /= NI_CLK_USEC;
414
415     length = ALIGN_TO_WORDSIZE(length);
416
417     header.type = type;
418     header.length = length;
419     count = 0;
420     memcpy(&buffer[count], &sid, sizeof(traceStream));
421     count += sizeof(traceStream);
422
423     memcpy(&buffer[count], &header, sizeof(header));
424     count += sizeof(header);
425
426     memcpy(&buffer[count], eventData, length);
427     count += length;
428
429     TRACE(buffer, count);
430 }
431
432 void DYNINSTbreakPoint(int arg)
433 {
434     printf("Break point %d reached\n", arg);
435 /*     asm("ta 0x81"); */
436 }
437
438 void must_end_timeslice()
439 {
440   printf ("Need to end timeslice!!!\n");
441   /*
442    * We still don't do anything good for this case.
443    * Simple solutions are:
444    * 1.  Increase buffer size
445    * 2.  Implement a way for a node to trigger a context switch and
446    * surrender the rest of a timeslice.
447    */
448 }