xref: /original-bsd/bin/csh/time.c (revision a5a45b47)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)time.c	5.15 (Berkeley) 07/19/91";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #if __STDC__
14 # include <stdarg.h>
15 #else
16 # include <varargs.h>
17 #endif
18 
19 #include "csh.h"
20 #include "extern.h"
21 
22 /*
23  * C Shell - routines handling process timing and niceing
24  */
25 static void	pdeltat __P((struct timeval *, struct timeval *));
26 
27 void
28 settimes()
29 {
30     struct rusage ruch;
31 
32     (void) gettimeofday(&time0, NULL);
33     (void) getrusage(RUSAGE_SELF, &ru0);
34     (void) getrusage(RUSAGE_CHILDREN, &ruch);
35     ruadd(&ru0, &ruch);
36 }
37 
38 /*
39  * dotime is only called if it is truly a builtin function and not a
40  * prefix to another command
41  */
42 void
43 /*ARGSUSED*/
44 dotime(v, t)
45     Char **v;
46     struct command *t;
47 {
48     struct timeval timedol;
49     struct rusage ru1, ruch;
50 
51     (void) getrusage(RUSAGE_SELF, &ru1);
52     (void) getrusage(RUSAGE_CHILDREN, &ruch);
53     ruadd(&ru1, &ruch);
54     (void) gettimeofday(&timedol, NULL);
55     prusage(&ru0, &ru1, &timedol, &time0);
56 }
57 
58 /*
59  * donice is only called when it on the line by itself or with a +- value
60  */
61 void
62 /*ARGSUSED*/
63 donice(v, t)
64     Char **v;
65     struct command *t;
66 {
67     register Char *cp;
68     int     nval = 0;
69 
70     v++, cp = *v++;
71     if (cp == 0)
72 	nval = 4;
73     else if (*v == 0 && any("+-", cp[0]))
74 	nval = getn(cp);
75     (void) setpriority(PRIO_PROCESS, 0, nval);
76 }
77 
78 void
79 ruadd(ru, ru2)
80     register struct rusage *ru, *ru2;
81 {
82     tvadd(&ru->ru_utime, &ru2->ru_utime);
83     tvadd(&ru->ru_stime, &ru2->ru_stime);
84     if (ru2->ru_maxrss > ru->ru_maxrss)
85 	ru->ru_maxrss = ru2->ru_maxrss;
86 
87     ru->ru_ixrss += ru2->ru_ixrss;
88     ru->ru_idrss += ru2->ru_idrss;
89     ru->ru_isrss += ru2->ru_isrss;
90     ru->ru_minflt += ru2->ru_minflt;
91     ru->ru_majflt += ru2->ru_majflt;
92     ru->ru_nswap += ru2->ru_nswap;
93     ru->ru_inblock += ru2->ru_inblock;
94     ru->ru_oublock += ru2->ru_oublock;
95     ru->ru_msgsnd += ru2->ru_msgsnd;
96     ru->ru_msgrcv += ru2->ru_msgrcv;
97     ru->ru_nsignals += ru2->ru_nsignals;
98     ru->ru_nvcsw += ru2->ru_nvcsw;
99     ru->ru_nivcsw += ru2->ru_nivcsw;
100 }
101 
102 void
103 prusage(r0, r1, e, b)
104     register struct rusage *r0, *r1;
105     struct timeval *e, *b;
106 {
107     register time_t t =
108     (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 +
109     (r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 +
110     (r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 +
111     (r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000;
112     register char *cp;
113     register long i;
114     register struct varent *vp = adrof(STRtime);
115 
116     int     ms =
117     (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000;
118 
119     cp = "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
120 
121     if (vp && vp->vec[0] && vp->vec[1])
122 	cp = short2str(vp->vec[1]);
123 
124     for (; *cp; cp++)
125 	if (*cp != '%')
126 	    (void) fputc(*cp, cshout);
127 	else if (cp[1])
128 	    switch (*++cp) {
129 
130 	    case 'U':		/* user CPU time used */
131 		pdeltat(&r1->ru_utime, &r0->ru_utime);
132 		break;
133 
134 	    case 'S':		/* system CPU time used */
135 		pdeltat(&r1->ru_stime, &r0->ru_stime);
136 		break;
137 
138 	    case 'E':		/* elapsed (wall-clock) time */
139 		pcsecs((long) ms);
140 		break;
141 
142 	    case 'P':		/* percent time spent running */
143 		/* check if it did not run at all */
144 		i = (ms == 0) ? 0 : (t * 1000 / ms);
145 		/* nn.n% */
146 		(void) fprintf(cshout, "%ld.%01ld%%", i / 10, i % 10);
147 		break;
148 
149 	    case 'W':		/* number of swaps */
150 		i = r1->ru_nswap - r0->ru_nswap;
151 		(void) fprintf(cshout, "%ld", i);
152 		break;
153 
154 	    case 'X':		/* (average) shared text size */
155 		(void) fprintf(cshout, "%ld", t == 0 ? 0L :
156 			       (r1->ru_ixrss - r0->ru_ixrss) / t);
157 		break;
158 
159 	    case 'D':		/* (average) unshared data size */
160 		(void) fprintf(cshout, "%ld", t == 0 ? 0L :
161 			(r1->ru_idrss + r1->ru_isrss -
162 			 (r0->ru_idrss + r0->ru_isrss)) / t);
163 		break;
164 
165 	    case 'K':		/* (average) total data memory used  */
166 		(void) fprintf(cshout, "%ld", t == 0 ? 0L :
167 			((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) -
168 			 (r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t);
169 		break;
170 
171 	    case 'M':		/* max. Resident Set Size */
172 		(void) fprintf(cshout, "%ld", r1->ru_maxrss / 2L);
173 		break;
174 
175 	    case 'F':		/* page faults */
176 		(void) fprintf(cshout, "%ld", r1->ru_majflt - r0->ru_majflt);
177 		break;
178 
179 	    case 'R':		/* page reclaims */
180 		(void) fprintf(cshout, "%ld", r1->ru_minflt - r0->ru_minflt);
181 		break;
182 
183 	    case 'I':		/* FS blocks in */
184 		(void) fprintf(cshout, "%ld", r1->ru_inblock - r0->ru_inblock);
185 		break;
186 
187 	    case 'O':		/* FS blocks out */
188 		(void) fprintf(cshout, "%ld", r1->ru_oublock - r0->ru_oublock);
189 		break;
190 
191 	    case 'r':		/* socket messages recieved */
192 		(void) fprintf(cshout, "%ld", r1->ru_msgrcv - r0->ru_msgrcv);
193 		break;
194 
195 	    case 's':		/* socket messages sent */
196 		(void) fprintf(cshout, "%ld", r1->ru_msgsnd - r0->ru_msgsnd);
197 		break;
198 
199 	    case 'k':		/* number of signals recieved */
200 		(void) fprintf(cshout, "%ld", r1->ru_nsignals-r0->ru_nsignals);
201 		break;
202 
203 	    case 'w':		/* num. voluntary context switches (waits) */
204 		(void) fprintf(cshout, "%ld", r1->ru_nvcsw - r0->ru_nvcsw);
205 		break;
206 
207 	    case 'c':		/* num. involuntary context switches */
208 		(void) fprintf(cshout, "%ld", r1->ru_nivcsw - r0->ru_nivcsw);
209 		break;
210 	    }
211     (void) fputc('\n', cshout);
212 }
213 
214 static void
215 pdeltat(t1, t0)
216     struct timeval *t1, *t0;
217 {
218     struct timeval td;
219 
220     tvsub(&td, t1, t0);
221     (void) fprintf(cshout, "%d.%01d", td.tv_sec, td.tv_usec / 100000);
222 }
223 
224 void
225 tvadd(tsum, t0)
226     struct timeval *tsum, *t0;
227 {
228 
229     tsum->tv_sec += t0->tv_sec;
230     tsum->tv_usec += t0->tv_usec;
231     if (tsum->tv_usec > 1000000)
232 	tsum->tv_sec++, tsum->tv_usec -= 1000000;
233 }
234 
235 void
236 tvsub(tdiff, t1, t0)
237     struct timeval *tdiff, *t1, *t0;
238 {
239 
240     tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
241     tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
242     if (tdiff->tv_usec < 0)
243 	tdiff->tv_sec--, tdiff->tv_usec += 1000000;
244 }
245 
246 #define  P2DIG(i) (void) fprintf(cshout, "%d%d", (i) / 10, (i) % 10)
247 
248 void
249 psecs(l)
250     long    l;
251 {
252     register int i;
253 
254     i = l / 3600;
255     if (i) {
256 	(void) fprintf(cshout, "%d:", i);
257 	i = l % 3600;
258 	P2DIG(i / 60);
259 	goto minsec;
260     }
261     i = l;
262     (void) fprintf(cshout, "%d", i / 60);
263 minsec:
264     i %= 60;
265     (void) fputc(':', cshout);
266     P2DIG(i);
267 }
268 
269 void
270 pcsecs(l)			/* PWP: print mm:ss.dd, l is in sec*100 */
271     long    l;
272 {
273     register int i;
274 
275     i = l / 360000;
276     if (i) {
277 	(void) fprintf(cshout, "%d:", i);
278 	i = (l % 360000) / 100;
279 	P2DIG(i / 60);
280 	goto minsec;
281     }
282     i = l / 100;
283     (void) fprintf(cshout, "%d", i / 60);
284 minsec:
285     i %= 60;
286     (void) fputc(':', cshout);
287     P2DIG(i);
288     (void) fputc('.', cshout);
289     P2DIG((int) (l % 100));
290 }
291