17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*509bee73SRafael Vanoni Polanczyk * Common Development and Distribution License (the "License"). 6*509bee73SRafael Vanoni Polanczyk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*509bee73SRafael Vanoni Polanczyk * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*509bee73SRafael Vanoni Polanczyk * 25*509bee73SRafael Vanoni Polanczyk * Portions Copyright 2008 Chad Mynhier 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <unistd.h> 317c478bd9Sstevel@tonic-gate #include <fcntl.h> 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 347c478bd9Sstevel@tonic-gate #include <math.h> 357c478bd9Sstevel@tonic-gate #include <wait.h> 367c478bd9Sstevel@tonic-gate #include <signal.h> 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/time.h> 397c478bd9Sstevel@tonic-gate #include <signal.h> 407c478bd9Sstevel@tonic-gate #include <libproc.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate static int look(pid_t); 437c478bd9Sstevel@tonic-gate static void hr_min_sec(char *, long); 447c478bd9Sstevel@tonic-gate static void prtime(char *, timestruc_t *); 457c478bd9Sstevel@tonic-gate static int perr(const char *); 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static void tsadd(timestruc_t *result, timestruc_t *a, timestruc_t *b); 487c478bd9Sstevel@tonic-gate static void tssub(timestruc_t *result, timestruc_t *a, timestruc_t *b); 49*509bee73SRafael Vanoni Polanczyk static void hrt2ts(hrtime_t hrt, timestruc_t *tsp); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate static char *command; 52*509bee73SRafael Vanoni Polanczyk static char *pidarg; 537c478bd9Sstevel@tonic-gate static char procname[64]; 547c478bd9Sstevel@tonic-gate 55*509bee73SRafael Vanoni Polanczyk static int Fflag; 56*509bee73SRafael Vanoni Polanczyk static int mflag; 57*509bee73SRafael Vanoni Polanczyk static int errflg; 58*509bee73SRafael Vanoni Polanczyk 597c478bd9Sstevel@tonic-gate int 607c478bd9Sstevel@tonic-gate main(int argc, char **argv) 617c478bd9Sstevel@tonic-gate { 62*509bee73SRafael Vanoni Polanczyk int opt; 637c478bd9Sstevel@tonic-gate pid_t pid; 647c478bd9Sstevel@tonic-gate struct siginfo info; 657c478bd9Sstevel@tonic-gate int status; 66*509bee73SRafael Vanoni Polanczyk int gret; 67*509bee73SRafael Vanoni Polanczyk struct ps_prochandle *Pr; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 707c478bd9Sstevel@tonic-gate command++; 717c478bd9Sstevel@tonic-gate else 727c478bd9Sstevel@tonic-gate command = argv[0]; 737c478bd9Sstevel@tonic-gate 74*509bee73SRafael Vanoni Polanczyk while ((opt = getopt(argc, argv, "Fhmp:")) != EOF) { 75*509bee73SRafael Vanoni Polanczyk switch (opt) { 76*509bee73SRafael Vanoni Polanczyk case 'F': /* force grabbing (no O_EXCL) */ 77*509bee73SRafael Vanoni Polanczyk Fflag = PGRAB_FORCE; 78*509bee73SRafael Vanoni Polanczyk break; 79*509bee73SRafael Vanoni Polanczyk case 'm': /* microstate accounting */ 80*509bee73SRafael Vanoni Polanczyk mflag = 1; 81*509bee73SRafael Vanoni Polanczyk break; 82*509bee73SRafael Vanoni Polanczyk case 'p': 83*509bee73SRafael Vanoni Polanczyk pidarg = optarg; 84*509bee73SRafael Vanoni Polanczyk break; 85*509bee73SRafael Vanoni Polanczyk default: 86*509bee73SRafael Vanoni Polanczyk errflg = 1; 87*509bee73SRafael Vanoni Polanczyk break; 88*509bee73SRafael Vanoni Polanczyk } 89*509bee73SRafael Vanoni Polanczyk } 90*509bee73SRafael Vanoni Polanczyk 91*509bee73SRafael Vanoni Polanczyk argc -= optind; 92*509bee73SRafael Vanoni Polanczyk argv += optind; 93*509bee73SRafael Vanoni Polanczyk 94*509bee73SRafael Vanoni Polanczyk if (((pidarg != NULL) ^ (argc < 1)) || errflg) { 957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 96*509bee73SRafael Vanoni Polanczyk "usage:\t%s [-mh] [-p pid | command [ args ... ]]\n", 97*509bee73SRafael Vanoni Polanczyk command); 987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 997c478bd9Sstevel@tonic-gate " (time a command using microstate accounting)\n"); 1007c478bd9Sstevel@tonic-gate return (1); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 103*509bee73SRafael Vanoni Polanczyk if (pidarg != NULL) { 104*509bee73SRafael Vanoni Polanczyk if ((Pr = proc_arg_grab(pidarg, PR_ARG_PIDS, 105*509bee73SRafael Vanoni Polanczyk Fflag | PGRAB_RDONLY, &gret)) == NULL) { 106*509bee73SRafael Vanoni Polanczyk (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 107*509bee73SRafael Vanoni Polanczyk command, pidarg, Pgrab_error(gret)); 108*509bee73SRafael Vanoni Polanczyk return (1); 109*509bee73SRafael Vanoni Polanczyk } 110*509bee73SRafael Vanoni Polanczyk } else { 111*509bee73SRafael Vanoni Polanczyk if ((Pr = Pcreate(argv[0], &argv[0], &gret, NULL, 0)) == NULL) { 1127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: failed to exec %s: %s\n", 113*509bee73SRafael Vanoni Polanczyk command, argv[0], Pcreate_error(gret)); 114*509bee73SRafael Vanoni Polanczyk return (1); 115*509bee73SRafael Vanoni Polanczyk } 116*509bee73SRafael Vanoni Polanczyk if (Psetrun(Pr, 0, 0) == -1) { 117*509bee73SRafael Vanoni Polanczyk (void) fprintf(stderr, "%s: failed to set running %s: " 118*509bee73SRafael Vanoni Polanczyk "%s\n", command, argv[0], strerror(errno)); 119*509bee73SRafael Vanoni Polanczyk return (1); 120*509bee73SRafael Vanoni Polanczyk } 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 123*509bee73SRafael Vanoni Polanczyk pid = Pstatus(Pr)->pr_pid; 1247c478bd9Sstevel@tonic-gate (void) sprintf(procname, "%d", (int)pid); /* for perr() */ 1257c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 1267c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 127*509bee73SRafael Vanoni Polanczyk 128*509bee73SRafael Vanoni Polanczyk if (pidarg == NULL) 1297c478bd9Sstevel@tonic-gate (void) waitid(P_PID, pid, &info, WEXITED | WNOWAIT); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate (void) look(pid); 1327c478bd9Sstevel@tonic-gate 133*509bee73SRafael Vanoni Polanczyk if (pidarg != NULL) { 134*509bee73SRafael Vanoni Polanczyk Prelease(Pr, 0); 135*509bee73SRafael Vanoni Polanczyk return (0); 136*509bee73SRafael Vanoni Polanczyk } else { 1377c478bd9Sstevel@tonic-gate (void) waitpid(pid, &status, 0); 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate if (WIFEXITED(status)) 1407c478bd9Sstevel@tonic-gate return (WEXITSTATUS(status)); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (WIFSIGNALED(status)) { 1437c478bd9Sstevel@tonic-gate int sig = WTERMSIG(status); 1447c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX]; 1457c478bd9Sstevel@tonic-gate 146*509bee73SRafael Vanoni Polanczyk (void) fprintf(stderr, "%s: command terminated " 147*509bee73SRafael Vanoni Polanczyk "abnormally by %s\n", command, 148*509bee73SRafael Vanoni Polanczyk proc_signame(sig, name, sizeof (name))); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate return (status | WCOREFLG); /* see time(1) */ 1527c478bd9Sstevel@tonic-gate } 153*509bee73SRafael Vanoni Polanczyk } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate static int 1567c478bd9Sstevel@tonic-gate look(pid_t pid) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate char pathname[100]; 1597c478bd9Sstevel@tonic-gate int rval = 0; 1607c478bd9Sstevel@tonic-gate int fd; 1617c478bd9Sstevel@tonic-gate psinfo_t psinfo; 1627c478bd9Sstevel@tonic-gate prusage_t prusage; 1637c478bd9Sstevel@tonic-gate timestruc_t real, user, sys; 164*509bee73SRafael Vanoni Polanczyk hrtime_t hrtime; 1657c478bd9Sstevel@tonic-gate prusage_t *pup = &prusage; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate if (proc_get_psinfo(pid, &psinfo) < 0) 1687c478bd9Sstevel@tonic-gate return (perr("read psinfo")); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate (void) sprintf(pathname, "/proc/%d/usage", (int)pid); 1717c478bd9Sstevel@tonic-gate if ((fd = open(pathname, O_RDONLY)) < 0) 1727c478bd9Sstevel@tonic-gate return (perr("open usage")); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (read(fd, &prusage, sizeof (prusage)) != sizeof (prusage)) 1757c478bd9Sstevel@tonic-gate rval = perr("read usage"); 1767c478bd9Sstevel@tonic-gate else { 177*509bee73SRafael Vanoni Polanczyk if (pidarg) { 178*509bee73SRafael Vanoni Polanczyk hrtime = gethrtime(); 179*509bee73SRafael Vanoni Polanczyk hrt2ts(hrtime, &real); 180*509bee73SRafael Vanoni Polanczyk } else { 1817c478bd9Sstevel@tonic-gate real = pup->pr_term; 182*509bee73SRafael Vanoni Polanczyk } 1837c478bd9Sstevel@tonic-gate tssub(&real, &real, &pup->pr_create); 1847c478bd9Sstevel@tonic-gate user = pup->pr_utime; 1857c478bd9Sstevel@tonic-gate sys = pup->pr_stime; 186*509bee73SRafael Vanoni Polanczyk if (!mflag) 1877c478bd9Sstevel@tonic-gate tsadd(&sys, &sys, &pup->pr_ttime); 188*509bee73SRafael Vanoni Polanczyk 1897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 1907c478bd9Sstevel@tonic-gate prtime("real", &real); 1917c478bd9Sstevel@tonic-gate prtime("user", &user); 1927c478bd9Sstevel@tonic-gate prtime("sys", &sys); 193*509bee73SRafael Vanoni Polanczyk 194*509bee73SRafael Vanoni Polanczyk if (mflag) { 195*509bee73SRafael Vanoni Polanczyk prtime("trap", &pup->pr_ttime); 196*509bee73SRafael Vanoni Polanczyk prtime("tflt", &pup->pr_tftime); 197*509bee73SRafael Vanoni Polanczyk prtime("dflt", &pup->pr_dftime); 198*509bee73SRafael Vanoni Polanczyk prtime("kflt", &pup->pr_kftime); 199*509bee73SRafael Vanoni Polanczyk prtime("lock", &pup->pr_ltime); 200*509bee73SRafael Vanoni Polanczyk prtime("slp", &pup->pr_slptime); 201*509bee73SRafael Vanoni Polanczyk prtime("lat", &pup->pr_wtime); 202*509bee73SRafael Vanoni Polanczyk prtime("stop", &pup->pr_stoptime); 203*509bee73SRafael Vanoni Polanczyk } 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate (void) close(fd); 2077c478bd9Sstevel@tonic-gate return (rval); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate static void 2117c478bd9Sstevel@tonic-gate hr_min_sec(char *buf, long sec) 2127c478bd9Sstevel@tonic-gate { 2137c478bd9Sstevel@tonic-gate if (sec >= 3600) 2147c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%ld:%.2ld:%.2ld", 2157c478bd9Sstevel@tonic-gate sec / 3600, (sec % 3600) / 60, sec % 60); 2167c478bd9Sstevel@tonic-gate else if (sec >= 60) 2177c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%ld:%.2ld", 2187c478bd9Sstevel@tonic-gate sec / 60, sec % 60); 2197c478bd9Sstevel@tonic-gate else 2207c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%ld", sec); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate static void 2247c478bd9Sstevel@tonic-gate prtime(char *name, timestruc_t *ts) 2257c478bd9Sstevel@tonic-gate { 2267c478bd9Sstevel@tonic-gate char buf[32]; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate hr_min_sec(buf, ts->tv_sec); 229*509bee73SRafael Vanoni Polanczyk 230*509bee73SRafael Vanoni Polanczyk (void) fprintf(stderr, "%-4s %8s.%.9u\n", 231*509bee73SRafael Vanoni Polanczyk name, buf, (uint_t)ts->tv_nsec); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate static int 2357c478bd9Sstevel@tonic-gate perr(const char *s) 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate if (s) 2387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 2397c478bd9Sstevel@tonic-gate else 2407c478bd9Sstevel@tonic-gate s = procname; 2417c478bd9Sstevel@tonic-gate perror(s); 2427c478bd9Sstevel@tonic-gate return (1); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate static void 2467c478bd9Sstevel@tonic-gate tsadd(timestruc_t *result, timestruc_t *a, timestruc_t *b) 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate result->tv_sec = a->tv_sec + b->tv_sec; 2497c478bd9Sstevel@tonic-gate if ((result->tv_nsec = a->tv_nsec + b->tv_nsec) >= 1000000000) { 2507c478bd9Sstevel@tonic-gate result->tv_nsec -= 1000000000; 2517c478bd9Sstevel@tonic-gate result->tv_sec += 1; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate static void 2567c478bd9Sstevel@tonic-gate tssub(timestruc_t *result, timestruc_t *a, timestruc_t *b) 2577c478bd9Sstevel@tonic-gate { 2587c478bd9Sstevel@tonic-gate result->tv_sec = a->tv_sec - b->tv_sec; 2597c478bd9Sstevel@tonic-gate if ((result->tv_nsec = a->tv_nsec - b->tv_nsec) < 0) { 2607c478bd9Sstevel@tonic-gate result->tv_nsec += 1000000000; 2617c478bd9Sstevel@tonic-gate result->tv_sec -= 1; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate } 264*509bee73SRafael Vanoni Polanczyk 265*509bee73SRafael Vanoni Polanczyk static void 266*509bee73SRafael Vanoni Polanczyk hrt2ts(hrtime_t hrt, timestruc_t *tsp) 267*509bee73SRafael Vanoni Polanczyk { 268*509bee73SRafael Vanoni Polanczyk tsp->tv_sec = hrt / NANOSEC; 269*509bee73SRafael Vanoni Polanczyk tsp->tv_nsec = hrt % NANOSEC; 270*509bee73SRafael Vanoni Polanczyk } 271