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