Added true combines for global instrumentation
[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.6  1993/10/07 19:09:12  jcargill
8  * Added true combines for global instrumentation
9  *
10  * Revision 1.5  1993/10/01  18:15:53  hollings
11  * Added filtering and resource discovery.
12  *
13  * Revision 1.4  1993/09/02  22:09:38  hollings
14  * fixed race condition caused be no re-trying sampling of process time.
15  *
16  * Revision 1.3  1993/08/26  23:07:34  hollings
17  * made initTraceLibPN called from DYNINSTinitTraceLib.
18  *
19  * Revision 1.2  1993/07/02  21:53:33  hollings
20  * removed unnecessary include files
21  *
22  * Revision 1.1  1993/07/02  21:49:35  hollings
23  * Initial revision
24  *
25  *
26  */
27 #include <signal.h>
28 #include <assert.h>
29
30 /* our include files */
31 #include <h/rtinst.h>
32 #include <h/trace.h>
33 #include <rtinst/traceio.h>
34
35 #include <cm/cmmd/amx.h>
36 #include <cm/cmmd/mp.h>
37 #include <cm/cmmd/cn.h>
38 #include <cm/cmmd/io.h>
39 #include <cm/cmmd/util.h>
40 #include <cm/cmmd/cmmd_constants.h>
41 #include <cm/cmmd.h>
42 #define pe_obj
43 #include <cm/cmna.h>
44 #include <cmsys/ni_interface.h>
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <sys/types.h>
49 #include <sys/stdtypes.h>
50 #include <sys/time.h>
51 #include <sys/timeb.h>
52 #include <dirent.h>
53 #include <sys/stat.h>
54 #include <sys/vfs.h>
55 #include <cm/cm_file.h>
56 #include <cm/cm_errno.h>
57 #include <errno.h>
58 #include <sys/un.h>
59 #include <sys/socket.h>
60 #include <netdb.h>
61 #include <netinet/in.h>
62 #include <fcntl.h>
63 #include <sys/filio.h>
64 #include <math.h>
65
66 #define NI_CLK_USEC 33
67 #define MILLION 1000000
68
69
70 #ifdef notdef
71 time64 inline getProcessTime()
72 {
73     time64 end;
74     time64 ni_end;
75     time64 ni2;
76
77 retry:
78     CMOS_get_NI_time(&ni_end);
79     CMOS_get_time(&end);
80     CMOS_get_NI_time(&ni2);
81     if (ni_end != ni2) goto retry;
82     return(end-ni_end);
83 }
84 #endif
85
86 struct timer_buf {
87     unsigned int high;
88     unsigned int sync;
89     time64   ni_time;
90 };
91
92 typedef union {
93     struct {
94         unsigned int high;
95         unsigned int low;
96     } parts;
97     time64 value;
98 } timeParts;
99
100 static volatile unsigned int *ni;
101 static volatile struct timer_buf timerBuffer;
102
103 time64 inline getProcessTime()
104 {
105     timeParts end;
106     time64 ni_end;
107
108 retry:
109     timerBuffer.sync = 1;
110     ni_end = timerBuffer.ni_time;
111     end.parts.high = timerBuffer.high;
112     end.parts.low = *ni;
113     if (timerBuffer.sync != 1) goto retry;
114     return(end.value-ni_end);
115 }
116
117 time64 inline getWallTime()
118 {
119     timeParts end;
120     time64 ni_end;
121
122 retry:
123     timerBuffer.sync = 1;
124     end.parts.high = timerBuffer.high;
125     end.parts.low = *ni;
126     if (timerBuffer.sync != 1) goto retry;
127     return(end.value);
128 }
129
130 void DYNINSTstartWallTimer(tTimer *timer)
131 {
132     if (timer->trigger && (!timer->trigger->value)) return;
133     if (timer->counter == 0) {
134          timer->start = getWallTime();
135     }
136     /* this must be last to prevent race conditions with the sampler */
137     timer->counter++;
138 }
139
140 void DYNINSTstopWallTimer(tTimer *timer)
141 {
142     time64 now;
143
144     if (timer->trigger && (timer->trigger->value <= 0)) return;
145     if (!timer->counter) return;
146
147     if (timer->counter == 1) {
148          now = getWallTime();
149          timer->snapShot = timer->total + now - timer->start;
150          timer->mutex = 1;
151          timer->counter = 0;
152          timer->total = timer->snapShot;
153          timer->mutex = 0;
154     } else {
155         timer->counter--;
156     }
157 }
158
159 void DYNINSTstartProcessTimer(tTimer *timer)
160 {
161     if (timer->trigger && (!timer->trigger->value)) return;
162     if (timer->counter == 0) {
163          timer->start = getProcessTime();
164     }
165     /* this must be last to prevent race conditions with the sampler */
166     timer->counter++;
167 }
168
169 void set_timer_buf(struct timer_buf *param)
170 {
171     asm("set 50,%g1");
172     asm("retl");
173     asm("ta 0x8");
174 }
175
176 double previous[1000];
177
178 void DYNINSTstopProcessTimer(tTimer *timer)
179 {
180     time64 end;
181     time64 elapsed;
182     tTimer timerTemp;
183
184     if (timer->trigger && (timer->trigger->value <= 0)) return;
185     if (!timer->counter) return;
186
187     if (timer->counter == 1) {
188         end = getProcessTime();
189         elapsed = end - timer->start;
190         timer->snapShot = elapsed + timer->total;
191         timer->mutex = 1;
192         timer->counter = 0;
193         /* read proces time again in case the value was sampled between
194          *  last sample and mutex getting set.
195          */
196         timer->total += getProcessTime() - timer->start;
197         timer->mutex = 0;
198
199         /* for debugging */
200         if (timer->total < 0) {
201             timerTemp = *timer;
202             abort();
203         }
204
205     } else {
206         timer->counter--;
207     }
208 }
209
210 void DYNINSTreportAggregateCounter(intCounter *counter)
211 {
212     traceSample sample;
213     int aggregate;
214
215     /* Everyone aggregates to a single value */
216     CMNA_com(ADD_SCAN, SCAN_REDUCE, &counter->value, 1, &aggregate);
217
218     sample.value = aggregate;
219     sample.id = counter->id;
220
221     if (CMNA_self_address == 0)
222         DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample);
223 }
224
225
226 void DYNINSTreportTimer(tTimer *timer)
227 {
228     double temp;
229     double temp2;
230     time64 now;
231     double value;
232     time64 total;
233     tTimer timerTemp;
234     traceSample sample;
235
236
237     if (timer->mutex) {
238         total = timer->snapShot;
239     } else if (timer->counter) {
240         /* timer is running */
241         if (timer->type == processTime) {
242             now = getProcessTime();
243             total = now - timer->start;
244         } else {
245             CMOS_get_time(&now);
246             total = (now - timer->start);
247         }
248         total += timer->total;
249     } else {
250         total = timer->total;
251     }
252
253     if (total < 0) {
254         timerTemp = *timer;
255         abort();
256     }
257
258     timer->normalize = NI_CLK_USEC * MILLION;
259     sample.value = total / (double) timer->normalize;
260     sample.id = timer->id;
261
262     temp = sample.value;
263     if (temp < previous[sample.id.id]) {
264         timerTemp = *timer;
265         temp2 = previous[sample.id.id];
266         abort();
267         while(1);
268     }
269     previous[sample.id.id] = temp;
270
271     DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample);
272 }
273
274
275 Add_combine_64bit (x, aggregate)
276     time64 *x, *aggregate;
277 {
278     unsigned int *x_lsw_p;
279     unsigned int *x_msw_p;
280     unsigned int *agg_lsw_p;
281     unsigned int *agg_msw_p;
282
283    x_lsw_p = (((unsigned int *) x) + 1);
284     x_msw_p = ((unsigned int *) x);
285     agg_lsw_p = (((unsigned int *) aggregate) + 1);
286     agg_msw_p = ((unsigned int *) aggregate);
287
288     do {
289         CMNA_com_send_first (UADD_SCAN, SCAN_REDUCE, 2, *x_lsw_p);
290         CMNA_com_send_word (*x_msw_p);
291     }
292     while (!SEND_OK(CMNA_com_status()));
293
294     while (!(RECEIVE_OK(CMNA_com_status())))
295         continue;
296 /*     recv_length = RECEIVE_LENGTH_LEFT(CMNA_com_status()); */
297     
298     *agg_lsw_p = CMNA_com_receive_word();
299     *agg_msw_p = CMNA_com_receive_word();
300 }
301
302
303 void DYNINSTreportAggregateTimer(tTimer *timer)
304 {
305     double temp;
306     double temp2;
307     time64 now;
308     double value;
309     time64 total;
310     time64 aggregate;
311     tTimer timerTemp;
312     traceSample sample;
313
314
315     if (timer->mutex) {
316         total = timer->snapShot;
317     } else if (timer->counter) {
318         /* timer is running */
319         if (timer->type == processTime) {
320             now = getProcessTime();
321             total = now - timer->start;
322         } else {
323             CMOS_get_time(&now);
324             total = (now - timer->start);
325         }
326         total += timer->total;
327     } else {
328         total = timer->total;
329     }
330
331     if (total < 0) {
332         timerTemp = *timer;
333         abort();
334     }
335
336     /* Combine all timers to get a single aggregate 64-bit timer */
337     Add_combine_64bit (&total, &aggregate);
338
339     sample.value = aggregate / (double) timer->normalize;
340     sample.id = timer->id;
341
342     /* only node 0 does sanity check and reports the timer */
343     if (CMNA_self_address == 0) {
344         temp = sample.value;
345         if (temp < previous[sample.id.id]) {
346             timerTemp = *timer;
347             temp2 = previous[sample.id.id];
348             abort();
349             while(1);
350         }
351         previous[sample.id.id] = temp;
352
353         DYNINSTgenerateTraceRecord(0, TR_SAMPLE, sizeof(sample), &sample);
354     }
355 }
356
357
358
359 static time64 startWall;
360 int DYNINSTnoHandlers;
361
362 #define NI_BASE       (0x20000000)
363 #define NI_TIME_A             (NI_BASE + 0x0070)
364
365 /*
366  * should be called before main in each process.
367  *
368  */
369 void DYNINSTinit()
370 {
371     char *interval;
372     struct timeval tv;
373     time64 startNItime;
374     extern void DYNINSTalarmExpire();
375
376     CMOS_get_time(&startNItime);
377     gettimeofday(&tv, NULL);
378
379     startWall = tv.tv_sec;
380     startWall *= MILLION;
381     startWall += tv.tv_usec;
382
383     /* change time base to ni time */
384     startWall *= NI_CLK_USEC;
385
386     startWall -= startNItime;
387
388     ni = (unsigned int *) NI_TIME_A;
389     set_timer_buf(&timerBuffer);
390
391 /*     initTraceLibPN(); */
392 }
393
394 /*
395  * DYNINSTinitTraceLib - call initTraceLibPN & trap back.
396  *
397  */
398 asm(".global _DYNINSTinitTraceLib");
399 asm("_DYNINSTinitTraceLib:");
400 asm("   call    _initTraceLibPN");
401 asm("   nop     ");
402 asm("   ta 0x1");
403 asm("   nop     ");
404
405 void DYNINSTexit()
406 {
407     cleanupTraceLibPN();
408 }
409
410 /*
411  * generate a trace record onto the named stream.
412  *
413  */
414 void DYNINSTgenerateTraceRecord(traceStream sid, short type, short length,
415     void *eventData)
416 {
417     int ret;
418     int count;
419     time64 pTime;
420     double newVal;
421     char buffer[1024];
422     traceSample *sample;
423     traceHeader header;
424
425     /* check and see if we should aggregate to other nodes */
426 /*     if ((type == TR_SAMPLE) && (((traceSample*) eventData)->id.aggregate)) { */
427          /* not ready yet! */
428 /*       abort(); */
429
430          /* use reduction net to compute aggregate */
431 /*       sample = (traceSample*) eventData; */
432          /* newVal = CMMD_reduce_float(sample->value, CMMD_combiner_fadd); */
433 /*       newVal = CMCN_reduce_float(sample->value, CMMD_combiner_fadd); */
434 /*       sample->value = newVal; */
435
436
437          /* only node zero reports value */
438 /*       if (CMMD_self_address()) return; */
439 /*     } */
440
441     CMOS_get_time(&header.wall);
442     header.wall += startWall;
443     header.wall /= NI_CLK_USEC;
444
445     CMOS_get_time(&header.process);
446     CMOS_get_NI_time(&pTime);
447     header.process -= pTime;
448     header.process /= NI_CLK_USEC;
449
450     header.type = type;
451     header.length = length;
452     count = 0;
453     memcpy(&buffer[count], &sid, sizeof(traceStream));
454     count += sizeof(traceStream);
455
456     memcpy(&buffer[count], &header, sizeof(header));
457     count += sizeof(header);
458
459     memcpy(&buffer[count], eventData, length);
460     count += length;
461
462     TRACE(buffer, count);
463 }
464
465 void DYNINSTbreakPoint(int arg)
466 {
467     /* printf("Break point %d reached\n", arg); */
468     asm("ta 0x81");
469 }