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