1 /* $Header: /src/pub/tcsh/sh.time.c,v 3.25 2002/06/25 19:02:11 christos Exp $ */
3 * sh.time.c: Shell time keeping and printing.
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$Id: sh.time.c,v 3.25 2002/06/25 19:02:11 christos Exp $")
38 # include <machine/param.h>
42 * C Shell - routines handling process timing and niceing
46 # define RUSAGE_SELF 0
47 # define RUSAGE_CHILDREN -1
48 # endif /* RUSAGE_SELF */
53 #if !defined(BSDTIMES) && !defined(_SEQUENT_)
55 static void pdtimet
__P((clock_t, clock_t));
57 static void pdtimet
__P((time_t, time_t));
59 #else /* BSDTIMES || _SEQUENT_ */
60 static void tvadd
__P((timeval_t
*, timeval_t
*));
61 static void pdeltat
__P((timeval_t
*, timeval_t
*));
62 #endif /* BSDTIMES || _SEQUENT_ */
68 struct sysrusage ruch
;
70 memset(&ru0
, 0, sizeof(ru0
));
71 memset(&ruch
, 0, sizeof(ruch
));
74 (void) gettimeofday(&time0
, NULL
);
75 (void) getrusage(RUSAGE_SELF
, (struct rusage
*) &ru0
);
76 (void) getrusage(RUSAGE_CHILDREN
, (struct rusage
*) &ruch
);
80 struct process_stats ruch
;
82 (void) get_process_stats(&time0
, PS_SELF
, &ru0
, &ruch
);
84 # else /* _SEQUENT_ */
85 seconds0
= time(NULL
);
87 time0
= times(×0
);
88 # else /* !COHERENT */
89 time0
= HZ
* seconds0
;
91 # endif /* !COHERENT */
92 times0
.tms_stime
+= times0
.tms_cstime
;
93 times0
.tms_utime
+= times0
.tms_cutime
;
94 times0
.tms_cstime
= 0;
95 times0
.tms_cutime
= 0;
96 # endif /* _SEQUENT_ */
101 * dotime is only called if it is truly a builtin function and not a
102 * prefix to another command
112 struct sysrusage ru1
, ruch
;
114 memset(&ru1
, 0, sizeof(ru1
));
115 memset(&ruch
, 0, sizeof(ruch
));
118 (void) getrusage(RUSAGE_SELF
, (struct rusage
*) &ru1
);
119 (void) getrusage(RUSAGE_CHILDREN
, (struct rusage
*) &ruch
);
121 (void) gettimeofday(&timedol
, NULL
);
122 prusage(&ru0
, &ru1
, &timedol
, &time0
);
126 struct process_stats ru1
, ruch
;
128 (void) get_process_stats(&timedol
, PS_SELF
, &ru1
, &ruch
);
130 prusage(&ru0
, &ru1
, &timedol
, &time0
);
131 # else /* _SEQUENT_ */
138 struct tms times_dol
;
141 timedol
= times(×_dol
);
143 timedol
= HZ
* time(NULL
);
146 times_dol
.tms_stime
+= times_dol
.tms_cstime
;
147 times_dol
.tms_utime
+= times_dol
.tms_cutime
;
148 times_dol
.tms_cstime
= 0;
149 times_dol
.tms_cutime
= 0;
150 prusage(×0
, ×_dol
, timedol
, time0
);
151 # endif /* _SEQUENT_ */
152 #endif /* BSDTIMES */
158 * donice is only called when it on the line by itself or with a +- value
173 else if (*v
== 0 && any("+-", cp
[0]))
176 if (setpriority(PRIO_PROCESS
, 0, nval
) == -1 && errno
)
177 stderror(ERR_SYSTEM
, "setpriority", strerror(errno
));
186 register struct sysrusage
*ru
, *ru2
;
188 tvadd(&ru
->ru_utime
, &ru2
->ru_utime
);
189 tvadd(&ru
->ru_stime
, &ru2
->ru_stime
);
190 if (ru2
->ru_maxrss
> ru
->ru_maxrss
)
191 ru
->ru_maxrss
= ru2
->ru_maxrss
;
193 ru
->ru_ixrss
+= ru2
->ru_ixrss
;
194 ru
->ru_idrss
+= ru2
->ru_idrss
;
195 ru
->ru_isrss
+= ru2
->ru_isrss
;
196 ru
->ru_minflt
+= ru2
->ru_minflt
;
197 ru
->ru_majflt
+= ru2
->ru_majflt
;
198 ru
->ru_nswap
+= ru2
->ru_nswap
;
199 ru
->ru_inblock
+= ru2
->ru_inblock
;
200 ru
->ru_oublock
+= ru2
->ru_oublock
;
201 ru
->ru_msgsnd
+= ru2
->ru_msgsnd
;
202 ru
->ru_msgrcv
+= ru2
->ru_msgrcv
;
203 ru
->ru_nsignals
+= ru2
->ru_nsignals
;
204 ru
->ru_nvcsw
+= ru2
->ru_nvcsw
;
205 ru
->ru_nivcsw
+= ru2
->ru_nivcsw
;
208 tvadd(&ru
->ru_exutime
, &ru2
->ru_exutime
);
209 ru
->ru_utotal
+= ru2
->ru_utotal
;
210 ru
->ru_usamples
+= ru2
->ru_usamples
;
211 ru
->ru_stotal
+= ru2
->ru_stotal
;
212 ru
->ru_ssamples
+= ru2
->ru_ssamples
;
220 register struct process_stats
*ru
, *ru2
;
222 tvadd(&ru
->ps_utime
, &ru2
->ps_utime
);
223 tvadd(&ru
->ps_stime
, &ru2
->ps_stime
);
224 if (ru2
->ps_maxrss
> ru
->ps_maxrss
)
225 ru
->ps_maxrss
= ru2
->ps_maxrss
;
227 ru
->ps_pagein
+= ru2
->ps_pagein
;
228 ru
->ps_reclaim
+= ru2
->ps_reclaim
;
229 ru
->ps_zerofill
+= ru2
->ps_zerofill
;
230 ru
->ps_pffincr
+= ru2
->ps_pffincr
;
231 ru
->ps_pffdecr
+= ru2
->ps_pffdecr
;
232 ru
->ps_swap
+= ru2
->ps_swap
;
233 ru
->ps_syscall
+= ru2
->ps_syscall
;
234 ru
->ps_volcsw
+= ru2
->ps_volcsw
;
235 ru
->ps_involcsw
+= ru2
->ps_involcsw
;
236 ru
->ps_signal
+= ru2
->ps_signal
;
237 ru
->ps_lread
+= ru2
->ps_lread
;
238 ru
->ps_lwrite
+= ru2
->ps_lwrite
;
239 ru
->ps_bread
+= ru2
->ps_bread
;
240 ru
->ps_bwrite
+= ru2
->ps_bwrite
;
241 ru
->ps_phread
+= ru2
->ps_phread
;
242 ru
->ps_phwrite
+= ru2
->ps_phwrite
;
245 # endif /* _SEQUENT_ */
246 #endif /* BSDTIMES */
251 * PWP: the LOG1024 and pagetok stuff taken from the top command,
252 * written by William LeFebvre
254 /* Log base 2 of 1024 is 10 (2^10 == 1024) */
257 /* Convert clicks (kernel pages) to kbytes ... */
258 /* If there is no PGSHIFT defined, assume it is 11 */
259 /* Is this needed for compatability with some old flavor of 4.2 or 4.1? */
262 # define pagetok(size) ((size) << 1)
265 # define pagetok(size) ((size) << (PGSHIFT - LOG1024))
267 # define pagetok(size) ((size) >> (LOG1024 - PGSHIFT))
273 * if any other machines return wierd values in the ru_i* stuff, put
274 * the adjusting macro here:
277 # define IADJUST(i) (pagetok(i)/2)
281 * convex has megabytes * CLK_TCK
282 * multiply by 100 since we use time in 100ths of a second in prusage
284 # define IADJUST(i) (((i) << 10) / CLK_TCK * 100)
286 # define IADJUST(i) (i)
291 prusage(r0
, r1
, e
, b
)
292 register struct sysrusage
*r0
, *r1
;
298 prusage(r0
, r1
, e
, b
)
299 register struct process_stats
*r0
, *r1
;
302 # else /* _SEQUENT_ */
304 prusage(bs
, es
, e
, b
)
314 # endif /* _SEQUENT_ */
315 #endif /* BSDTIMES */
319 (r1
->ru_utime
.tv_sec
- r0
->ru_utime
.tv_sec
) * 100 +
320 (r1
->ru_utime
.tv_usec
- r0
->ru_utime
.tv_usec
) / 10000 +
321 (r1
->ru_stime
.tv_sec
- r0
->ru_stime
.tv_sec
) * 100 +
322 (r1
->ru_stime
.tv_usec
- r0
->ru_stime
.tv_usec
) / 10000;
327 (r1
->ps_utime
.tv_sec
- r0
->ps_utime
.tv_sec
) * 100 +
328 (r1
->ps_utime
.tv_usec
- r0
->ps_utime
.tv_usec
) / 10000 +
329 (r1
->ps_stime
.tv_sec
- r0
->ps_stime
.tv_sec
) * 100 +
330 (r1
->ps_stime
.tv_usec
- r0
->ps_stime
.tv_usec
) / 10000;
332 # else /* _SEQUENT_ */
334 register time_t t
= (es
->tms_utime
- bs
->tms_utime
+
335 es
->tms_stime
- bs
->tms_stime
) * 100 / HZ
;
338 register clock_t t
= (es
->tms_utime
- bs
->tms_utime
+
339 es
->tms_stime
- bs
->tms_stime
) * 100 / clk_tck
;
342 # endif /* _SEQUENT_ */
343 #endif /* BSDTIMES */
347 register struct varent
*vp
= adrof(STRtime
);
351 static struct system_information sysinfo
;
352 long long memtmp
; /* let memory calculations exceede 2Gb */
355 ((e
->tv_sec
- b
->tv_sec
) * 100 + (e
->tv_usec
- b
->tv_usec
) / 10000);
357 cp
= "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
358 #else /* !BSDTIMES */
361 ((e
->tv_sec
- b
->tv_sec
) * 100 + (e
->tv_usec
- b
->tv_usec
) / 10000);
363 cp
= "%Uu %Ss %E %P %I+%Oio %Fpf+%Ww";
364 # else /* !_SEQUENT_ */
366 time_t ms
= ((time_t)((e
- b
) / HZ
) * 100) +
367 (time_t)(((e
- b
) % HZ
) * 100) / HZ
;
369 clock_t ms
= ((clock_t)((e
- b
) / clk_tck
) * 100) +
370 (clock_t)(((e
- b
) % clk_tck
) * 100) / clk_tck
;
373 cp
= "%Uu %Ss %E %P";
376 * the tms stuff is not very precise, so we fudge it.
377 * granularity fix: can't be more than 100%
378 * this breaks in multi-processor systems...
379 * maybe I should take it out and let people see more then 100%
383 if (ms
< t
&& ms
!= 0)
386 # endif /*! _SEQUENT_ */
387 #endif /* !BSDTIMES */
389 xprintf("es->tms_utime %lu bs->tms_utime %lu\n",
390 es
->tms_utime
, bs
->tms_utime
);
391 xprintf("es->tms_stime %lu bs->tms_stime %lu\n",
392 es
->tms_stime
, bs
->tms_stime
);
393 xprintf("ms %lu e %lu b %lu\n", ms
, e
, b
);
394 xprintf("t %lu\n", t
);
397 if (vp
&& vp
->vec
&& vp
->vec
[0] && vp
->vec
[1])
398 cp
= short2str(vp
->vec
[1]);
405 case 'U': /* user CPU time used */
407 pdeltat(&r1
->ru_utime
, &r0
->ru_utime
);
410 pdeltat(&r1
->ps_utime
, &r0
->ps_utime
);
411 # else /* _SEQUENT_ */
413 pdtimet(es
->tms_utime
, bs
->tms_utime
);
415 pdtimet(es
->tms_utime
, bs
->tms_utime
);
417 # endif /* _SEQUENT_ */
418 #endif /* BSDTIMES */
421 case 'S': /* system CPU time used */
423 pdeltat(&r1
->ru_stime
, &r0
->ru_stime
);
426 pdeltat(&r1
->ps_stime
, &r0
->ps_stime
);
427 # else /* _SEQUENT_ */
429 pdtimet(es
->tms_stime
, bs
->tms_stime
);
431 pdtimet(es
->tms_stime
, bs
->tms_stime
);
433 # endif /* _SEQUENT_ */
434 #endif /* BSDTIMES */
437 case 'E': /* elapsed (wall-clock) time */
442 #endif /* BSDTIMES */
445 case 'P': /* percent time spent running */
446 /* check if the process did not run */
449 * scale the cpu %- ages by the number of processors
450 * available on this machine
452 if ((sysinfo
.cpu_count
== 0) &&
453 (getsysinfo(SYSINFO_SIZE
, &sysinfo
) < 0))
454 sysinfo
.cpu_count
= 1;
455 i
= (ms
== 0) ? 0 : (t
* 1000.0 / (ms
* sysinfo
.cpu_count
));
457 i
= (ms
== 0) ? 0 : (long)(t
* 1000.0 / ms
);
459 xprintf("%ld.%01ld%%", i
/ 10, i
% 10); /* nn.n% */
463 case 'W': /* number of swaps */
464 i
= r1
->ru_nswap
- r0
->ru_nswap
;
469 case 'X': /* (average) shared text size */
470 memtmp
= (t
== 0 ? 0LL : IADJUST((long long)r1
->ru_ixrss
-
471 (long long)r0
->ru_ixrss
) /
473 xprintf("%lu", (unsigned long)memtmp
);
477 case 'D': /* (average) unshared data size */
478 memtmp
= (t
== 0 ? 0LL : IADJUST((long long)r1
->ru_idrss
+
479 (long long)r1
->ru_isrss
-
480 ((long long)r0
->ru_idrss
+
481 (long long)r0
->ru_isrss
)) /
483 xprintf("%lu", (unsigned long)memtmp
);
486 case 'K': /* (average) total data memory used */
487 memtmp
= (t
== 0 ? 0LL : IADJUST(((long long)r1
->ru_ixrss
+
488 (long long)r1
->ru_isrss
+
489 (long long)r1
->ru_idrss
) -
490 ((long long)r0
->ru_ixrss
+
491 (long long)r0
->ru_idrss
+
492 (long long)r0
->ru_isrss
)) /
494 xprintf("%lu", (unsigned long)memtmp
);
497 case 'X': /* (average) shared text size */
498 xprintf("%ld", t
== 0 ? 0L :
499 IADJUST(r1
->ru_ixrss
- r0
->ru_ixrss
) / t
);
502 case 'D': /* (average) unshared data size */
503 xprintf("%ld", t
== 0 ? 0L :
504 IADJUST(r1
->ru_idrss
+ r1
->ru_isrss
-
505 (r0
->ru_idrss
+ r0
->ru_isrss
)) / t
);
508 case 'K': /* (average) total data memory used */
509 xprintf("%ld", t
== 0 ? 0L :
510 IADJUST((r1
->ru_ixrss
+ r1
->ru_isrss
+ r1
->ru_idrss
) -
511 (r0
->ru_ixrss
+ r0
->ru_idrss
+ r0
->ru_isrss
)) / t
);
514 case 'M': /* max. Resident Set Size */
516 xprintf("%ld", pagetok(r1
->ru_maxrss
));
519 xprintf("%ld", r1
->ru_maxrss
* 4L);
521 xprintf("%ld", r1
->ru_maxrss
/ 2L);
526 case 'F': /* page faults */
527 xprintf("%ld", r1
->ru_majflt
- r0
->ru_majflt
);
530 case 'R': /* page reclaims */
531 xprintf("%ld", r1
->ru_minflt
- r0
->ru_minflt
);
534 case 'I': /* FS blocks in */
535 xprintf("%ld", r1
->ru_inblock
- r0
->ru_inblock
);
538 case 'O': /* FS blocks out */
539 xprintf("%ld", r1
->ru_oublock
- r0
->ru_oublock
);
543 case 'C': /* CPU parallelization factor */
544 if (r1
->ru_usamples
!= 0LL) {
545 long long parr
= ((r1
->ru_utotal
* 100LL) /
547 xprintf("%d.%02d", (int)(parr
/100), (int)(parr
%100));
552 case 'r': /* PWP: socket messages recieved */
553 xprintf("%ld", r1
->ru_msgrcv
- r0
->ru_msgrcv
);
556 case 's': /* PWP: socket messages sent */
557 xprintf("%ld", r1
->ru_msgsnd
- r0
->ru_msgsnd
);
560 case 'k': /* PWP: signals received */
561 xprintf("%ld", r1
->ru_nsignals
- r0
->ru_nsignals
);
564 case 'w': /* PWP: voluntary context switches (waits) */
565 xprintf("%ld", r1
->ru_nvcsw
- r0
->ru_nvcsw
);
568 case 'c': /* PWP: involuntary context switches */
569 xprintf("%ld", r1
->ru_nivcsw
- r0
->ru_nivcsw
);
573 case 'W': /* number of swaps */
574 i
= r1
->ps_swap
- r0
->ps_swap
;
579 xprintf("%ld", r1
->ps_maxrss
/ 2);
583 xprintf("%ld", r1
->ps_pagein
- r0
->ps_pagein
);
587 xprintf("%ld", r1
->ps_reclaim
- r0
->ps_reclaim
);
591 xprintf("%ld", r1
->ps_bread
- r0
->ps_bread
);
595 xprintf("%ld", r1
->ps_bwrite
- r0
->ps_bwrite
);
599 xprintf("%ld", r1
->ps_signal
- r0
->ps_signal
);
603 xprintf("%ld", r1
->ps_volcsw
- r0
->ps_volcsw
);
607 xprintf("%ld", r1
->ps_involcsw
- r0
->ps_involcsw
);
611 xprintf("%ld", r1
->ps_zerofill
- r0
->ps_zerofill
);
615 xprintf("%ld", r1
->ps_pffincr
- r0
->ps_pffincr
);
619 xprintf("%ld", r1
->ps_pffdecr
- r0
->ps_pffdecr
);
623 xprintf("%ld", r1
->ps_syscall
- r0
->ps_syscall
);
627 xprintf("%ld", r1
->ps_lread
- r0
->ps_lread
);
631 xprintf("%ld", r1
->ps_lwrite
- r0
->ps_lwrite
);
635 xprintf("%ld", r1
->ps_phread
- r0
->ps_phread
);
639 xprintf("%ld", r1
->ps_phwrite
- r0
->ps_phwrite
);
641 # endif /* _SEQUENT_ */
642 #endif /* BSDTIMES */
649 #if defined(BSDTIMES) || defined(_SEQUENT_)
657 xprintf("%ld.%03ld", td
.tv_sec
, td
.tv_usec
/ 1000L);
662 timeval_t
*tsum
, *t0
;
665 tsum
->tv_sec
+= t0
->tv_sec
;
666 tsum
->tv_usec
+= t0
->tv_usec
;
667 if (tsum
->tv_usec
>= 1000000)
668 tsum
->tv_sec
++, tsum
->tv_usec
-= 1000000;
673 timeval_t
*tdiff
, *t1
, *t0
;
676 tdiff
->tv_sec
= t1
->tv_sec
- t0
->tv_sec
;
677 tdiff
->tv_usec
= t1
->tv_usec
- t0
->tv_usec
;
678 if (tdiff
->tv_usec
< 0)
679 tdiff
->tv_sec
--, tdiff
->tv_usec
+= 1000000;
682 #else /* !BSDTIMES && !_SEQUENT_ */
702 val
= (eval
- bval
) * 100 / HZ
;
704 val
= (eval
- bval
) * 100 / clk_tck
;
707 xprintf("%ld.%02ld", val
/ 100, val
- (val
/ 100 * 100));
709 #endif /* BSDTIMES || _SEQUENT_ */