1 /*-
2 * Copyright (c) 1980, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 05/31/93";
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
settimes()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*/
dotime(v,t)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*/
donice(v,t)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
ruadd(ru,ru2)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
prusage(r0,r1,e,b)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
pdeltat(t1,t0)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
tvadd(tsum,t0)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
tvsub(tdiff,t1,t0)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
psecs(l)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
pcsecs(l)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