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