xref: /netbsd-src/bin/csh/time.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: time.c,v 1.11 2001/06/12 15:17:10 wiz Exp $	*/
2 
3 /*-
4  * Copyright (c) 1980, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)time.c	8.1 (Berkeley) 5/31/93";
40 #else
41 __RCSID("$NetBSD: time.c,v 1.11 2001/06/12 15:17:10 wiz Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/types.h>
46 #if __STDC__
47 # include <stdarg.h>
48 #else
49 # include <varargs.h>
50 #endif
51 
52 #include "csh.h"
53 #include "extern.h"
54 
55 /*
56  * C Shell - routines handling process timing and niceing
57  */
58 static void	pdeltat __P((struct timeval *, struct timeval *));
59 extern char * strpct __P((u_long num, u_long denom, u_int digits));
60 
61 void
62 settimes()
63 {
64     struct rusage ruch;
65 
66     (void) gettimeofday(&time0, NULL);
67     (void) getrusage(RUSAGE_SELF, &ru0);
68     (void) getrusage(RUSAGE_CHILDREN, &ruch);
69     ruadd(&ru0, &ruch);
70 }
71 
72 /*
73  * dotime is only called if it is truly a builtin function and not a
74  * prefix to another command
75  */
76 void
77 /*ARGSUSED*/
78 dotime(v, t)
79     Char **v;
80     struct command *t;
81 {
82     struct timeval timedol;
83     struct rusage ru1, ruch;
84 
85     (void) getrusage(RUSAGE_SELF, &ru1);
86     (void) getrusage(RUSAGE_CHILDREN, &ruch);
87     ruadd(&ru1, &ruch);
88     (void) gettimeofday(&timedol, NULL);
89     prusage(&ru0, &ru1, &timedol, &time0);
90 }
91 
92 /*
93  * donice is only called when it on the line by itself or with a +- value
94  */
95 void
96 /*ARGSUSED*/
97 donice(v, t)
98     Char **v;
99     struct command *t;
100 {
101     Char *cp;
102     int     nval = 0;
103 
104     v++, cp = *v++;
105     if (cp == 0)
106 	nval = 4;
107     else if (*v == 0 && any("+-", cp[0]))
108 	nval = getn(cp);
109     (void) setpriority(PRIO_PROCESS, 0, nval);
110 }
111 
112 void
113 ruadd(ru, ru2)
114     struct rusage *ru, *ru2;
115 {
116     timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
117     timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
118     if (ru2->ru_maxrss > ru->ru_maxrss)
119 	ru->ru_maxrss = ru2->ru_maxrss;
120 
121     ru->ru_ixrss += ru2->ru_ixrss;
122     ru->ru_idrss += ru2->ru_idrss;
123     ru->ru_isrss += ru2->ru_isrss;
124     ru->ru_minflt += ru2->ru_minflt;
125     ru->ru_majflt += ru2->ru_majflt;
126     ru->ru_nswap += ru2->ru_nswap;
127     ru->ru_inblock += ru2->ru_inblock;
128     ru->ru_oublock += ru2->ru_oublock;
129     ru->ru_msgsnd += ru2->ru_msgsnd;
130     ru->ru_msgrcv += ru2->ru_msgrcv;
131     ru->ru_nsignals += ru2->ru_nsignals;
132     ru->ru_nvcsw += ru2->ru_nvcsw;
133     ru->ru_nivcsw += ru2->ru_nivcsw;
134 }
135 
136 void
137 prusage(r0, r1, e, b)
138     struct rusage *r0, *r1;
139     struct timeval *e, *b;
140 {
141     time_t t =
142     (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 +
143     (r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 +
144     (r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 +
145     (r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000;
146     char *cp;
147     long i;
148     struct varent *vp = adrof(STRtime);
149 
150     int     ms =
151     (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000;
152 
153     cp = "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
154 
155     if (vp && vp->vec[0] && vp->vec[1])
156 	cp = short2str(vp->vec[1]);
157 
158     for (; *cp; cp++)
159 	if (*cp != '%')
160 	    (void) fputc(*cp, cshout);
161 	else if (cp[1])
162 	    switch (*++cp) {
163 
164 	    case 'U':		/* user CPU time used */
165 		pdeltat(&r1->ru_utime, &r0->ru_utime);
166 		break;
167 
168 	    case 'S':		/* system CPU time used */
169 		pdeltat(&r1->ru_stime, &r0->ru_stime);
170 		break;
171 
172 	    case 'E':		/* elapsed (wall-clock) time */
173 		pcsecs((long) ms);
174 		break;
175 
176 	    case 'P':		/* percent time spent running */
177 		/* check if it did not run at all */
178 		if (ms == 0) {
179 			(void) fputs("0.0%", cshout);
180 		} else {
181 			(void) fputs(strpct((ulong)t, (ulong)ms, 1), cshout);
182 		}
183 		break;
184 
185 	    case 'W':		/* number of swaps */
186 		i = r1->ru_nswap - r0->ru_nswap;
187 		(void) fprintf(cshout, "%ld", i);
188 		break;
189 
190 	    case 'X':		/* (average) shared text size */
191 		(void) fprintf(cshout, "%ld", t == 0 ? 0L :
192 			       (r1->ru_ixrss - r0->ru_ixrss) / t);
193 		break;
194 
195 	    case 'D':		/* (average) unshared data size */
196 		(void) fprintf(cshout, "%ld", t == 0 ? 0L :
197 			(r1->ru_idrss + r1->ru_isrss -
198 			 (r0->ru_idrss + r0->ru_isrss)) / t);
199 		break;
200 
201 	    case 'K':		/* (average) total data memory used  */
202 		(void) fprintf(cshout, "%ld", t == 0 ? 0L :
203 			((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) -
204 			 (r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t);
205 		break;
206 
207 	    case 'M':		/* max. Resident Set Size */
208 		(void) fprintf(cshout, "%ld", r1->ru_maxrss / 2L);
209 		break;
210 
211 	    case 'F':		/* page faults */
212 		(void) fprintf(cshout, "%ld", r1->ru_majflt - r0->ru_majflt);
213 		break;
214 
215 	    case 'R':		/* page reclaims */
216 		(void) fprintf(cshout, "%ld", r1->ru_minflt - r0->ru_minflt);
217 		break;
218 
219 	    case 'I':		/* FS blocks in */
220 		(void) fprintf(cshout, "%ld", r1->ru_inblock - r0->ru_inblock);
221 		break;
222 
223 	    case 'O':		/* FS blocks out */
224 		(void) fprintf(cshout, "%ld", r1->ru_oublock - r0->ru_oublock);
225 		break;
226 
227 	    case 'r':		/* socket messages received */
228 		(void) fprintf(cshout, "%ld", r1->ru_msgrcv - r0->ru_msgrcv);
229 		break;
230 
231 	    case 's':		/* socket messages sent */
232 		(void) fprintf(cshout, "%ld", r1->ru_msgsnd - r0->ru_msgsnd);
233 		break;
234 
235 	    case 'k':		/* number of signals received */
236 		(void) fprintf(cshout, "%ld", r1->ru_nsignals-r0->ru_nsignals);
237 		break;
238 
239 	    case 'w':		/* num. voluntary context switches (waits) */
240 		(void) fprintf(cshout, "%ld", r1->ru_nvcsw - r0->ru_nvcsw);
241 		break;
242 
243 	    case 'c':		/* num. involuntary context switches */
244 		(void) fprintf(cshout, "%ld", r1->ru_nivcsw - r0->ru_nivcsw);
245 		break;
246 	    }
247     (void) fputc('\n', cshout);
248 }
249 
250 static void
251 pdeltat(t1, t0)
252     struct timeval *t1, *t0;
253 {
254     struct timeval td;
255 
256     timersub(t1, t0, &td);
257     (void) fprintf(cshout, "%ld.%01ld", (long) td.tv_sec,
258 	(long) (td.tv_usec / 100000));
259 }
260 
261 #define  P2DIG(i) (void) fprintf(cshout, "%d%d", (i) / 10, (i) % 10)
262 
263 void
264 psecs(l)
265     long    l;
266 {
267     int i;
268 
269     i = l / 3600;
270     if (i) {
271 	(void) fprintf(cshout, "%d:", i);
272 	i = l % 3600;
273 	P2DIG(i / 60);
274 	goto minsec;
275     }
276     i = l;
277     (void) fprintf(cshout, "%d", i / 60);
278 minsec:
279     i %= 60;
280     (void) fputc(':', cshout);
281     P2DIG(i);
282 }
283 
284 void
285 pcsecs(l)			/* PWP: print mm:ss.dd, l is in sec*100 */
286     long    l;
287 {
288     int i;
289 
290     i = l / 360000;
291     if (i) {
292 	(void) fprintf(cshout, "%d:", i);
293 	i = (l % 360000) / 100;
294 	P2DIG(i / 60);
295 	goto minsec;
296     }
297     i = l / 100;
298     (void) fprintf(cshout, "%d", i / 60);
299 minsec:
300     i %= 60;
301     (void) fputc(':', cshout);
302     P2DIG(i);
303     (void) fputc('.', cshout);
304     P2DIG((int) (l % 100));
305 }
306