2 * sh.time.c: Shell time keeping and printing.
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 # include <machine/param.h>
38 * C Shell - routines handling process timing and niceing
42 # define RUSAGE_SELF 0
43 # define RUSAGE_CHILDREN -1
44 # endif /* RUSAGE_SELF */
49 #if !defined(BSDTIMES) && !defined(_SEQUENT_)
51 static void pdtimet (clock_t, clock_t);
53 static void pdtimet (time_t, time_t);
55 #else /* BSDTIMES || _SEQUENT_ */
56 static void tvadd (timeval_t
*, timeval_t
*);
57 static void pdeltat (timeval_t
*, timeval_t
*);
58 #endif /* BSDTIMES || _SEQUENT_ */
64 struct sysrusage ruch
;
66 memset(&ru0
, 0, sizeof(ru0
));
67 memset(&ruch
, 0, sizeof(ruch
));
70 (void) gettimeofday(&time0
, NULL
);
71 (void) getrusage(RUSAGE_SELF
, (struct rusage
*) &ru0
);
72 (void) getrusage(RUSAGE_CHILDREN
, (struct rusage
*) &ruch
);
76 struct process_stats ruch
;
78 (void) get_process_stats(&time0
, PS_SELF
, &ru0
, &ruch
);
80 # else /* _SEQUENT_ */
81 seconds0
= time(NULL
);
82 time0
= times(×0
);
83 times0
.tms_stime
+= times0
.tms_cstime
;
84 times0
.tms_utime
+= times0
.tms_cutime
;
85 times0
.tms_cstime
= 0;
86 times0
.tms_cutime
= 0;
87 # endif /* _SEQUENT_ */
92 * dotime is only called if it is truly a builtin function and not a
93 * prefix to another command
97 dotime(Char
**v
, struct command
*c
)
101 struct sysrusage ru1
, ruch
;
103 memset(&ru1
, 0, sizeof(ru1
));
104 memset(&ruch
, 0, sizeof(ruch
));
107 (void) getrusage(RUSAGE_SELF
, (struct rusage
*) &ru1
);
108 (void) getrusage(RUSAGE_CHILDREN
, (struct rusage
*) &ruch
);
110 (void) gettimeofday(&timedol
, NULL
);
111 prusage(&ru0
, &ru1
, &timedol
, &time0
);
115 struct process_stats ru1
, ruch
;
117 (void) get_process_stats(&timedol
, PS_SELF
, &ru1
, &ruch
);
119 prusage(&ru0
, &ru1
, &timedol
, &time0
);
120 # else /* _SEQUENT_ */
127 struct tms times_dol
;
129 timedol
= times(×_dol
);
130 times_dol
.tms_stime
+= times_dol
.tms_cstime
;
131 times_dol
.tms_utime
+= times_dol
.tms_cutime
;
132 times_dol
.tms_cstime
= 0;
133 times_dol
.tms_cutime
= 0;
134 prusage(×0
, ×_dol
, timedol
, time0
);
135 # endif /* _SEQUENT_ */
136 #endif /* BSDTIMES */
142 * donice is only called when it on the line by itself or with a +- value
146 donice(Char
**v
, struct command
*c
)
155 else if (*v
== 0 && any("+-", cp
[0]))
157 #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
158 if (setpriority(PRIO_PROCESS
, 0, nval
) == -1 && errno
)
159 stderror(ERR_SYSTEM
, "setpriority", strerror(errno
));
160 #else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */
162 #endif /* HAVE_SETPRIORITY && PRIO_PROCESS */
167 ruadd(struct sysrusage
*ru
, struct sysrusage
*ru2
)
169 tvadd(&ru
->ru_utime
, &ru2
->ru_utime
);
170 tvadd(&ru
->ru_stime
, &ru2
->ru_stime
);
172 if (ru2
->ru_maxrss
> ru
->ru_maxrss
)
173 ru
->ru_maxrss
= ru2
->ru_maxrss
;
175 ru
->ru_ixrss
+= ru2
->ru_ixrss
;
176 ru
->ru_idrss
+= ru2
->ru_idrss
;
177 ru
->ru_isrss
+= ru2
->ru_isrss
;
178 ru
->ru_minflt
+= ru2
->ru_minflt
;
179 ru
->ru_majflt
+= ru2
->ru_majflt
;
180 ru
->ru_nswap
+= ru2
->ru_nswap
;
181 ru
->ru_inblock
+= ru2
->ru_inblock
;
182 ru
->ru_oublock
+= ru2
->ru_oublock
;
183 ru
->ru_msgsnd
+= ru2
->ru_msgsnd
;
184 ru
->ru_msgrcv
+= ru2
->ru_msgrcv
;
185 ru
->ru_nsignals
+= ru2
->ru_nsignals
;
186 ru
->ru_nvcsw
+= ru2
->ru_nvcsw
;
187 ru
->ru_nivcsw
+= ru2
->ru_nivcsw
;
191 tvadd(&ru
->ru_exutime
, &ru2
->ru_exutime
);
192 ru
->ru_utotal
+= ru2
->ru_utotal
;
193 ru
->ru_usamples
+= ru2
->ru_usamples
;
194 ru
->ru_stotal
+= ru2
->ru_stotal
;
195 ru
->ru_ssamples
+= ru2
->ru_ssamples
;
202 ruadd(struct process_stats
*ru
, struct process_stats
*ru2
)
204 tvadd(&ru
->ps_utime
, &ru2
->ps_utime
);
205 tvadd(&ru
->ps_stime
, &ru2
->ps_stime
);
206 if (ru2
->ps_maxrss
> ru
->ps_maxrss
)
207 ru
->ps_maxrss
= ru2
->ps_maxrss
;
209 ru
->ps_pagein
+= ru2
->ps_pagein
;
210 ru
->ps_reclaim
+= ru2
->ps_reclaim
;
211 ru
->ps_zerofill
+= ru2
->ps_zerofill
;
212 ru
->ps_pffincr
+= ru2
->ps_pffincr
;
213 ru
->ps_pffdecr
+= ru2
->ps_pffdecr
;
214 ru
->ps_swap
+= ru2
->ps_swap
;
215 ru
->ps_syscall
+= ru2
->ps_syscall
;
216 ru
->ps_volcsw
+= ru2
->ps_volcsw
;
217 ru
->ps_involcsw
+= ru2
->ps_involcsw
;
218 ru
->ps_signal
+= ru2
->ps_signal
;
219 ru
->ps_lread
+= ru2
->ps_lread
;
220 ru
->ps_lwrite
+= ru2
->ps_lwrite
;
221 ru
->ps_bread
+= ru2
->ps_bread
;
222 ru
->ps_bwrite
+= ru2
->ps_bwrite
;
223 ru
->ps_phread
+= ru2
->ps_phread
;
224 ru
->ps_phwrite
+= ru2
->ps_phwrite
;
227 # endif /* _SEQUENT_ */
228 #endif /* BSDTIMES */
233 * PWP: the LOG1024 and pagetok stuff taken from the top command,
234 * written by William LeFebvre
236 /* Log base 2 of 1024 is 10 (2^10 == 1024) */
239 /* Convert clicks (kernel pages) to kbytes ... */
240 /* If there is no PGSHIFT defined, assume it is 11 */
241 /* Is this needed for compatability with some old flavor of 4.2 or 4.1? */
244 # define pagetok(size) ((size) << 1)
247 # define pagetok(size) ((size) << (PGSHIFT - LOG1024))
249 # define pagetok(size) ((size) >> (LOG1024 - PGSHIFT))
255 * if any other machines return wierd values in the ru_i* stuff, put
256 * the adjusting macro here:
259 # define IADJUST(i) (pagetok(i)/2)
263 * convex has megabytes * CLK_TCK
264 * multiply by 100 since we use time in 100ths of a second in prusage
266 # define IADJUST(i) (((i) << 10) / CLK_TCK * 100)
268 # define IADJUST(i) (i)
273 prusage(struct sysrusage
*r0
, struct sysrusage
*r1
, timeval_t
*e
, timeval_t
*b
)
278 prusage(struct process_stats
*r0
, struct process_stats
*r1
, timeval_t e
,
281 # else /* _SEQUENT_ */
284 prusage(struct tms
*bs
, struct tms
*es
, time_t e
, time_t b
)
287 prusage(struct tms
*bs
, struct tms
*es
, clock_t e
, clock_t b
)
289 # endif /* _SEQUENT_ */
290 #endif /* BSDTIMES */
292 int ohaderr
= haderr
;
295 (r1
->ru_utime
.tv_sec
- r0
->ru_utime
.tv_sec
) * 100 +
296 (r1
->ru_utime
.tv_usec
- r0
->ru_utime
.tv_usec
) / 10000 +
297 (r1
->ru_stime
.tv_sec
- r0
->ru_stime
.tv_sec
) * 100 +
298 (r1
->ru_stime
.tv_usec
- r0
->ru_stime
.tv_usec
) / 10000;
303 (r1
->ps_utime
.tv_sec
- r0
->ps_utime
.tv_sec
) * 100 +
304 (r1
->ps_utime
.tv_usec
- r0
->ps_utime
.tv_usec
) / 10000 +
305 (r1
->ps_stime
.tv_sec
- r0
->ps_stime
.tv_sec
) * 100 +
306 (r1
->ps_stime
.tv_usec
- r0
->ps_stime
.tv_usec
) / 10000;
308 # else /* _SEQUENT_ */
310 time_t t
= (es
->tms_utime
- bs
->tms_utime
+
311 es
->tms_stime
- bs
->tms_stime
) * 100 / HZ
;
314 clock_t t
= (es
->tms_utime
- bs
->tms_utime
+
315 es
->tms_stime
- bs
->tms_stime
) * 100 / clk_tck
;
318 # endif /* _SEQUENT_ */
319 #endif /* BSDTIMES */
323 struct varent
*vp
= adrof(STRtime
);
327 static struct system_information sysinfo
;
328 long long memtmp
; /* let memory calculations exceede 2Gb */
331 ((e
->tv_sec
- b
->tv_sec
) * 100 + (e
->tv_usec
- b
->tv_usec
) / 10000);
333 cp
= "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
335 #else /* !BSDTIMES */
338 ((e
->tv_sec
- b
->tv_sec
) * 100 + (e
->tv_usec
- b
->tv_usec
) / 10000);
340 cp
= "%Uu %Ss %E %P %I+%Oio %Fpf+%Ww";
342 # else /* !_SEQUENT_ */
344 time_t ms
= ((time_t)((e
- b
) / HZ
) * 100) +
345 (time_t)(((e
- b
) % HZ
) * 100) / HZ
;
347 clock_t ms
= ((clock_t)((e
- b
) / clk_tck
) * 100) +
348 (clock_t)(((e
- b
) % clk_tck
) * 100) / clk_tck
;
351 cp
= "%Uu %Ss %E %P";
355 * the tms stuff is not very precise, so we fudge it.
356 * granularity fix: can't be more than 100%
357 * this breaks in multi-processor systems...
358 * maybe I should take it out and let people see more then 100%
362 if (ms
< t
&& ms
!= 0)
365 # endif /*! _SEQUENT_ */
366 #endif /* !BSDTIMES */
368 xprintf("es->tms_utime %lu bs->tms_utime %lu\n",
369 (unsigned long)es
->tms_utime
, (unsigned long)bs
->tms_utime
);
370 xprintf("es->tms_stime %lu bs->tms_stime %lu\n",
371 (unsigned long)es
->tms_stime
, (unsigned long)bs
->tms_stime
);
372 xprintf("ms %llu e %p b %p\n", (unsigned long long)ms
, e
, b
);
373 xprintf("t %llu\n", (unsigned long long)t
);
376 if (vp
&& vp
->vec
&& vp
->vec
[0] && vp
->vec
[1])
377 cp
= short2str(vp
->vec
[1]);
384 case 'U': /* user CPU time used */
386 pdeltat(&r1
->ru_utime
, &r0
->ru_utime
);
389 pdeltat(&r1
->ps_utime
, &r0
->ps_utime
);
390 # else /* _SEQUENT_ */
392 pdtimet(es
->tms_utime
, bs
->tms_utime
);
394 pdtimet(es
->tms_utime
, bs
->tms_utime
);
396 # endif /* _SEQUENT_ */
397 #endif /* BSDTIMES */
400 case 'S': /* system CPU time used */
402 pdeltat(&r1
->ru_stime
, &r0
->ru_stime
);
405 pdeltat(&r1
->ps_stime
, &r0
->ps_stime
);
406 # else /* _SEQUENT_ */
408 pdtimet(es
->tms_stime
, bs
->tms_stime
);
410 pdtimet(es
->tms_stime
, bs
->tms_stime
);
412 # endif /* _SEQUENT_ */
413 #endif /* BSDTIMES */
416 case 'E': /* elapsed (wall-clock) time */
421 #endif /* BSDTIMES */
424 case 'P': /* percent time spent running */
425 /* check if the process did not run */
428 * scale the cpu %- ages by the number of processors
429 * available on this machine
431 if ((sysinfo
.cpu_count
== 0) &&
432 (getsysinfo(SYSINFO_SIZE
, &sysinfo
) < 0))
433 sysinfo
.cpu_count
= 1;
434 i
= (ms
== 0) ? 0 : (t
* 1000.0 / (ms
* sysinfo
.cpu_count
));
436 i
= (ms
== 0) ? 0 : (long)(t
* 1000.0 / ms
);
438 xprintf("%ld.%01ld%%", i
/ 10, i
% 10); /* nn.n% */
442 case 'W': /* number of swaps */
446 i
= r1
->ru_nswap
- r0
->ru_nswap
;
452 case 'X': /* (average) shared text size */
453 memtmp
= (t
== 0 ? 0LL : IADJUST((long long)r1
->ru_ixrss
-
454 (long long)r0
->ru_ixrss
) /
456 xprintf("%lu", (unsigned long)memtmp
);
459 case 'D': /* (average) unshared data size */
460 memtmp
= (t
== 0 ? 0LL : IADJUST((long long)r1
->ru_idrss
+
461 (long long)r1
->ru_isrss
-
462 ((long long)r0
->ru_idrss
+
463 (long long)r0
->ru_isrss
)) /
465 xprintf("%lu", (unsigned long)memtmp
);
468 case 'K': /* (average) total data memory used */
469 memtmp
= (t
== 0 ? 0LL : IADJUST(((long long)r1
->ru_ixrss
+
470 (long long)r1
->ru_isrss
+
471 (long long)r1
->ru_idrss
) -
472 ((long long)r0
->ru_ixrss
+
473 (long long)r0
->ru_idrss
+
474 (long long)r0
->ru_isrss
)) /
476 xprintf("%lu", (unsigned long)memtmp
);
479 case 'X': /* (average) shared text size */
483 xprintf("%lld", (long long)(t
== 0 ? 0L :
484 IADJUST(r1
->ru_ixrss
- r0
->ru_ixrss
) / t
));
488 case 'D': /* (average) unshared data size */
492 xprintf("%lld", (long long)(t
== 0 ? 0L :
493 IADJUST(r1
->ru_idrss
+ r1
->ru_isrss
-
494 (r0
->ru_idrss
+ r0
->ru_isrss
)) / t
));
498 case 'K': /* (average) total data memory used */
502 xprintf("%lld", (long long)(t
== 0 ? 0L :
503 IADJUST((r1
->ru_ixrss
+ r1
->ru_isrss
+ r1
->ru_idrss
) -
504 (r0
->ru_ixrss
+ r0
->ru_idrss
+ r0
->ru_isrss
)) / t
));
508 case 'M': /* max. Resident Set Size */
510 xprintf("%ld", (long)pagetok(r1
->ru_maxrss
));
513 xprintf("%ld", (long)(r1
->ru_maxrss
* 4L));
518 xprintf("%ld", (long)r1
->ru_maxrss
);
524 case 'F': /* page faults */
528 xprintf("%ld", (long)(r1
->ru_majflt
- r0
->ru_majflt
));
532 case 'R': /* page reclaims */
536 xprintf("%ld", (long)(r1
->ru_minflt
- r0
->ru_minflt
));
540 case 'I': /* FS blocks in */
544 xprintf("%ld", (long)(r1
->ru_inblock
- r0
->ru_inblock
));
548 case 'O': /* FS blocks out */
552 xprintf("%ld", (long)(r1
->ru_oublock
- r0
->ru_oublock
));
557 case 'C': /* CPU parallelization factor */
558 if (r1
->ru_usamples
!= 0LL) {
559 long long parr
= ((r1
->ru_utotal
* 100LL) /
561 xprintf("%d.%02d", (int)(parr
/100), (int)(parr
%100));
566 case 'r': /* PWP: socket messages recieved */
570 xprintf("%ld", (long)(r1
->ru_msgrcv
- r0
->ru_msgrcv
));
574 case 's': /* PWP: socket messages sent */
578 xprintf("%ld", (long)(r1
->ru_msgsnd
- r0
->ru_msgsnd
));
582 case 'k': /* PWP: signals received */
586 xprintf("%ld", (long)(r1
->ru_nsignals
- r0
->ru_nsignals
));
590 case 'w': /* PWP: voluntary context switches (waits) */
594 xprintf("%ld", (long)(r1
->ru_nvcsw
- r0
->ru_nvcsw
));
598 case 'c': /* PWP: involuntary context switches */
602 xprintf("%ld", (long)(r1
->ru_nivcsw
- r0
->ru_nivcsw
));
607 case 'W': /* number of swaps */
608 i
= r1
->ps_swap
- r0
->ps_swap
;
609 xprintf("%ld", (long)i
);
613 xprintf("%ld", (long)r1
->ps_maxrss
);
617 xprintf("%ld", (long)(r1
->ps_pagein
- r0
->ps_pagein
));
621 xprintf("%ld", (long)(r1
->ps_reclaim
- r0
->ps_reclaim
));
625 xprintf("%ld", (long)(r1
->ps_bread
- r0
->ps_bread
));
629 xprintf("%ld", (long)(r1
->ps_bwrite
- r0
->ps_bwrite
));
633 xprintf("%ld", (long)(r1
->ps_signal
- r0
->ps_signal
));
637 xprintf("%ld", (long)(r1
->ps_volcsw
- r0
->ps_volcsw
));
641 xprintf("%ld", r1
->ps_involcsw
- r0
->ps_involcsw
);
645 xprintf("%ld", (long)(r1
->ps_zerofill
- r0
->ps_zerofill
));
649 xprintf("%ld", (long)(r1
->ps_pffincr
- r0
->ps_pffincr
));
653 xprintf("%ld", (long)(r1
->ps_pffdecr
- r0
->ps_pffdecr
));
657 xprintf("%ld", (long)(r1
->ps_syscall
- r0
->ps_syscall
));
661 xprintf("%ld", (long)(r1
->ps_lread
- r0
->ps_lread
));
665 xprintf("%ld", (long)(r1
->ps_lwrite
- r0
->ps_lwrite
));
669 xprintf("%ld", (long)(r1
->ps_phread
- r0
->ps_phread
));
673 xprintf("%ld", (long)(r1
->ps_phwrite
- r0
->ps_phwrite
));
675 # endif /* _SEQUENT_ */
676 #endif /* BSDTIMES */
684 #if defined(BSDTIMES) || defined(_SEQUENT_)
686 pdeltat(timeval_t
*t1
, timeval_t
*t0
)
691 xprintf("%lld.%03ld", (long long)td
.tv_sec
, (long)td
.tv_usec
/ 1000L);
695 tvadd(timeval_t
*tsum
, timeval_t
*t0
)
698 tsum
->tv_sec
+= t0
->tv_sec
;
699 tsum
->tv_usec
+= t0
->tv_usec
;
700 if (tsum
->tv_usec
>= 1000000)
701 tsum
->tv_sec
++, tsum
->tv_usec
-= 1000000;
705 tvsub(timeval_t
*tdiff
, timeval_t
*t1
, timeval_t
*t0
)
708 tdiff
->tv_sec
= t1
->tv_sec
- t0
->tv_sec
;
709 tdiff
->tv_usec
= t1
->tv_usec
- t0
->tv_usec
;
710 if (tdiff
->tv_usec
< 0)
711 tdiff
->tv_sec
--, tdiff
->tv_usec
+= 1000000;
714 #else /* !BSDTIMES && !_SEQUENT_ */
717 pdtimet(time_t eval
, time_t bval
)
720 pdtimet(clock_t eval
, clock_t bval
)
733 val
= (eval
- bval
) * 100 / HZ
;
735 val
= (eval
- bval
) * 100 / clk_tck
;
738 xprintf("%lld.%02ld", (long long)(val
/ 100),
739 (long long)(val
- (val
/ 100 * 100)));
741 #endif /* BSDTIMES || _SEQUENT_ */