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