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 * 4. Neither the name of the University nor the names of its contributors 149b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 159b50d902SRodney W. Grimes * without specific prior written permission. 169b50d902SRodney W. Grimes * 179b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 189b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 199b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 209b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 219b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 229b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 239b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 249b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 259b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 269b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 279b50d902SRodney W. Grimes * SUCH DAMAGE. 289b50d902SRodney W. Grimes */ 299b50d902SRodney W. Grimes 309b50d902SRodney W. Grimes #ifndef lint 3180c486a4SPhilippe Charnier static const char copyright[] = 329b50d902SRodney W. Grimes "@(#) Copyright (c) 1987, 1988, 1993\n\ 339b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 349b50d902SRodney W. Grimes #endif /* not lint */ 359b50d902SRodney W. Grimes 369b50d902SRodney W. Grimes #ifndef lint 3780c486a4SPhilippe Charnier #if 0 389b50d902SRodney W. Grimes static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/6/93"; 3980c486a4SPhilippe Charnier #endif 4080c486a4SPhilippe Charnier static const char rcsid[] = 41c3aac50fSPeter Wemm "$FreeBSD$"; 429b50d902SRodney W. Grimes #endif /* not lint */ 439b50d902SRodney W. Grimes 449b50d902SRodney W. Grimes #include <sys/types.h> 459b50d902SRodney W. Grimes #include <sys/resource.h> 469b50d902SRodney W. Grimes #include <sys/signal.h> 47f0850246SJohn Polstra #include <sys/sysctl.h> 4869df5b5aSYaroslav Tykhiy #include <sys/time.h> 49bc2c47dfSJordan K. Hubbard #include <sys/wait.h> 50f0850246SJohn Polstra 51f0850246SJohn Polstra #include <err.h> 52844338c2SOllivier Robert #include <errno.h> 53e1fc0c16SAndrey A. Chernov #include <locale.h> 5469df5b5aSYaroslav Tykhiy #include <signal.h> 5569df5b5aSYaroslav Tykhiy #include <stdio.h> 5669df5b5aSYaroslav Tykhiy #include <stdlib.h> 5761d8eedeSDavid Malone #include <stdint.h> 58821df508SXin LI #include <string.h> 59fabfd133SDag-Erling Smørgrav #include <unistd.h> 609b50d902SRodney W. Grimes 613f330d7dSWarner Losh static int getstathz(void); 623f330d7dSWarner Losh static void humantime(FILE *, long, long); 63b6d7073dSPawel Jakub Dawidek static void showtime(FILE *, struct timeval *, struct timeval *, 64b6d7073dSPawel Jakub Dawidek struct rusage *); 65b6d7073dSPawel Jakub Dawidek static void siginfo(int); 663f330d7dSWarner Losh static void usage(void); 67f0850246SJohn Polstra 68e1fc0c16SAndrey A. Chernov static char decimal_point; 6961d8eedeSDavid Malone static struct timeval before_tv; 70b6d7073dSPawel Jakub Dawidek static int hflag, pflag; 71e1fc0c16SAndrey A. Chernov 7280c486a4SPhilippe Charnier int 73f4ac32deSDavid Malone main(int argc, char **argv) 749b50d902SRodney W. Grimes { 75b6d7073dSPawel Jakub Dawidek int aflag, ch, lflag, status; 7669df5b5aSYaroslav Tykhiy int exitonsig; 7769df5b5aSYaroslav Tykhiy pid_t pid; 7815309540SYaroslav Tykhiy struct rlimit rl; 799b50d902SRodney W. Grimes struct rusage ru; 80b6d7073dSPawel Jakub Dawidek struct timeval after; 81fabfd133SDag-Erling Smørgrav char *ofn = NULL; 8269df5b5aSYaroslav Tykhiy FILE *out = stderr; 839b50d902SRodney W. Grimes 84e1fc0c16SAndrey A. Chernov (void) setlocale(LC_NUMERIC, ""); 85e1fc0c16SAndrey A. Chernov decimal_point = localeconv()->decimal_point[0]; 86e1fc0c16SAndrey A. Chernov 87ea257bd5SDavid E. O'Brien aflag = hflag = lflag = pflag = 0; 88ea257bd5SDavid E. O'Brien while ((ch = getopt(argc, argv, "ahlo:p")) != -1) 899b50d902SRodney W. Grimes switch((char)ch) { 9003a22248SPoul-Henning Kamp case 'a': 91fabfd133SDag-Erling Smørgrav aflag = 1; 9203a22248SPoul-Henning Kamp break; 93ea257bd5SDavid E. O'Brien case 'h': 94ea257bd5SDavid E. O'Brien hflag = 1; 95ea257bd5SDavid E. O'Brien break; 969b50d902SRodney W. Grimes case 'l': 979b50d902SRodney W. Grimes lflag = 1; 989b50d902SRodney W. Grimes break; 999b81ca85SDag-Erling Smørgrav case 'o': 1009b81ca85SDag-Erling Smørgrav ofn = optarg; 1019b81ca85SDag-Erling Smørgrav break; 102844338c2SOllivier Robert case 'p': 103844338c2SOllivier Robert pflag = 1; 104844338c2SOllivier Robert break; 1059b50d902SRodney W. Grimes case '?': 1069b50d902SRodney W. Grimes default: 10780c486a4SPhilippe Charnier usage(); 1089b50d902SRodney W. Grimes } 1099b50d902SRodney W. Grimes 1109b50d902SRodney W. Grimes if (!(argc -= optind)) 1119b50d902SRodney W. Grimes exit(0); 1129b50d902SRodney W. Grimes argv += optind; 1139b50d902SRodney W. Grimes 114fabfd133SDag-Erling Smørgrav if (ofn) { 115*689f0bd9SJilles Tjoelker if ((out = fopen(ofn, aflag ? "ae" : "we")) == NULL) 1169b81ca85SDag-Erling Smørgrav err(1, "%s", ofn); 1179b81ca85SDag-Erling Smørgrav setvbuf(out, (char *)NULL, _IONBF, (size_t)0); 118fabfd133SDag-Erling Smørgrav } 11903a22248SPoul-Henning Kamp 120902d9eafSEd Schouten (void)gettimeofday(&before_tv, NULL); 1211fd98d7dSDag-Erling Smørgrav switch(pid = fork()) { 1229b50d902SRodney W. Grimes case -1: /* error */ 12380c486a4SPhilippe Charnier err(1, "time"); 1249b50d902SRodney W. Grimes /* NOTREACHED */ 1259b50d902SRodney W. Grimes case 0: /* child */ 1269b50d902SRodney W. Grimes execvp(*argv, argv); 127d6c762afSTim J. Robbins err(errno == ENOENT ? 127 : 126, "%s", *argv); 1289b50d902SRodney W. Grimes /* NOTREACHED */ 1299b50d902SRodney W. Grimes } 1309b50d902SRodney W. Grimes /* parent */ 1319b50d902SRodney W. Grimes (void)signal(SIGINT, SIG_IGN); 1329b50d902SRodney W. Grimes (void)signal(SIGQUIT, SIG_IGN); 133b6d7073dSPawel Jakub Dawidek (void)signal(SIGINFO, siginfo); 13477879b47SSean Chittenden while (wait4(pid, &status, 0, &ru) != pid); 135902d9eafSEd Schouten (void)gettimeofday(&after, NULL); 1369a4902a9SMartin Cracauer if ( ! WIFEXITED(status)) 13780c486a4SPhilippe Charnier warnx("command terminated abnormally"); 13869df5b5aSYaroslav Tykhiy exitonsig = WIFSIGNALED(status) ? WTERMSIG(status) : 0; 13961d8eedeSDavid Malone showtime(out, &before_tv, &after, &ru); 1409b50d902SRodney W. Grimes if (lflag) { 141f0850246SJohn Polstra int hz = getstathz(); 1429e5fd22bSPaul Traina u_long ticks; 1439b50d902SRodney W. Grimes 1449b50d902SRodney W. Grimes ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) + 1459b50d902SRodney W. Grimes hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000; 1469e5fd22bSPaul Traina 1479e5fd22bSPaul Traina /* 1489e5fd22bSPaul Traina * If our round-off on the tick calculation still puts us at 0, 1499e5fd22bSPaul Traina * then always assume at least one tick. 1509e5fd22bSPaul Traina */ 1519e5fd22bSPaul Traina if (ticks == 0) 1529e5fd22bSPaul Traina ticks = 1; 1539e5fd22bSPaul Traina 15403a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1559b50d902SRodney W. Grimes ru.ru_maxrss, "maximum resident set size"); 15603a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1579b50d902SRodney W. Grimes ru.ru_ixrss / ticks, "average shared memory size"); 15803a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1599b50d902SRodney W. Grimes ru.ru_idrss / ticks, "average unshared data size"); 16003a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1619b50d902SRodney W. Grimes ru.ru_isrss / ticks, "average unshared stack size"); 16203a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1639b50d902SRodney W. Grimes ru.ru_minflt, "page reclaims"); 16403a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1659b50d902SRodney W. Grimes ru.ru_majflt, "page faults"); 16603a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1679b50d902SRodney W. Grimes ru.ru_nswap, "swaps"); 16803a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1699b50d902SRodney W. Grimes ru.ru_inblock, "block input operations"); 17003a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1719b50d902SRodney W. Grimes ru.ru_oublock, "block output operations"); 17203a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1739b50d902SRodney W. Grimes ru.ru_msgsnd, "messages sent"); 17403a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1759b50d902SRodney W. Grimes ru.ru_msgrcv, "messages received"); 17603a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1779b50d902SRodney W. Grimes ru.ru_nsignals, "signals received"); 17803a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1799b50d902SRodney W. Grimes ru.ru_nvcsw, "voluntary context switches"); 18003a22248SPoul-Henning Kamp fprintf(out, "%10ld %s\n", 1819b50d902SRodney W. Grimes ru.ru_nivcsw, "involuntary context switches"); 1829b50d902SRodney W. Grimes } 18369df5b5aSYaroslav Tykhiy /* 18469df5b5aSYaroslav Tykhiy * If the child has exited on a signal, exit on the same 18569df5b5aSYaroslav Tykhiy * signal, too, in order to reproduce the child's exit status. 18669df5b5aSYaroslav Tykhiy * However, avoid actually dumping core from the current process. 18769df5b5aSYaroslav Tykhiy */ 1889a4902a9SMartin Cracauer if (exitonsig) { 1890050672aSDavid Malone if (signal(exitonsig, SIG_DFL) == SIG_ERR) 19069df5b5aSYaroslav Tykhiy warn("signal"); 19115309540SYaroslav Tykhiy else { 19215309540SYaroslav Tykhiy rl.rlim_max = rl.rlim_cur = 0; 19315309540SYaroslav Tykhiy if (setrlimit(RLIMIT_CORE, &rl) == -1) 19415309540SYaroslav Tykhiy warn("setrlimit"); 1959a4902a9SMartin Cracauer kill(getpid(), exitonsig); 1969a4902a9SMartin Cracauer } 19715309540SYaroslav Tykhiy } 198bc2c47dfSJordan K. Hubbard exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE); 1999b50d902SRodney W. Grimes } 200f0850246SJohn Polstra 20180c486a4SPhilippe Charnier static void 202f4ac32deSDavid Malone usage(void) 20380c486a4SPhilippe Charnier { 2043f6c6c91STim J. Robbins fprintf(stderr, 2053f6c6c91STim J. Robbins "usage: time [-al] [-h | -p] [-o file] utility [argument ...]\n"); 2069b81ca85SDag-Erling Smørgrav exit(1); 20780c486a4SPhilippe Charnier } 20880c486a4SPhilippe Charnier 209f0850246SJohn Polstra /* 210f0850246SJohn Polstra * Return the frequency of the kernel's statistics clock. 211f0850246SJohn Polstra */ 212f0850246SJohn Polstra static int 213f4ac32deSDavid Malone getstathz(void) 214f0850246SJohn Polstra { 215f0850246SJohn Polstra int mib[2]; 216f0850246SJohn Polstra size_t size; 21769df5b5aSYaroslav Tykhiy struct clockinfo clockrate; 218f0850246SJohn Polstra 219f0850246SJohn Polstra mib[0] = CTL_KERN; 220f0850246SJohn Polstra mib[1] = KERN_CLOCKRATE; 221f0850246SJohn Polstra size = sizeof clockrate; 222f0850246SJohn Polstra if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1) 223f0850246SJohn Polstra err(1, "sysctl kern.clockrate"); 224f0850246SJohn Polstra return clockrate.stathz; 225f0850246SJohn Polstra } 226ea257bd5SDavid E. O'Brien 227ea257bd5SDavid E. O'Brien static void 228f4ac32deSDavid Malone humantime(FILE *out, long sec, long usec) 229ea257bd5SDavid E. O'Brien { 230ea257bd5SDavid E. O'Brien long days, hrs, mins; 231ea257bd5SDavid E. O'Brien 232ea257bd5SDavid E. O'Brien days = sec / (60L * 60 * 24); 233ea257bd5SDavid E. O'Brien sec %= (60L * 60 * 24); 234ea257bd5SDavid E. O'Brien hrs = sec / (60L * 60); 235ea257bd5SDavid E. O'Brien sec %= (60L * 60); 236ea257bd5SDavid E. O'Brien mins = sec / 60; 237ea257bd5SDavid E. O'Brien sec %= 60; 238ea257bd5SDavid E. O'Brien 239ea257bd5SDavid E. O'Brien fprintf(out, "\t"); 240ea257bd5SDavid E. O'Brien if (days) 241ea257bd5SDavid E. O'Brien fprintf(out, "%ldd", days); 242ea257bd5SDavid E. O'Brien if (hrs) 243ea257bd5SDavid E. O'Brien fprintf(out, "%ldh", hrs); 244ea257bd5SDavid E. O'Brien if (mins) 245ea257bd5SDavid E. O'Brien fprintf(out, "%ldm", mins); 246e1fc0c16SAndrey A. Chernov fprintf(out, "%ld%c%02lds", sec, decimal_point, usec); 247ea257bd5SDavid E. O'Brien } 248b6d7073dSPawel Jakub Dawidek 249b6d7073dSPawel Jakub Dawidek static void 250b6d7073dSPawel Jakub Dawidek showtime(FILE *out, struct timeval *before, struct timeval *after, 251b6d7073dSPawel Jakub Dawidek struct rusage *ru) 252b6d7073dSPawel Jakub Dawidek { 253b6d7073dSPawel Jakub Dawidek 254b6d7073dSPawel Jakub Dawidek after->tv_sec -= before->tv_sec; 255b6d7073dSPawel Jakub Dawidek after->tv_usec -= before->tv_usec; 256b6d7073dSPawel Jakub Dawidek if (after->tv_usec < 0) 257b6d7073dSPawel Jakub Dawidek after->tv_sec--, after->tv_usec += 1000000; 258b6d7073dSPawel Jakub Dawidek 259b6d7073dSPawel Jakub Dawidek if (pflag) { 260b6d7073dSPawel Jakub Dawidek /* POSIX wants output that must look like 261b6d7073dSPawel Jakub Dawidek "real %f\nuser %f\nsys %f\n" and requires 262b6d7073dSPawel Jakub Dawidek at least two digits after the radix. */ 26361d8eedeSDavid Malone fprintf(out, "real %jd%c%02ld\n", 26461d8eedeSDavid Malone (intmax_t)after->tv_sec, decimal_point, 265b6d7073dSPawel Jakub Dawidek after->tv_usec/10000); 26661d8eedeSDavid Malone fprintf(out, "user %jd%c%02ld\n", 26761d8eedeSDavid Malone (intmax_t)ru->ru_utime.tv_sec, decimal_point, 268b6d7073dSPawel Jakub Dawidek ru->ru_utime.tv_usec/10000); 26961d8eedeSDavid Malone fprintf(out, "sys %jd%c%02ld\n", 27061d8eedeSDavid Malone (intmax_t)ru->ru_stime.tv_sec, decimal_point, 271b6d7073dSPawel Jakub Dawidek ru->ru_stime.tv_usec/10000); 272b6d7073dSPawel Jakub Dawidek } else if (hflag) { 273b6d7073dSPawel Jakub Dawidek humantime(out, after->tv_sec, after->tv_usec/10000); 274b6d7073dSPawel Jakub Dawidek fprintf(out, " real\t"); 275b6d7073dSPawel Jakub Dawidek humantime(out, ru->ru_utime.tv_sec, ru->ru_utime.tv_usec/10000); 276b6d7073dSPawel Jakub Dawidek fprintf(out, " user\t"); 277b6d7073dSPawel Jakub Dawidek humantime(out, ru->ru_stime.tv_sec, ru->ru_stime.tv_usec/10000); 278b6d7073dSPawel Jakub Dawidek fprintf(out, " sys\n"); 279b6d7073dSPawel Jakub Dawidek } else { 28061d8eedeSDavid Malone fprintf(out, "%9jd%c%02ld real ", 28161d8eedeSDavid Malone (intmax_t)after->tv_sec, decimal_point, 282b6d7073dSPawel Jakub Dawidek after->tv_usec/10000); 28361d8eedeSDavid Malone fprintf(out, "%9jd%c%02ld user ", 28461d8eedeSDavid Malone (intmax_t)ru->ru_utime.tv_sec, decimal_point, 285b6d7073dSPawel Jakub Dawidek ru->ru_utime.tv_usec/10000); 28661d8eedeSDavid Malone fprintf(out, "%9jd%c%02ld sys\n", 28761d8eedeSDavid Malone (intmax_t)ru->ru_stime.tv_sec, decimal_point, 288b6d7073dSPawel Jakub Dawidek ru->ru_stime.tv_usec/10000); 289b6d7073dSPawel Jakub Dawidek } 290b6d7073dSPawel Jakub Dawidek } 291b6d7073dSPawel Jakub Dawidek 292b6d7073dSPawel Jakub Dawidek static void 293b6d7073dSPawel Jakub Dawidek siginfo(int sig __unused) 294b6d7073dSPawel Jakub Dawidek { 295b6d7073dSPawel Jakub Dawidek struct timeval after; 296b6d7073dSPawel Jakub Dawidek struct rusage ru; 297b6d7073dSPawel Jakub Dawidek 298902d9eafSEd Schouten (void)gettimeofday(&after, NULL); 299b6d7073dSPawel Jakub Dawidek getrusage(RUSAGE_CHILDREN, &ru); 30061d8eedeSDavid Malone showtime(stdout, &before_tv, &after, &ru); 301b6d7073dSPawel Jakub Dawidek } 302