4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Portions Copyright 2008 Chad Mynhier
28 * Copyright 2016 Joyent, Inc.
40 #include <sys/types.h>
45 static int look(pid_t
);
46 static void hr_min_sec(char *, long);
47 static void prtime(char *, timestruc_t
*);
48 static int perr(const char *);
50 static void tsadd(timestruc_t
*result
, timestruc_t
*a
, timestruc_t
*b
);
51 static void tssub(timestruc_t
*result
, timestruc_t
*a
, timestruc_t
*b
);
52 static void hrt2ts(hrtime_t hrt
, timestruc_t
*tsp
);
56 static char procname
[64];
65 ptime_pid(const char *pidstr
)
67 struct ps_prochandle
*Pr
;
71 if ((Pr
= proc_arg_grab(pidstr
, PR_ARG_PIDS
,
72 Fflag
| PGRAB_RDONLY
, &gret
)) == NULL
) {
73 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
74 command
, pidstr
, Pgrab_error(gret
));
78 pid
= Pstatus(Pr
)->pr_pid
;
79 (void) sprintf(procname
, "%d", (int)pid
); /* for perr() */
86 main(int argc
, char **argv
)
93 struct ps_prochandle
*Pr
;
95 if ((command
= strrchr(argv
[0], '/')) != NULL
)
100 while ((opt
= getopt(argc
, argv
, "Fhmp:")) != EOF
) {
102 case 'F': /* force grabbing (no O_EXCL) */
105 case 'm': /* microstate accounting */
121 if (((pidarg
!= NULL
) ^ (argc
< 1)) || errflg
) {
122 (void) fprintf(stderr
,
123 "usage:\t%s [-mh] [-p pidlist | command [ args ... ]]\n",
125 (void) fprintf(stderr
,
126 " (time a command using microstate accounting)\n");
134 (void) signal(SIGINT
, SIG_IGN
);
135 (void) signal(SIGQUIT
, SIG_IGN
);
137 pp
= strtok(pidarg
, ", ");
139 (void) fprintf(stderr
, "%s: invalid argument for -p\n",
143 exit
= ptime_pid(pp
);
144 while ((pp
= strtok(NULL
, ", ")) != NULL
) {
145 exit
|= ptime_pid(pp
);
151 if ((Pr
= Pcreate(argv
[0], &argv
[0], &gret
, NULL
, 0)) == NULL
) {
152 (void) fprintf(stderr
, "%s: failed to exec %s: %s\n",
153 command
, argv
[0], Pcreate_error(gret
));
156 if (Psetrun(Pr
, 0, 0) == -1) {
157 (void) fprintf(stderr
, "%s: failed to set running %s: "
158 "%s\n", command
, argv
[0], strerror(errno
));
162 pid
= Pstatus(Pr
)->pr_pid
;
164 (void) sprintf(procname
, "%d", (int)pid
); /* for perr() */
165 (void) signal(SIGINT
, SIG_IGN
);
166 (void) signal(SIGQUIT
, SIG_IGN
);
168 (void) waitid(P_PID
, pid
, &info
, WEXITED
| WNOWAIT
);
172 (void) waitpid(pid
, &status
, 0);
174 if (WIFEXITED(status
))
175 return (WEXITSTATUS(status
));
177 if (WIFSIGNALED(status
)) {
178 int sig
= WTERMSIG(status
);
179 char name
[SIG2STR_MAX
];
181 (void) fprintf(stderr
, "%s: command terminated "
182 "abnormally by %s\n", command
,
183 proc_signame(sig
, name
, sizeof (name
)));
186 return (status
| WCOREFLG
); /* see time(1) */
197 timestruc_t real
, user
, sys
;
199 prusage_t
*pup
= &prusage
;
203 if (proc_get_psinfo(pid
, &psinfo
) < 0)
204 return (perr("read psinfo"));
206 (void) sprintf(pathname
, "/proc/%d/usage", (int)pid
);
207 if ((fd
= open(pathname
, O_RDONLY
)) < 0)
208 return (perr("open usage"));
210 if (read(fd
, &prusage
, sizeof (prusage
)) != sizeof (prusage
))
211 rval
= perr("read usage");
214 hrtime
= gethrtime();
215 hrt2ts(hrtime
, &real
);
219 tssub(&real
, &real
, &pup
->pr_create
);
220 user
= pup
->pr_utime
;
223 tsadd(&sys
, &sys
, &pup
->pr_ttime
);
225 if (!pflag
|| pfirst
> 1)
226 (void) fprintf(stderr
, "\n");
228 (void) fprintf(stderr
, "%d:\t%.70s\n",
229 (int)psinfo
.pr_pid
, psinfo
.pr_psargs
);
230 prtime("real", &real
);
231 prtime("user", &user
);
235 prtime("trap", &pup
->pr_ttime
);
236 prtime("tflt", &pup
->pr_tftime
);
237 prtime("dflt", &pup
->pr_dftime
);
238 prtime("kflt", &pup
->pr_kftime
);
239 prtime("lock", &pup
->pr_ltime
);
240 prtime("slp", &pup
->pr_slptime
);
241 prtime("lat", &pup
->pr_wtime
);
242 prtime("stop", &pup
->pr_stoptime
);
251 hr_min_sec(char *buf
, long sec
)
254 (void) sprintf(buf
, "%ld:%.2ld:%.2ld",
255 sec
/ 3600, (sec
% 3600) / 60, sec
% 60);
257 (void) sprintf(buf
, "%ld:%.2ld",
260 (void) sprintf(buf
, "%ld", sec
);
264 prtime(char *name
, timestruc_t
*ts
)
268 hr_min_sec(buf
, ts
->tv_sec
);
270 (void) fprintf(stderr
, "%-4s %8s.%.9u\n",
271 name
, buf
, (uint_t
)ts
->tv_nsec
);
278 (void) fprintf(stderr
, "%s: ", procname
);
286 tsadd(timestruc_t
*result
, timestruc_t
*a
, timestruc_t
*b
)
288 result
->tv_sec
= a
->tv_sec
+ b
->tv_sec
;
289 if ((result
->tv_nsec
= a
->tv_nsec
+ b
->tv_nsec
) >= 1000000000) {
290 result
->tv_nsec
-= 1000000000;
296 tssub(timestruc_t
*result
, timestruc_t
*a
, timestruc_t
*b
)
298 result
->tv_sec
= a
->tv_sec
- b
->tv_sec
;
299 if ((result
->tv_nsec
= a
->tv_nsec
- b
->tv_nsec
) < 0) {
300 result
->tv_nsec
+= 1000000000;
306 hrt2ts(hrtime_t hrt
, timestruc_t
*tsp
)
308 tsp
->tv_sec
= hrt
/ NANOSEC
;
309 tsp
->tv_nsec
= hrt
% NANOSEC
;