1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.time.c,v 3.36 2013/03/18 21:00:46 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("$tcsh: sh.time.c,v 3.36 2013/03/18 21:00:46 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 (clock_t, clock_t);
57 static void pdtimet (time_t, time_t);
59 #else /* BSDTIMES || _SEQUENT_ */
60 static void tvadd (timeval_t
*, timeval_t
*);
61 static void pdeltat (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
);
86 time0
= times(×0
);
87 times0
.tms_stime
+= times0
.tms_cstime
;
88 times0
.tms_utime
+= times0
.tms_cutime
;
89 times0
.tms_cstime
= 0;
90 times0
.tms_cutime
= 0;
91 # endif /* _SEQUENT_ */
96 * dotime is only called if it is truly a builtin function and not a
97 * prefix to another command
101 dotime(Char
**v
, struct command
*c
)
105 struct sysrusage ru1
, ruch
;
107 memset(&ru1
, 0, sizeof(ru1
));
108 memset(&ruch
, 0, sizeof(ruch
));
111 (void) getrusage(RUSAGE_SELF
, (struct rusage
*) &ru1
);
112 (void) getrusage(RUSAGE_CHILDREN
, (struct rusage
*) &ruch
);
114 (void) gettimeofday(&timedol
, NULL
);
115 prusage(&ru0
, &ru1
, &timedol
, &time0
);
119 struct process_stats ru1
, ruch
;
121 (void) get_process_stats(&timedol
, PS_SELF
, &ru1
, &ruch
);
123 prusage(&ru0
, &ru1
, &timedol
, &time0
);
124 # else /* _SEQUENT_ */
131 struct tms times_dol
;
133 timedol
= times(×_dol
);
134 times_dol
.tms_stime
+= times_dol
.tms_cstime
;
135 times_dol
.tms_utime
+= times_dol
.tms_cutime
;
136 times_dol
.tms_cstime
= 0;
137 times_dol
.tms_cutime
= 0;
138 prusage(×0
, ×_dol
, timedol
, time0
);
139 # endif /* _SEQUENT_ */
140 #endif /* BSDTIMES */
146 * donice is only called when it on the line by itself or with a +- value
150 donice(Char
**v
, struct command
*c
)
159 else if (*v
== 0 && any("+-", cp
[0]))
161 #if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS)
162 if (setpriority(PRIO_PROCESS
, 0, nval
) == -1 && errno
)
163 stderror(ERR_SYSTEM
, "setpriority", strerror(errno
));
164 #else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */
166 #endif /* HAVE_SETPRIORITY && PRIO_PROCESS */
171 ruadd(struct sysrusage
*ru
, struct sysrusage
*ru2
)
173 tvadd(&ru
->ru_utime
, &ru2
->ru_utime
);
174 tvadd(&ru
->ru_stime
, &ru2
->ru_stime
);
176 if (ru2
->ru_maxrss
> ru
->ru_maxrss
)
177 ru
->ru_maxrss
= ru2
->ru_maxrss
;
179 ru
->ru_ixrss
+= ru2
->ru_ixrss
;
180 ru
->ru_idrss
+= ru2
->ru_idrss
;
181 ru
->ru_isrss
+= ru2
->ru_isrss
;
182 ru
->ru_minflt
+= ru2
->ru_minflt
;
183 ru
->ru_majflt
+= ru2
->ru_majflt
;
184 ru
->ru_nswap
+= ru2
->ru_nswap
;
185 ru
->ru_inblock
+= ru2
->ru_inblock
;
186 ru
->ru_oublock
+= ru2
->ru_oublock
;
187 ru
->ru_msgsnd
+= ru2
->ru_msgsnd
;
188 ru
->ru_msgrcv
+= ru2
->ru_msgrcv
;
189 ru
->ru_nsignals
+= ru2
->ru_nsignals
;
190 ru
->ru_nvcsw
+= ru2
->ru_nvcsw
;
191 ru
->ru_nivcsw
+= ru2
->ru_nivcsw
;
195 tvadd(&ru
->ru_exutime
, &ru2
->ru_exutime
);
196 ru
->ru_utotal
+= ru2
->ru_utotal
;
197 ru
->ru_usamples
+= ru2
->ru_usamples
;
198 ru
->ru_stotal
+= ru2
->ru_stotal
;
199 ru
->ru_ssamples
+= ru2
->ru_ssamples
;
206 ruadd(struct process_stats
*ru
, struct process_stats
*ru2
)
208 tvadd(&ru
->ps_utime
, &ru2
->ps_utime
);
209 tvadd(&ru
->ps_stime
, &ru2
->ps_stime
);
210 if (ru2
->ps_maxrss
> ru
->ps_maxrss
)
211 ru
->ps_maxrss
= ru2
->ps_maxrss
;
213 ru
->ps_pagein
+= ru2
->ps_pagein
;
214 ru
->ps_reclaim
+= ru2
->ps_reclaim
;
215 ru
->ps_zerofill
+= ru2
->ps_zerofill
;
216 ru
->ps_pffincr
+= ru2
->ps_pffincr
;
217 ru
->ps_pffdecr
+= ru2
->ps_pffdecr
;
218 ru
->ps_swap
+= ru2
->ps_swap
;
219 ru
->ps_syscall
+= ru2
->ps_syscall
;
220 ru
->ps_volcsw
+= ru2
->ps_volcsw
;
221 ru
->ps_involcsw
+= ru2
->ps_involcsw
;
222 ru
->ps_signal
+= ru2
->ps_signal
;
223 ru
->ps_lread
+= ru2
->ps_lread
;
224 ru
->ps_lwrite
+= ru2
->ps_lwrite
;
225 ru
->ps_bread
+= ru2
->ps_bread
;
226 ru
->ps_bwrite
+= ru2
->ps_bwrite
;
227 ru
->ps_phread
+= ru2
->ps_phread
;
228 ru
->ps_phwrite
+= ru2
->ps_phwrite
;
231 # endif /* _SEQUENT_ */
232 #endif /* BSDTIMES */
237 * PWP: the LOG1024 and pagetok stuff taken from the top command,
238 * written by William LeFebvre
240 /* Log base 2 of 1024 is 10 (2^10 == 1024) */
243 /* Convert clicks (kernel pages) to kbytes ... */
244 /* If there is no PGSHIFT defined, assume it is 11 */
245 /* Is this needed for compatability with some old flavor of 4.2 or 4.1? */
248 # define pagetok(size) ((size) << 1)
251 # define pagetok(size) ((size) << (PGSHIFT - LOG1024))
253 # define pagetok(size) ((size) >> (LOG1024 - PGSHIFT))
259 * if any other machines return wierd values in the ru_i* stuff, put
260 * the adjusting macro here:
263 # define IADJUST(i) (pagetok(i)/2)
267 * convex has megabytes * CLK_TCK
268 * multiply by 100 since we use time in 100ths of a second in prusage
270 # define IADJUST(i) (((i) << 10) / CLK_TCK * 100)
272 # define IADJUST(i) (i)
277 prusage(struct sysrusage
*r0
, struct sysrusage
*r1
, timeval_t
*e
, timeval_t
*b
)
282 prusage(struct process_stats
*r0
, struct process_stats
*r1
, timeval_t e
,
285 # else /* _SEQUENT_ */
288 prusage(struct tms
*bs
, struct tms
*es
, time_t e
, time_t b
)
291 prusage(struct tms
*bs
, struct tms
*es
, clock_t e
, clock_t b
)
293 # endif /* _SEQUENT_ */
294 #endif /* BSDTIMES */
298 (r1
->ru_utime
.tv_sec
- r0
->ru_utime
.tv_sec
) * 100 +
299 (r1
->ru_utime
.tv_usec
- r0
->ru_utime
.tv_usec
) / 10000 +
300 (r1
->ru_stime
.tv_sec
- r0
->ru_stime
.tv_sec
) * 100 +
301 (r1
->ru_stime
.tv_usec
- r0
->ru_stime
.tv_usec
) / 10000;
306 (r1
->ps_utime
.tv_sec
- r0
->ps_utime
.tv_sec
) * 100 +
307 (r1
->ps_utime
.tv_usec
- r0
->ps_utime
.tv_usec
) / 10000 +
308 (r1
->ps_stime
.tv_sec
- r0
->ps_stime
.tv_sec
) * 100 +
309 (r1
->ps_stime
.tv_usec
- r0
->ps_stime
.tv_usec
) / 10000;
311 # else /* _SEQUENT_ */
313 time_t t
= (es
->tms_utime
- bs
->tms_utime
+
314 es
->tms_stime
- bs
->tms_stime
) * 100 / HZ
;
317 clock_t t
= (es
->tms_utime
- bs
->tms_utime
+
318 es
->tms_stime
- bs
->tms_stime
) * 100 / clk_tck
;
321 # endif /* _SEQUENT_ */
322 #endif /* BSDTIMES */
326 struct varent
*vp
= adrof(STRtime
);
330 static struct system_information sysinfo
;
331 long long memtmp
; /* let memory calculations exceede 2Gb */
334 ((e
->tv_sec
- b
->tv_sec
) * 100 + (e
->tv_usec
- b
->tv_usec
) / 10000);
336 cp
= "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
337 #else /* !BSDTIMES */
340 ((e
->tv_sec
- b
->tv_sec
) * 100 + (e
->tv_usec
- b
->tv_usec
) / 10000);
342 cp
= "%Uu %Ss %E %P %I+%Oio %Fpf+%Ww";
343 # else /* !_SEQUENT_ */
345 time_t ms
= ((time_t)((e
- b
) / HZ
) * 100) +
346 (time_t)(((e
- b
) % HZ
) * 100) / HZ
;
348 clock_t ms
= ((clock_t)((e
- b
) / clk_tck
) * 100) +
349 (clock_t)(((e
- b
) % clk_tck
) * 100) / clk_tck
;
352 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 */
683 #if defined(BSDTIMES) || defined(_SEQUENT_)
685 pdeltat(timeval_t
*t1
, timeval_t
*t0
)
690 xprintf("%lld.%03ld", (long long)td
.tv_sec
, (long)td
.tv_usec
/ 1000L);
694 tvadd(timeval_t
*tsum
, timeval_t
*t0
)
697 tsum
->tv_sec
+= t0
->tv_sec
;
698 tsum
->tv_usec
+= t0
->tv_usec
;
699 if (tsum
->tv_usec
>= 1000000)
700 tsum
->tv_sec
++, tsum
->tv_usec
-= 1000000;
704 tvsub(timeval_t
*tdiff
, timeval_t
*t1
, timeval_t
*t0
)
707 tdiff
->tv_sec
= t1
->tv_sec
- t0
->tv_sec
;
708 tdiff
->tv_usec
= t1
->tv_usec
- t0
->tv_usec
;
709 if (tdiff
->tv_usec
< 0)
710 tdiff
->tv_sec
--, tdiff
->tv_usec
+= 1000000;
713 #else /* !BSDTIMES && !_SEQUENT_ */
716 pdtimet(time_t eval
, time_t bval
)
719 pdtimet(clock_t eval
, clock_t bval
)
732 val
= (eval
- bval
) * 100 / HZ
;
734 val
= (eval
- bval
) * 100 / clk_tck
;
737 xprintf("%lld.%02ld", (long long)(val
/ 100),
738 (long long)(val
- (val
/ 100 * 100)));
740 #endif /* BSDTIMES || _SEQUENT_ */