2 * This file contains the implementation of runtime dynamic instrumentation
3 * functions for a TMC CM-5 machine.
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
12 * Revision 1.10 1993/12/14 17:27:21 jcargill
13 * Put sampleMultiple and length alignment fixes back, and one retry fix
15 * Revision 1.9 1993/12/14 16:35:27 hollings
16 * moved getProcessTime() out of the ifdef notdef.
18 * Revision 1.8 1993/12/13 19:47:06 hollings
19 * use assembly version of clock code.
21 * Revision 1.7 1993/10/19 15:29:58 hollings
22 * new simpler primitives.
24 * Revision 1.6 1993/10/07 19:09:12 jcargill
25 * Added true combines for global instrumentation
27 * Revision 1.5 1993/10/01 18:15:53 hollings
28 * Added filtering and resource discovery.
30 * Revision 1.4 1993/09/02 22:09:38 hollings
31 * fixed race condition caused be no re-trying sampling of process time.
33 * Revision 1.3 1993/08/26 23:07:34 hollings
34 * made initTraceLibPN called from DYNINSTinitTraceLib.
36 * Revision 1.2 1993/07/02 21:53:33 hollings
37 * removed unnecessary include files
39 * Revision 1.1 1993/07/02 21:49:35 hollings
45 /* #include <signal.h> */
48 /* our include files */
49 #include "rtinst/h/rtinst.h"
50 #include "rtinst/h/trace.h"
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>
63 #include <cmsys/cm_signal.h>
66 #include <cmsys/ni_interface.h>
70 #include <sys/types.h>
71 #include <sys/stdtypes.h>
73 #include <sys/timeb.h>
77 #include <cm/cm_file.h>
78 #include <cm/cm_errno.h>
81 #include <sys/socket.h>
83 #include <netinet/in.h>
85 #include <sys/filio.h>
88 #define NI_CLK_USEC 33
89 #define MILLION 1000000
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 */
99 time64 inline getProcessTime()
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;
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;
134 static volatile unsigned int *ni;
135 volatile struct timer_buf timerBuffer;
137 time64 DYNINSTgetCPUtime()
141 now = getProcessTime();
142 now /= NI_CLK_USEC * MILLION;
148 inline time64 getProcessTime()
154 timerBuffer.sync = 1;
155 ni_end = timerBuffer.ni_time;
156 end.parts.high = timerBuffer.high;
158 if (timerBuffer.sync != 1) goto retry;
159 return(end.value-ni_end);
163 inline time64 getWallTime()
168 timerBuffer.sync = 1;
169 end.parts.high = timerBuffer.high;
171 if (timerBuffer.sync != 1) goto retry;
175 void DYNINSTstartWallTimer(tTimer *timer)
177 if (timer->counter == 0) {
178 timer->start = getWallTime();
180 /* this must be last to prevent race conditions with the sampler */
184 void DYNINSTstopWallTimer(tTimer *timer)
188 if (!timer->counter) return;
190 if (timer->counter == 1) {
192 timer->snapShot = timer->total + now - timer->start;
195 timer->total = timer->snapShot;
202 void DYNINSTstartProcessTimer(tTimer *timer)
204 if (timer->counter == 0) {
205 timer->start = getProcessTime();
207 /* this must be last to prevent race conditions with the sampler */
212 void DYNINSTstopProcessTimer(tTimer *timer)
218 if (!timer->counter) return;
220 if (timer->counter == 1) {
222 end = getProcessTime();
223 elapsed = end - timer->start;
224 timer->snapShot = elapsed + timer->total;
227 /* read proces time again in case the value was sampled between
228 * last sample and mutex getting set.
230 if (timer->sampled) {
234 timer->total = timer->snapShot;
240 if (timer->total < 0) {
252 double previous[1000];
254 void set_timer_buf(volatile struct timer_buf *param)
256 /* asm("set 50,%g1"); */
258 /* asm("set 23,%g1"); */
265 void DYNINSTreportTimer(tTimer *timer)
276 total = timer->snapShot;
278 } else if (timer->counter) {
279 /* timer is running */
280 if (timer->type == processTime) {
281 now = getProcessTime();
282 total = now - timer->start;
285 total = (now - timer->start);
287 total += timer->total;
289 total = timer->total;
297 timer->normalize = NI_CLK_USEC * MILLION;
298 sample.value = total / (double) timer->normalize;
299 sample.id = timer->id;
302 if (temp < previous[sample.id.id]) {
304 temp2 = previous[sample.id.id];
308 previous[sample.id.id] = temp;
310 DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample);
315 static time64 startWall;
316 int DYNINSTnoHandlers;
317 static int DYNINSTinitDone;
319 #define NI_BASE (0x20000000)
320 #define NI_TIME_A (NI_BASE + 0x0070)
323 * should be called before main in each process.
329 struct itimerval timeInterval;
333 extern void DYNINSTalarmExpire();
334 extern int DYNINSTsampleMultiple;
336 CMOS_get_time(&startNItime);
337 gettimeofday(&tv, NULL);
339 startWall = tv.tv_sec;
340 startWall *= MILLION;
341 startWall += tv.tv_usec;
343 /* change time base to ni time */
344 startWall *= NI_CLK_USEC;
346 startWall -= startNItime;
348 /* printf ("startWall is %x%x\n", *(int *) &startWall, */
349 /* *((int *) &startWall) + 1); */
351 ni = (unsigned int *) NI_TIME_A;
352 set_timer_buf(&timerBuffer);
354 if (getenv("DYNINSTsampleMultiple")) {
355 DYNINSTsampleMultiple = atoi(getenv("DYNINSTsampleMultiple"));
359 * Allocate a trace buffer for this node, and set up the buffer
362 TRACELIBcurrPtr = TRACELIBfreePtr = TRACELIBtraceBuffer = (char *) malloc (TRACE_BUF_SIZE);
363 TRACELIBendPtr = TRACELIBtraceBuffer + TRACE_BUF_SIZE - 1;
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.
371 sampleInterval = 500000; /* default is 500msec */
372 interval = (char *) getenv("DYNINSTsampleInterval");
374 sampleInterval = atoi(interval);
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);
392 * generate a trace record onto the named stream.
395 void DYNINSTgenerateTraceRecord(traceStream sid, short type, short length,
405 if (!DYNINSTinitDone) return;
407 CMOS_get_time(&header.wall);
408 header.wall += startWall;
409 header.wall /= NI_CLK_USEC;
411 CMOS_get_times(&header.process, &pTime);
412 header.process -= pTime;
413 header.process /= NI_CLK_USEC;
415 length = ALIGN_TO_WORDSIZE(length);
418 header.length = length;
420 memcpy(&buffer[count], &sid, sizeof(traceStream));
421 count += sizeof(traceStream);
423 memcpy(&buffer[count], &header, sizeof(header));
424 count += sizeof(header);
426 memcpy(&buffer[count], eventData, length);
429 TRACE(buffer, count);
432 void DYNINSTbreakPoint(int arg)
434 printf("Break point %d reached\n", arg);
435 /* asm("ta 0x81"); */
438 void must_end_timeslice()
440 printf ("Need to end timeslice!!!\n");
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.