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