19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1987, 1988, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 3580c486a4SPhilippe Charnier static const char copyright[] = 369b50d902SRodney W. Grimes "@(#) Copyright (c) 1987, 1988, 1993\n\ 379b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 389b50d902SRodney W. Grimes #endif /* not lint */ 399b50d902SRodney W. Grimes 409b50d902SRodney W. Grimes #ifndef lint 4180c486a4SPhilippe Charnier #if 0 429b50d902SRodney W. Grimes static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/6/93"; 4380c486a4SPhilippe Charnier #endif 4480c486a4SPhilippe Charnier static const char rcsid[] = 45c3aac50fSPeter Wemm "$FreeBSD$"; 469b50d902SRodney W. Grimes #endif /* not lint */ 479b50d902SRodney W. Grimes 489b50d902SRodney W. Grimes #include <sys/types.h> 499b50d902SRodney W. Grimes #include <sys/resource.h> 509b50d902SRodney W. Grimes #include <sys/signal.h> 51f0850246SJohn Polstra #include <sys/sysctl.h> 5269df5b5aSYaroslav Tykhiy #include <sys/time.h> 53bc2c47dfSJordan K. Hubbard #include <sys/wait.h> 54f0850246SJohn Polstra 55f0850246SJohn Polstra #include <err.h> 56844338c2SOllivier Robert #include <errno.h> 57e1fc0c16SAndrey A. Chernov #include <locale.h> 5869df5b5aSYaroslav Tykhiy #include <signal.h> 5969df5b5aSYaroslav Tykhiy #include <stdio.h> 6069df5b5aSYaroslav Tykhiy #include <stdlib.h> 6103a22248SPoul-Henning Kamp #include <string.h> 62fabfd133SDag-Erling Smørgrav #include <unistd.h> 639b50d902SRodney W. Grimes 643f330d7dSWarner Losh static int getstathz(void); 653f330d7dSWarner Losh static void humantime(FILE *, long, long); 66b6d7073dSPawel Jakub Dawidek static void showtime(FILE *, struct timeval *, struct timeval *, 67b6d7073dSPawel Jakub Dawidek struct rusage *); 68b6d7073dSPawel Jakub Dawidek static void siginfo(int); 693f330d7dSWarner Losh static void usage(void); 70f0850246SJohn Polstra 71e1fc0c16SAndrey A. Chernov static char decimal_point; 72b6d7073dSPawel Jakub Dawidek static struct timeval before; 73b6d7073dSPawel Jakub Dawidek static int hflag, pflag; 74e1fc0c16SAndrey A. Chernov 7580c486a4SPhilippe Charnier int 76f4ac32deSDavid Malone main(int argc, char **argv) 779b50d902SRodney W. Grimes { 78b6d7073dSPawel Jakub Dawidek int aflag, ch, lflag, status; 7969df5b5aSYaroslav Tykhiy int exitonsig; 8069df5b5aSYaroslav Tykhiy pid_t pid; 8115309540SYaroslav Tykhiy struct rlimit rl; 829b50d902SRodney W. Grimes struct rusage ru; 83b6d7073dSPawel Jakub Dawidek struct timeval after; 84fabfd133SDag-Erling Smørgrav char *ofn = NULL; 8569df5b5aSYaroslav Tykhiy FILE *out = stderr; 869b50d902SRodney W. Grimes 87e1fc0c16SAndrey A. Chernov (void) setlocale(LC_NUMERIC, ""); 88e1fc0c16SAndrey A. Chernov decimal_point = localeconv()->decimal_point[0]; 89e1fc0c16SAndrey A. Chernov 90ea257bd5SDavid E. O'Brien aflag = hflag = lflag = pflag = 0; 91ea257bd5SDavid E. O'Brien while ((ch = getopt(argc, argv, "ahlo:p")) != -1) 929b50d902SRodney W. Grimes switch((char)ch) { 9303a22248SPoul-Henning Kamp case 'a': 94fabfd133SDag-Erling Smørgrav aflag = 1; 9503a22248SPoul-Henning Kamp break; 96ea257bd5SDavid E. O'Brien case 'h': 97ea257bd5SDavid E. O'Brien hflag = 1; 98ea257bd5SDavid E. O'Brien break; 999b50d902SRodney W. Grimes case 'l': 1009b50d902SRodney W. Grimes lflag = 1; 1019b50d902SRodney W. Grimes break; 1029b81ca85SDag-Erling Smørgrav case 'o': 1039b81ca85SDag-Erling Smørgrav ofn = optarg; 1049b81ca85SDag-Erling Smørgrav break; 105844338c2SOllivier Robert case 'p': 106844338c2SOllivier Robert pflag = 1; 107844338c2SOllivier Robert break; 1089b50d902SRodney W. Grimes case '?': 1099b50d902SRodney W. Grimes default: 11080c486a4SPhilippe Charnier usage(); 1119b50d902SRodney W. Grimes } 1129b50d902SRodney W. Grimes 1139b50d902SRodney W. Grimes if (!(argc -= optind)) 1149b50d902SRodney W. Grimes exit(0); 1159b50d902SRodney W. Grimes argv += optind; 1169b50d902SRodney W. Grimes 117fabfd133SDag-Erling Smørgrav if (ofn) { 118fabfd133SDag-Erling Smørgrav if ((out = fopen(ofn, aflag ? "a" : "w")) == NULL) 1199b81ca85SDag-Erling Smørgrav err(1, "%s", ofn); 1209b81ca85SDag-Erling Smørgrav setvbuf(out, (char *)NULL, _IONBF, (size_t)0); 121fabfd133SDag-Erling Smørgrav } 12203a22248SPoul-Henning Kamp 1239b50d902SRodney W. Grimes gettimeofday(&before, (struct timezone *)NULL); 1241fd98d7dSDag-Erling Smørgrav switch(pid = fork()) { 1259b50d902SRodney W. Grimes case -1: /* error */ 12680c486a4SPhilippe Charnier err(1, "time"); 1279b50d902SRodney W. Grimes /* NOTREACHED */ 1289b50d902SRodney W. Grimes case 0: /* child */ 129beb66b02SMaxim Konovalov if (ofn) 130beb66b02SMaxim Konovalov fclose(out); 1319b50d902SRodney W. Grimes execvp(*argv, argv); 132d6c762afSTim J. Robbins err(errno == ENOENT ? 127 : 126, "%s", *argv); 1339b50d902SRodney W. Grimes /* NOTREACHED */ 1349b50d902SRodney W. Grimes } 1359b50d902SRodney W. Grimes /* parent */ 1369b50d902SRodney W. Grimes (void)signal(SIGINT, SIG_IGN); 1379b50d902SRodney W. Grimes (void)signal(SIGQUIT, SIG_IGN); 138b6d7073dSPawel Jakub Dawidek (void)signal(SIGINFO, siginfo); 13977879b47SSean Chittenden while (wait4(pid, &status, 0, &ru) != pid); 1409b50d902SRodney W. Grimes gettimeofday(&after, (struct timezone *)NULL); 1419a4902a9SMartin Cracauer if ( ! WIFEXITED(status)) 14280c486a4SPhilippe Charnier warnx("command terminated abnormally"); 14369df5b5aSYaroslav Tykhiy exitonsig = WIFSIGNALED(status) ? WTERMSIG(status) : 0; 144b6d7073dSPawel Jakub Dawidek showtime(out, &before, &after, &ru); 1459b50d902SRodney W. Grimes if (lflag) { 146f0850246SJohn Polstra int hz = getstathz(); 1479e5fd22bSPaul Traina u_long ticks; 1489b50d902SRodney W. Grimes 1499b50d902SRodney W. Grimes ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) + 1509b50d902SRodney W. Grimes hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000; 1519e5fd22bSPaul Traina 1529e5fd22bSPaul Traina /* 1539e5fd22bSPaul Traina * If our round-off on the tick calculation still puts us at 0, 1549e5fd22bSPaul Traina * then always assume at least one tick. 1559e5fd22bSPaul Traina */ 1569e5fd22bSPaul Traina if (ticks == 0) 1579e5fd22bSPaul Traina ticks = 1; 1589e5fd22bSPaul Traina 15903a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1609b50d902SRodney W. Grimes ru.ru_maxrss, "maximum resident set size"); 16103a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1629b50d902SRodney W. Grimes ru.ru_ixrss / ticks, "average shared memory size"); 16303a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1649b50d902SRodney W. Grimes ru.ru_idrss / ticks, "average unshared data size"); 16503a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1669b50d902SRodney W. Grimes ru.ru_isrss / ticks, "average unshared stack size"); 16703a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1689b50d902SRodney W. Grimes ru.ru_minflt, "page reclaims"); 16903a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1709b50d902SRodney W. Grimes ru.ru_majflt, "page faults"); 17103a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1729b50d902SRodney W. Grimes ru.ru_nswap, "swaps"); 17303a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1749b50d902SRodney W. Grimes ru.ru_inblock, "block input operations"); 17503a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1769b50d902SRodney W. Grimes ru.ru_oublock, "block output operations"); 17703a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1789b50d902SRodney W. Grimes ru.ru_msgsnd, "messages sent"); 17903a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1809b50d902SRodney W. Grimes ru.ru_msgrcv, "messages received"); 18103a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1829b50d902SRodney W. Grimes ru.ru_nsignals, "signals received"); 18303a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1849b50d902SRodney W. Grimes ru.ru_nvcsw, "voluntary context switches"); 18503a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1869b50d902SRodney W. Grimes ru.ru_nivcsw, "involuntary context switches"); 1879b50d902SRodney W. Grimes } 18869df5b5aSYaroslav Tykhiy /* 18969df5b5aSYaroslav Tykhiy * If the child has exited on a signal, exit on the same 19069df5b5aSYaroslav Tykhiy * signal, too, in order to reproduce the child's exit status. 19169df5b5aSYaroslav Tykhiy * However, avoid actually dumping core from the current process. 19269df5b5aSYaroslav Tykhiy */ 1939a4902a9SMartin Cracauer if (exitonsig) { 1940050672aSDavid Malone if (signal(exitonsig, SIG_DFL) == SIG_ERR) 19569df5b5aSYaroslav Tykhiy warn("signal"); 19615309540SYaroslav Tykhiy else { 19715309540SYaroslav Tykhiy rl.rlim_max = rl.rlim_cur = 0; 19815309540SYaroslav Tykhiy if (setrlimit(RLIMIT_CORE, &rl) == -1) 19915309540SYaroslav Tykhiy warn("setrlimit"); 2009a4902a9SMartin Cracauer kill(getpid(), exitonsig); 2019a4902a9SMartin Cracauer } 20215309540SYaroslav Tykhiy } 203bc2c47dfSJordan K. Hubbard exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE); 2049b50d902SRodney W. Grimes } 205f0850246SJohn Polstra 20680c486a4SPhilippe Charnier static void 207f4ac32deSDavid Malone usage(void) 20880c486a4SPhilippe Charnier { 2093f6c6c91STim J. Robbins fprintf(stderr, 2103f6c6c91STim J. Robbins "usage: time [-al] [-h | -p] [-o file] utility [argument ...]\n"); 2119b81ca85SDag-Erling Smørgrav exit(1); 21280c486a4SPhilippe Charnier } 21380c486a4SPhilippe Charnier 214f0850246SJohn Polstra /* 215f0850246SJohn Polstra * Return the frequency of the kernel's statistics clock. 216f0850246SJohn Polstra */ 217f0850246SJohn Polstra static int 218f4ac32deSDavid Malone getstathz(void) 219f0850246SJohn Polstra { 220f0850246SJohn Polstra int mib[2]; 221f0850246SJohn Polstra size_t size; 22269df5b5aSYaroslav Tykhiy struct clockinfo clockrate; 223f0850246SJohn Polstra 224f0850246SJohn Polstra mib[0] = CTL_KERN; 225f0850246SJohn Polstra mib[1] = KERN_CLOCKRATE; 226f0850246SJohn Polstra size = sizeof clockrate; 227f0850246SJohn Polstra if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1) 228f0850246SJohn Polstra err(1, "sysctl kern.clockrate"); 229f0850246SJohn Polstra return clockrate.stathz; 230f0850246SJohn Polstra } 231ea257bd5SDavid E. O'Brien 232ea257bd5SDavid E. O'Brien static void 233f4ac32deSDavid Malone humantime(FILE *out, long sec, long usec) 234ea257bd5SDavid E. O'Brien { 235ea257bd5SDavid E. O'Brien long days, hrs, mins; 236ea257bd5SDavid E. O'Brien 237ea257bd5SDavid E. O'Brien days = sec / (60L * 60 * 24); 238ea257bd5SDavid E. O'Brien sec %= (60L * 60 * 24); 239ea257bd5SDavid E. O'Brien hrs = sec / (60L * 60); 240ea257bd5SDavid E. O'Brien sec %= (60L * 60); 241ea257bd5SDavid E. O'Brien mins = sec / 60; 242ea257bd5SDavid E. O'Brien sec %= 60; 243ea257bd5SDavid E. O'Brien 244ea257bd5SDavid E. O'Brien fprintf(out, "\t"); 245ea257bd5SDavid E. O'Brien if (days) 246ea257bd5SDavid E. O'Brien fprintf(out, "%ldd", days); 247ea257bd5SDavid E. O'Brien if (hrs) 248ea257bd5SDavid E. O'Brien fprintf(out, "%ldh", hrs); 249ea257bd5SDavid E. O'Brien if (mins) 250ea257bd5SDavid E. O'Brien fprintf(out, "%ldm", mins); 251e1fc0c16SAndrey A. Chernov fprintf(out, "%ld%c%02lds", sec, decimal_point, usec); 252ea257bd5SDavid E. O'Brien } 253b6d7073dSPawel Jakub Dawidek 254b6d7073dSPawel Jakub Dawidek static void 255b6d7073dSPawel Jakub Dawidek showtime(FILE *out, struct timeval *before, struct timeval *after, 256b6d7073dSPawel Jakub Dawidek struct rusage *ru) 257b6d7073dSPawel Jakub Dawidek { 258b6d7073dSPawel Jakub Dawidek 259b6d7073dSPawel Jakub Dawidek after->tv_sec -= before->tv_sec; 260b6d7073dSPawel Jakub Dawidek after->tv_usec -= before->tv_usec; 261b6d7073dSPawel Jakub Dawidek if (after->tv_usec < 0) 262b6d7073dSPawel Jakub Dawidek after->tv_sec--, after->tv_usec += 1000000; 263b6d7073dSPawel Jakub Dawidek 264b6d7073dSPawel Jakub Dawidek if (pflag) { 265b6d7073dSPawel Jakub Dawidek /* POSIX wants output that must look like 266b6d7073dSPawel Jakub Dawidek "real %f\nuser %f\nsys %f\n" and requires 267b6d7073dSPawel Jakub Dawidek at least two digits after the radix. */ 268b6d7073dSPawel Jakub Dawidek fprintf(out, "real %ld%c%02ld\n", 269b6d7073dSPawel Jakub Dawidek after->tv_sec, decimal_point, 270b6d7073dSPawel Jakub Dawidek after->tv_usec/10000); 271b6d7073dSPawel Jakub Dawidek fprintf(out, "user %ld%c%02ld\n", 272b6d7073dSPawel Jakub Dawidek ru->ru_utime.tv_sec, decimal_point, 273b6d7073dSPawel Jakub Dawidek ru->ru_utime.tv_usec/10000); 274b6d7073dSPawel Jakub Dawidek fprintf(out, "sys %ld%c%02ld\n", 275b6d7073dSPawel Jakub Dawidek ru->ru_stime.tv_sec, decimal_point, 276b6d7073dSPawel Jakub Dawidek ru->ru_stime.tv_usec/10000); 277b6d7073dSPawel Jakub Dawidek } else if (hflag) { 278b6d7073dSPawel Jakub Dawidek humantime(out, after->tv_sec, after->tv_usec/10000); 279b6d7073dSPawel Jakub Dawidek fprintf(out, " real\t"); 280b6d7073dSPawel Jakub Dawidek humantime(out, ru->ru_utime.tv_sec, ru->ru_utime.tv_usec/10000); 281b6d7073dSPawel Jakub Dawidek fprintf(out, " user\t"); 282b6d7073dSPawel Jakub Dawidek humantime(out, ru->ru_stime.tv_sec, ru->ru_stime.tv_usec/10000); 283b6d7073dSPawel Jakub Dawidek fprintf(out, " sys\n"); 284b6d7073dSPawel Jakub Dawidek } else { 285b6d7073dSPawel Jakub Dawidek fprintf(out, "%9ld%c%02ld real ", 286b6d7073dSPawel Jakub Dawidek after->tv_sec, decimal_point, 287b6d7073dSPawel Jakub Dawidek after->tv_usec/10000); 288b6d7073dSPawel Jakub Dawidek fprintf(out, "%9ld%c%02ld user ", 289b6d7073dSPawel Jakub Dawidek ru->ru_utime.tv_sec, decimal_point, 290b6d7073dSPawel Jakub Dawidek ru->ru_utime.tv_usec/10000); 291b6d7073dSPawel Jakub Dawidek fprintf(out, "%9ld%c%02ld sys\n", 292b6d7073dSPawel Jakub Dawidek ru->ru_stime.tv_sec, decimal_point, 293b6d7073dSPawel Jakub Dawidek ru->ru_stime.tv_usec/10000); 294b6d7073dSPawel Jakub Dawidek } 295b6d7073dSPawel Jakub Dawidek } 296b6d7073dSPawel Jakub Dawidek 297b6d7073dSPawel Jakub Dawidek static void 298b6d7073dSPawel Jakub Dawidek siginfo(int sig __unused) 299b6d7073dSPawel Jakub Dawidek { 300b6d7073dSPawel Jakub Dawidek struct timeval after; 301b6d7073dSPawel Jakub Dawidek struct rusage ru; 302b6d7073dSPawel Jakub Dawidek 303b6d7073dSPawel Jakub Dawidek gettimeofday(&after, (struct timezone *)NULL); 304b6d7073dSPawel Jakub Dawidek getrusage(RUSAGE_CHILDREN, &ru); 305b6d7073dSPawel Jakub Dawidek showtime(stdout, &before, &after, &ru); 306b6d7073dSPawel Jakub Dawidek } 307