Part of the base instrumentation for supporting multithreaded applications
[dyninst.git] / rtinst / src / RTaix.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 /************************************************************************
43  * RTaix.c: clock access functions for aix.
44  *
45  * $Log: RTaix.c,v $
46  * Revision 1.8  1997/01/27 19:43:31  naim
47  * Part of the base instrumentation for supporting multithreaded applications
48  * (vectors of counter/timers) implemented for all current platforms +
49  * different bug fixes - naim
50  *
51  * Revision 1.7  1997/01/16 22:19:34  tamches
52  * added proper param names to DYNINSTos_init
53  *
54  * Revision 1.6  1997/01/16 20:55:45  tamches
55  * params to DYNINSTos_init
56  *
57  * Revision 1.5  1996/08/16 21:27:27  tamches
58  * updated copyright for release 1.1
59  *
60  * Revision 1.4  1996/04/06 21:27:50  hollings
61  * Add missing case for system time.
62  *
63  * Revision 1.3  1996/02/13  16:21:57  hollings
64  * Fixed timer64 to be time64.
65  *
66  *
67  ************************************************************************/
68
69 #include <sys/time.h>
70 #include <sys/resource.h>
71 #include <malloc.h>
72 #include <stdlib.h>
73 #include <stdio.h>
74 #include "rtinst/h/rtinst.h"
75
76 #if defined(MT_THREAD)
77 #include <sys/thread.h>
78 #endif
79
80 static const double NANO_PER_USEC = 1.0e3;
81 static const long int MILLION       = 1000000;
82
83 /************************************************************************
84  * void DYNINSTos_init(void)
85  *
86  * os initialization function---currently null.
87 ************************************************************************/
88
89 void
90 DYNINSTos_init(int calledByFork, int calledByAttach) {
91 }
92
93
94 /************************************************************************
95  * time64 DYNINSTgetCPUtime(void)
96  *
97  * return value is in usec units.
98 ************************************************************************/
99
100 time64
101 DYNINSTgetCPUtime(void) {
102      time64 now;
103      static time64 previous=0;
104      struct rusage ru;
105
106 try_again:    
107     if (!getrusage(RUSAGE_SELF, &ru)) {
108       now = (time64)ru.ru_utime.tv_sec + (time64)ru.ru_stime.tv_sec;
109       now *= (time64)1000000;
110       now += (time64)ru.ru_utime.tv_usec + (time64)ru.ru_stime.tv_usec;
111       if (now<previous) {
112         goto try_again;
113       }
114       previous=now;
115       return(now);
116     }
117     else {
118       perror("getrusage");
119       abort();
120     }
121 }
122
123
124 \f
125
126
127 /************************************************************************
128  * time64 DYNINSTgetWalltime(void)
129  *
130  * get the total walltime used by the monitored process.
131  * return value is in usec units.
132 ************************************************************************/
133
134 time64 DYNINSTgetWalltime(void) {
135     time64 now;
136     register unsigned int timeSec asm("5");
137     register unsigned int timeNano asm("6");
138     register unsigned int timeSec2 asm("7");
139
140     /* Need to read the first value twice to make sure it doesn't role
141      *   over while we are reading it.
142      */
143 retry:
144     asm("mfspr   5,4");         /* read high into register 5 - timeSec */
145     asm("mfspr   6,5");         /* read low into register 6 - timeNano */
146     asm("mfspr   7,4");         /* read high into register 7 - timeSec2 */
147
148     if (timeSec != timeSec2) goto retry;
149     /* convert to correct form. */
150     now = (time64)timeSec;
151     now *= (time64)MILLION;
152     now += (time64)timeNano/(time64)1000;
153     return(now);
154 }
155
156
157 /*
158  * Code to trap execvp call and munge command (for SP-2).
159  *
160  */
161 void DYNINSTexecvp(char *argv[])
162 {
163      int i;
164      int ret;
165      char *ch;
166      char *cmd;
167      int iCount;
168      int acount;
169      char *pdArgs;
170      char **newArgs;
171      static int inExecvp;
172
173      if (inExecvp) return;
174      inExecvp = 1;
175
176      cmd = argv[0];
177
178      /* this only applies to poe on the SP-2 */
179      if (strcmp(cmd, "poe")) return;
180
181      for (iCount=0; argv[iCount]; iCount++);
182
183      pdArgs = (char *) getenv("PARADYN_MASTER_INFO");
184      if (!pdArgs) {
185          fprintf(stdout, "unable to get PARADYN_MASTER_INFO\n");
186          fflush(stdout);
187          return;
188      }
189
190      /* extras for first arg, command, -runme, and null  */
191      for (ch=pdArgs, acount=4; *ch; ch++) if (*ch == ' ') acount++;
192      newArgs = calloc(sizeof(char*), iCount+acount);
193
194      newArgs[0] = "poe";
195      newArgs[1] = "paradynd";
196
197      /* skip white spave at start */
198      while (*pdArgs && *pdArgs == ' ') pdArgs++;
199      newArgs[2] = pdArgs;
200      for (ch=pdArgs, acount=3; *ch; ch++) {
201          if (*ch == ' ') {
202              *ch = '\0';
203              /* skip over null argument -caused by spaces in environment var */
204              if (!strlen(newArgs[acount-1])) acount--;
205              newArgs[acount++] = ++ch;
206          }
207      }
208      /* skip over null argument -caused by space at end of environment var */
209      if (!strlen(newArgs[acount-1])) acount--;
210
211      newArgs[acount++] = "-runme";
212      for (i=1; i < iCount; i++) {
213          newArgs[acount++] = argv[i];
214      }
215
216      newArgs[acount] = "";
217
218      /* generate an exit record about the process to paradynd */
219      DYNINSTprintCost();
220
221      /* Now call execvp with the correct arguments */
222      ret = execvp(cmd, newArgs);
223
224      fprintf(stderr, "execvp failed\n");
225      perror("execvp");
226      fflush(stderr);
227
228      exit(-1);
229
230      inExecvp = 0;
231      return;
232 }
233
234
235 /*
236  * DYNINSTgetRusage(id) - Return the value of various OS stats.
237  *
238  *    The id is an integer, and when they are changed, any metric that uses
239  *        DYNINSTgetRusage will also need to be updated.
240  *
241  */
242 int DYNINSTgetRusage(int id)
243 {
244     int ret;
245     int value;
246     struct rusage rusage;
247     struct rusage *DYNINSTrusagePtr;
248
249     ret = getrusage(RUSAGE_SELF, &rusage);
250     if (ret) {
251         perror("getrusage");
252     }
253     DYNINSTrusagePtr = &rusage;
254     switch (id) {
255         case 0: /* page faults */
256             value = DYNINSTrusagePtr->ru_minflt+DYNINSTrusagePtr->ru_majflt;
257             break;
258         case 1: /* swaps */
259             value = DYNINSTrusagePtr->ru_nswap;
260             break;
261         case 2: /* signals received */
262             value = DYNINSTrusagePtr->ru_nsignals;
263             break;
264         case 3: /* max rss */
265             value = DYNINSTrusagePtr->ru_maxrss;
266             break;
267         case 4: /* context switches */
268             value = DYNINSTrusagePtr->ru_nvcsw + DYNINSTrusagePtr->ru_nivcsw;
269             break;
270         case 5: /* system time - in mili-seconds */
271             value = 1000 * DYNINSTrusagePtr->ru_stime.tv_sec + 
272                            DYNINSTrusagePtr->ru_stime.tv_usec/1000;
273             break;
274         default:
275             value = 0;
276             break;
277     }
278     return value;
279 }
280
281 #if defined(MT_THREAD)
282 extern unsigned hash_lookup(unsigned key);
283 extern unsigned initialize_done;
284 extern void initialize_hash(unsigned total);
285 extern void initialize_free(unsigned total);
286 extern unsigned hash_insert(unsigned k);
287
288 int DYNINSTthreadSelf(void) {
289   return(thread_self());
290 }
291
292 int DYNINSTthreadPos(void) {
293   if (initialize_done) {
294     return(hash_lookup(DYNINSTthreadSelf()));
295   } else {
296     initialize_free(MAX_NUMBER_OF_THREADS);
297     initialize_hash(MAX_NUMBER_OF_THREADS);
298     initialize_done=1;
299     return(hash_insert(DYNINSTthreadSelf()));
300   }
301 }
302 #endif