params to DYNINSTos_init
[dyninst.git] / rtinst / src / RTsunos.c
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 \f
43
44
45 /************************************************************************
46  * RTsunos.c: SunOs-4.1.3 specific functions.
47  *
48  * $Log: RTsunos.c,v $
49  * Revision 1.8  1997/01/16 20:59:17  tamches
50  * params to DYNINSTos_init
51  *
52  * Revision 1.7  1996/08/16 21:27:45  tamches
53  * updated copyright for release 1.1
54  *
55  * Revision 1.6  1996/02/19 22:22:16  naim
56  * Fixing DYNINSTgetWalltime. gettimeofday was going backwards. If it does,
57  * we retry again - naim
58  *
59  * Revision 1.5  1996/02/01  17:48:39  naim
60  * Fixing some problems related to timers and race conditions. I also tried to
61  * make a more standard definition of certain procedures (e.g. reportTimer)
62  * across all platforms - naim
63  *
64  * Revision 1.4  1995/08/24  15:12:44  hollings
65  * AIX/SP-2 port (including option for split instruction/data heaps)
66  * Tracing of rexec (correctly spawns a paradynd if needed)
67  * Added rtinst function to read getrusage stats (can now be used in metrics)
68  * Critical Path
69  * Improved Error reporting in MDL sematic checks
70  * Fixed MDL Function call statement
71  * Fixed bugs in TK usage (strings passed where UID expected)
72  *
73  * Revision 1.3  1995/03/10  19:38:03  hollings
74  * Removed use of floating point to compute times. This speed up
75  * the timer routines by a factor of 2-3.
76  *
77  * Added DYNINSTuseGetrusage environment variable to force use of getrusage over
78  * the mmaped uarea.
79  *
80  *
81  ************************************************************************/
82
83
84 \f
85
86
87 /************************************************************************
88  * header files.
89 ************************************************************************/
90
91 #include <assert.h>
92 #include <errno.h>
93 #include <fcntl.h>
94 #include <kvm.h>
95 #include <machine/vmparam.h>
96 #include <stdio.h>
97 #include <string.h>
98 #include <sys/mman.h>
99 #include <sys/proc.h>
100 #include <sys/resource.h>
101 #include <sys/types.h>
102 #include <sys/time.h>
103 #include <sys/times.h>
104 #include <sys/user.h>
105 #include <unistd.h>
106
107 #include "kludges.h"
108 #include "rtinst/h/rtinst.h"
109
110 extern int getrusage (int, struct rusage *);
111 extern char *getenv(char *);
112
113 \f
114
115
116 /************************************************************************
117  * caddr_t DYNINSTprobeUarea(void)
118  *
119  * test to see if uarea of the process can be mapped.  if so, return
120  * the address of the uarea, else return null.
121 ************************************************************************/
122
123 static caddr_t
124 DYNINSTprobeUarea(void) {
125     kvm_t*       kd;
126     struct user* u;
127     struct proc* p;
128
129     if (!(kd = kvm_open(0, 0, 0, O_RDONLY, 0))) {
130         perror("kvm_open");
131         return 0;
132     }
133
134     if (!(p = kvm_getproc(kd, getpid()))) {
135         perror("kvm_getproc");
136         return 0;
137     }
138
139     if (!(u = kvm_getu(kd, p))) {
140         perror("kvm_getu");
141         return 0;
142     }
143
144     kvm_close(kd);
145     return (caddr_t) (p->p_uarea);
146 }
147
148
149 \f
150
151
152 /************************************************************************
153  * void DYNINSTmapUarea(void)
154  *
155  * map urea of the process into its accessible address space.  if
156  * such a mapping is possible, set clock pointers for fast access,
157  * else use slower system calls.
158 ************************************************************************/
159
160 /*
161  * NOTE: This could be made static, but gdb has trouble finding them if
162  *   they are static.  jkh 3/8/95
163  */
164 int DYNINSTmappedUarea = 0;
165 volatile unsigned* DYNINSTuareaTimeSec = 0;
166 volatile unsigned* DYNINSTuareaTimeUsec = 0;
167 volatile unsigned* DYNINSTuareaSTimeSec = 0;
168 volatile unsigned* DYNINSTuareaSTimeUsec = 0;
169 struct rusage *DYNINSTrusagePtr;
170 struct user *DYNINSTuareaPtr;
171
172 static void
173 DYNINSTmapUarea(void) {
174     int     ret;
175     int     kmem;
176     caddr_t uAddr;
177     static struct user* u;
178
179     if (getenv("DYNINSTuseGetrusage")) {
180         printf("Using getrusage\n");
181         fflush(stdout);
182         return;
183     }
184
185     uAddr = DYNINSTprobeUarea();
186     if (!uAddr) {
187         printf("WARNING: unable to map uarea, using getrusage.\n");
188         printf(" This may slow your program down quite a bit.\n");
189         fflush(stdout);
190         return;
191     }
192
193     if ((kmem = open("/dev/kmem", O_RDONLY, 0)) == -1) {
194         perror("/dev/kmem");
195         return;
196     }
197
198     if ((ret = (int) mmap(0, sizeof(struct user), PROT_READ, MAP_SHARED,
199         kmem, (off_t) uAddr)) == -1) {
200         perror("mmap");
201         return;
202     }
203
204     DYNINSTuareaPtr = (struct user *) ret;
205     u = (struct user *) ret;
206     DYNINSTmappedUarea = 1;
207
208     DYNINSTuareaTimeSec = (int *) &(u->u_ru.ru_utime.tv_sec);
209     DYNINSTuareaTimeUsec = (int *) &(u->u_ru.ru_utime.tv_usec);
210     DYNINSTuareaSTimeSec = (int *) &(u->u_ru.ru_stime.tv_sec);
211     DYNINSTuareaSTimeUsec = (int *) &(u->u_ru.ru_stime.tv_usec);
212 }
213
214
215 \f
216
217
218 /************************************************************************
219  * void DYNINSTos_init(void)
220  *
221  * run any operating system dependent initialization.  this function
222  * will be called from DYNINSTinit().
223  *
224  * for SunOs, simply try to map the process uarea.
225 ************************************************************************/
226
227 void
228 DYNINSTos_init(int, int) { /* params: calledByFork, calledByAttach */
229     DYNINSTmapUarea();
230 }
231
232
233 \f
234
235
236 /************************************************************************
237  * symbolic constants.
238 ************************************************************************/
239
240 static const double MILLION = 1000000.0;
241
242
243 \f
244
245
246 /************************************************************************
247  * time64 DYNINSTgetCPUtime(void)
248  *
249  * get the total CPU time used for by the monitored process.
250  * return value is in usec units.
251  *
252  * while reading mapped clocks, there can be a race condition between
253  * the updates of the sec/usec fields, hence the retry loop.
254 ************************************************************************/
255
256 time64
257 DYNINSTgetCPUtime(void) {
258     unsigned long p1, p2;
259     time64 now;
260     static time64 previous=0;
261     struct rusage ru;
262
263     if (DYNINSTmappedUarea) {
264 retry:
265         p1 = *DYNINSTuareaTimeSec;
266         p2 = *DYNINSTuareaSTimeSec;
267         /* This MUST not use float constant MILLION - jkh 2/8/95 */
268         now  = (time64)p1 + (time64)p2;
269         now *= (time64)1000000;
270         now += (time64)(*DYNINSTuareaTimeUsec) + 
271                (time64)(*DYNINSTuareaSTimeUsec);
272         if (p1 != (*DYNINSTuareaTimeSec) || p2 != (*DYNINSTuareaSTimeSec)) {
273           goto retry;
274         }        
275         if (now<previous) {
276           goto retry;
277         }
278         previous=now;
279         return now;
280     }
281
282 try_again:    
283     if (!getrusage(RUSAGE_SELF, &ru)) {
284       now = (time64)ru.ru_utime.tv_sec + (time64)ru.ru_stime.tv_sec;
285       now *= (time64)1000000;
286       now += (time64)ru.ru_utime.tv_usec + (time64)ru.ru_stime.tv_usec;
287       if (now<previous) {
288         goto try_again;
289       }
290       previous=now;
291       return now;
292     }
293     else {
294       perror("getrusage");
295       abort();
296     }
297 }
298
299
300 \f
301
302
303 /************************************************************************
304  * time64 DYNINSTgetWalltime(void)
305  *
306  * get the total walltime used by the monitored process.
307  * return value is in usec units.
308 ************************************************************************/
309
310 time64
311 DYNINSTgetWalltime(void) {
312     static time64 previous=0;
313     time64 now;
314     struct timeval tv;
315
316 retryWT:
317     if (gettimeofday(&tv, NULL) == -1) {
318         perror("gettimeofday");
319         abort();
320     }
321     now = (time64)tv.tv_sec*(time64)1000000 + (time64)tv.tv_usec;
322     if (now < previous) {
323       goto retryWT;
324     }
325     previous = now;
326     return (now);
327 }
328
329 /*
330  * DYNINSTgetRusage(id) - Return the value of various OS stats.
331  *
332  *    The id is an integer, and when they are changed, any metric that uses
333  *        DYNINSTgetRusage will also need to be updated.
334  *
335  */
336 int DYNINSTgetRusage(int id)
337 {
338     int value;
339     struct rusage rusage;
340
341     if (!DYNINSTmappedUarea) {
342         getrusage(0, &rusage);
343         DYNINSTrusagePtr = &rusage;
344     } else {
345         DYNINSTrusagePtr = &DYNINSTuareaPtr->u_ru;
346     }
347     switch (id) {
348         case 0: /* page faults */
349             value = DYNINSTrusagePtr->ru_minflt+DYNINSTrusagePtr->ru_majflt;
350             break;
351         case 1: /* swaps */
352             value = DYNINSTrusagePtr->ru_nswap;
353             break;
354         case 2: /* signals received */
355             value = DYNINSTrusagePtr->ru_nsignals;
356             break;
357         case 3: /* max rss */
358             value = DYNINSTrusagePtr->ru_maxrss;
359             break;
360         case 4: /* context switches */
361             value = DYNINSTrusagePtr->ru_nvcsw + DYNINSTrusagePtr->ru_nivcsw;
362             break;
363         default:
364             value = 0;
365             break;
366     }
367     return value;
368 }