Implementation of CPU time using gethrvtime in order to improve performance -
[dyninst.git] / rtinst / src / RTsolaris.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  * RTsolaris.c: clock access functions for solaris-2.
44 ************************************************************************/
45
46 #include <signal.h>
47 #include <sys/ucontext.h>
48 #include <sys/time.h>
49 #include <assert.h>
50 #include <sys/syscall.h>
51
52 #include <sys/procfs.h> /* /proc PIOCUSAGE */
53 #include <stdio.h>
54 #include <fcntl.h> /* O_RDONLY */
55 #include <unistd.h> /* getpid() */
56
57 #include "rtinst/h/rtinst.h"
58
59 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
60 #include <thread.h>
61 #endif
62
63 /*extern int    gettimeofday(struct timeval *, struct timezone *);*/
64 extern void perror(const char *);
65
66 \f
67
68
69 /************************************************************************
70  * symbolic constants.
71 ************************************************************************/
72
73 static const double NANO_PER_USEC = 1.0e3;
74 static const double MILLION       = 1.0e6;
75
76
77 \f
78
79 static int procfd = -1;
80
81 void DYNINSTgetCPUtimeInitialize(void) {
82    /* This stuff is done just once */
83    char str[20];
84
85    sprintf(str, "/proc/%d", (int)getpid());
86    /* have to use syscall here for applications that have their own
87       versions of open, poll...In these cases there is no guarentee that
88       things have been initialized so that the application's version of
89       open can be used when this open call occurs (in DYNINSTinit)
90    */
91    procfd = syscall(SYS_open,str, O_RDONLY);
92    if (procfd < 0) {
93       fprintf(stderr, "open of /proc failed in DYNINSTgetCPUtimeInitialize\n");
94       perror("open");
95       abort();
96    }
97 }
98
99
100 /************************************************************************
101  * void DYNINSTos_init(void)
102  *
103  * os initialization function---currently null.
104 ************************************************************************/
105
106 void
107 DYNINSTos_init(int calledByFork, int calledByAttach) {
108
109     /*
110        Install trap handler.
111        This is currently being used only on the x86 platform.
112     */
113 #ifdef i386_unknown_solaris2_5
114     void DYNINSTtrapHandler(int sig, siginfo_t *info, ucontext_t *uap);
115     struct sigaction act;
116     act.sa_handler = DYNINSTtrapHandler;
117     act.sa_flags = 0;
118     sigfillset(&act.sa_mask);
119     if (sigaction(SIGTRAP, &act, 0) != 0) {
120         perror("sigaction(SIGTRAP)");
121         assert(0);
122         abort();
123     }
124 #endif
125
126     /* It is necessary to call DYNINSTgetCPUtimeInitialize here to make sure
127        that it is called again for a child process during a fork - naim */
128     DYNINSTgetCPUtimeInitialize();
129 }
130
131
132 \f
133
134
135 /************************************************************************
136  * time64 DYNINSTgetCPUtime(void)
137  *
138  * get the total CPU time used for "an" LWP of the monitored process.
139  * this functions needs to be rewritten if a per-thread CPU time is
140  * required.  time for a specific LWP can be obtained via the "/proc"
141  * filesystem.
142  * return value is in usec units.
143  *
144  * XXXX - This should really return time in native units and use normalize.
145  *      conversion to float and division are way too expensive to
146  *      do everytime we want to read a clock (slows this down 2x) -
147  *      jkh 3/9/95
148 ************************************************************************/
149
150
151 static unsigned long long div1000(unsigned long long in) {
152    /* Divides by 1000 without an integer division instruction or library call, both of
153     * which are slow.
154     * We do only shifts, adds, and subtracts.
155     *
156     * We divide by 1000 in this way:
157     * multiply by 1/1000, or multiply by (1/1000)*2^30 and then right-shift by 30.
158     * So what is 1/1000 * 2^30?
159     * It is 1,073,742.   (actually this is rounded)
160     * So we can multiply by 1,073,742 and then right-shift by 30 (neat, eh?)
161     *
162     * Now for multiplying by 1,073,742...
163     * 1,073,742 = (1,048,576 + 16384 + 8192 + 512 + 64 + 8 + 4 + 2)
164     * or, slightly optimized:
165     * = (1,048,576 + 16384 + 8192 + 512 + 64 + 16 - 2)
166     * for a total of 8 shifts and 6 add/subs, or 14 operations.
167     *
168     */
169
170    unsigned long long temp = in << 20; /* multiply by 1,048,576 */
171    /* beware of overflow; left shift by 20 is quite a lot.
172       If you know that the input fits in 32 bits (4 billion) then
173       no problem.  But if it's much bigger then start worrying...
174    */
175
176    temp += in << 14; /* 16384 */
177    temp += in << 13; /* 8192  */
178    temp += in << 9;  /* 512   */
179    temp += in << 6;  /* 64    */
180    temp += in << 4;  /* 16    */
181    temp -= in >> 2;  /* 2     */
182
183    return (temp >> 30); /* divide by 2^30 */
184 }
185
186 static unsigned long long divMillion(unsigned long long in) {
187    /* Divides by 1,000,000 without an integer division instruction or library call,
188     * both of which are slow.
189     * We do only shifts, adds, and subtracts.
190     *
191     * We divide by 1,000,000 in this way:
192     * multiply by 1/1,000,000, or multiply by (1/1,000,000)*2^30 and then right-shift
193     * by 30.  So what is 1/1,000,000 * 2^30?
194     * It is 1,074.   (actually this is rounded)
195     * So we can multiply by 1,074 and then right-shift by 30 (neat, eh?)
196     *
197     * Now for multiplying by 1,074
198     * 1,074 = (1024 + 32 + 16 + 2)
199     * for a total of 4 shifts and 4 add/subs, or 8 operations.
200     *
201     * Note: compare with div1000 -- it's cheaper to divide by a million than
202     *       by a thousand (!)
203     *
204     */
205
206    unsigned long long temp = in << 10; /* multiply by 1024 */
207    /* beware of overflow...if the input arg uses more than 52 bits
208       than start worrying about whether (in << 10) plus the smaller additions
209       we're gonna do next will fit in 64...
210    */
211
212    temp += in << 5; /* 32 */
213    temp += in << 4; /* 16 */
214    temp += in << 1; /* 2  */
215
216    return (temp >> 30); /* divide by 2^30 */
217 }
218
219 static unsigned long long mulMillion(unsigned long long in) {
220    unsigned long long result = in;
221
222    /* multiply by 125 by multiplying by 128 and subtracting 3x */
223    result = (result << 7) - result - result - result;
224
225    /* multiply by 125 again, for a total of 15625x */
226    result = (result << 7) - result - result - result;
227
228    /* multiply by 64, for a total of 1,000,000x */
229    result <<= 6;
230
231    /* cost was: 3 shifts and 6 subtracts
232     * cost of calling mul1000(mul1000()) would be: 6 shifts and 4 subtracts
233     *
234     * Another algorithm is to multiply by 2^6 and then 5^6.
235     * The former is super-cheap (one shift); the latter is more expensive.
236     * 5^6 = 15625 = 16384 - 512 - 256 + 8 + 1
237     * so multiplying by 5^6 means 4 shift operations and 4 add/sub ops
238     * so multiplying by 1000000 means 5 shift operations and 4 add/sub ops.
239     * That may or may not be cheaper than what we're doing (3 shifts; 6 subtracts);
240     * I'm not sure.  --ari
241     */
242
243    return result;
244 }
245
246 time64
247 DYNINSTgetCPUtime(void) {
248   hrtime_t lwpTime;
249   time64 now;
250   lwpTime = gethrvtime();
251   now = div1000(lwpTime);  /* nsec to usec */
252   return(now);  
253 }
254
255
256 \f
257
258
259 /************************************************************************
260  * time64 DYNINSTgetWalltime(void)
261  *
262  * get the total walltime used by the monitored process.
263  * return value is in usec units.
264 ************************************************************************/
265
266 time64
267 DYNINSTgetWalltime(void) {
268   static time64 previous=0;
269   time64 now;
270
271   while (1) {
272     struct timeval tv;
273     if (gettimeofday(&tv,NULL) == -1) {
274         perror("gettimeofday");
275         assert(0);
276         abort();
277     }
278
279     now = mulMillion(tv.tv_sec) + tv.tv_usec;
280     /*    now = (time64)tv.tv_sec*(time64)1000000 + (time64)tv.tv_usec; */
281
282     if (now < previous) continue;
283     previous = now;
284     return(now);
285   }
286 }
287
288 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
289 extern unsigned DYNINST_hash_lookup(unsigned key);
290 extern unsigned DYNINST_initialize_done;
291 extern void DYNINST_initialize_hash(unsigned total);
292 extern void DYNINST_initialize_free(unsigned total);
293 extern unsigned DYNINST_hash_insert(unsigned k);
294
295 int DYNINSTthreadSelf(void) {
296   return(thr_self());
297 }
298
299 int DYNINSTthreadPos(void) {
300   if (initialize_done) {
301     return(DYNINST_hash_lookup(DYNINSTthreadSelf()));
302   } else {
303     DYNINST_initialize_free(MAX_NUMBER_OF_THREADS);
304     DYNINST_initialize_hash(MAX_NUMBER_OF_THREADS);
305     DYNINST_initialize_done=1;
306     return(DYNINST_hash_insert(DYNINSTthreadSelf()));
307   }
308 }
309 #endif
310
311
312 /****************************************************************************
313    The trap handler. Currently being used only on x86 platform.
314
315    Traps are used when we can't insert a jump at a point. The trap
316    handler looks up the address of the base tramp for the point that
317    uses the trap, and set the pc to this base tramp.
318    The paradynd is responsible for updating the tramp table when it
319    inserts instrumentation.
320 *****************************************************************************/
321
322 #ifdef i386_unknown_solaris2_5
323 trampTableEntry DYNINSTtrampTable[TRAMPTABLESZ];
324 unsigned DYNINSTtotalTraps = 0;
325
326 static unsigned lookup(unsigned key) {
327     unsigned u;
328     unsigned k;
329     for (u = HASH1(key); 1; u = (u + HASH2(key)) % TRAMPTABLESZ) {
330       k = DYNINSTtrampTable[u].key;
331       if (k == 0)
332         return 0;
333       else if (k == key)
334         return DYNINSTtrampTable[u].val;
335     }
336     /* not reached */
337     assert(0);
338     abort();
339 }
340
341 void DYNINSTtrapHandler(int sig, siginfo_t *info, ucontext_t *uap) {
342     unsigned pc = uap->uc_mcontext.gregs[PC];
343     unsigned nextpc = lookup(pc);
344
345     if (!nextpc) {
346       /* kludge: maybe the PC was not automatically adjusted after the trap */
347       /* this happens for a forked process */
348       pc--;
349       nextpc = lookup(pc);
350     }
351
352     if (nextpc) {
353       uap->uc_mcontext.gregs[PC] = nextpc;
354     } else {
355       assert(0);
356       abort();
357     }
358     DYNINSTtotalTraps++;
359 }
360 #endif
361
362
363