1 /* $NetBSD: time.c,v 1.9 1997/10/20 03:28:21 lukem Exp $ */
4 * Copyright (c) 1987, 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 #include <sys/cdefs.h>
44 #include <sys/types.h>
46 #include <sys/resource.h>
58 bool child_running
= true;
61 child_handler(int sig
)
63 child_running
= false;
67 main(int argc
, char **argv
)
70 int ch
, status
, rusage_ret
= -1;
71 uint64_t before_ns
, after_ns
, duration_ns
, duration_secs
, duration_frac_ns
;
73 struct rusage_info_v4 ruinfo
;
74 sigset_t sigmask
, suspmask
, origmask
;
77 while ((ch
= getopt(argc
, argv
, "lp")) != -1) {
87 fprintf(stderr
, "usage: time [-lp] <command>\n");
92 if (!(argc
-= optind
)) {
97 sigemptyset(&sigmask
);
99 * Block SIGCHLD so that the check for `child_running` doesn't miss the
100 * handler before calling `sigsuspend` and blocking forever.
102 sigaddset(&sigmask
, SIGCHLD
);
103 sigprocmask(SIG_BLOCK
, &sigmask
, &origmask
);
106 * Ensure child signals are handled by the parent prior to fork; otherwise,
107 * they could be missed between the child forking and calling `sigsuspend`.
109 (void)signal(SIGCHLD
, child_handler
);
111 sigemptyset(&suspmask
);
113 before_ns
= clock_gettime_nsec_np(CLOCK_UPTIME_RAW
);
115 * NB: Don't add anything between these two lines -- measurement is
118 switch (pid
= vfork()) {
120 err(EX_OSERR
, "time");
121 __builtin_unreachable();
124 * Allow the child to respond to signals by resetting to the original
125 * signal handling behavior.
127 (void)sigprocmask(SIG_SETMASK
, &origmask
, NULL
);
130 _exit((errno
== ENOENT
) ? 127 : 126);
131 __builtin_unreachable();
132 default: /* parent */
137 * Let the child handle signals that normally exit.
139 (void)signal(SIGINT
, SIG_IGN
);
140 (void)signal(SIGQUIT
, SIG_IGN
);
142 while (child_running
) {
144 * This would be racy, but SIGCHLD is blocked above (as part of
147 sigsuspend(&suspmask
);
150 * NB: Minimize what's added between these statements to preserve the
151 * accuracy of the time measurement.
153 after_ns
= clock_gettime_nsec_np(CLOCK_UPTIME_RAW
);
155 rusage_ret
= proc_pid_rusage(pid
, RUSAGE_INFO_V4
, (void **)&ruinfo
);
157 while (wait3(&status
, 0, &ru
) != pid
) {
159 if (!WIFEXITED(status
)) {
160 fprintf(stderr
, "Command terminated abnormally.\n");
162 duration_ns
= after_ns
- before_ns
;
163 duration_secs
= duration_ns
/ (1000 * 1000 * 1000);
164 duration_frac_ns
= duration_ns
- (duration_secs
* 1000 * 1000 * 1000);
169 setlocale(LC_ALL
, "");
171 radix
= nl_langinfo(RADIXCHAR
);
172 if (!radix
|| radix
[0] == '\0') {
176 fprintf(stderr
, "real %9" PRIu64
"%s%02" PRIu64
"\n",
177 duration_secs
, radix
, duration_frac_ns
/ (10 * 1000 * 1000));
178 fprintf(stderr
, "user %9ld%s%02ld\n",
179 (long)ru
.ru_utime
.tv_sec
, radix
, (long)ru
.ru_utime
.tv_usec
/10000);
180 fprintf(stderr
, "sys %9ld%s%02ld\n",
181 (long)ru
.ru_stime
.tv_sec
, radix
, (long)ru
.ru_stime
.tv_usec
/10000);
183 fprintf(stderr
, "%9" PRIu64
".%02" PRIu64
" real ",
184 duration_secs
, duration_frac_ns
/ (10 * 1000 * 1000));
185 fprintf(stderr
, "%9ld.%02ld user ",
186 (long)ru
.ru_utime
.tv_sec
, (long)ru
.ru_utime
.tv_usec
/10000);
187 fprintf(stderr
, "%9ld.%02ld sys\n",
188 (long)ru
.ru_stime
.tv_sec
, (long)ru
.ru_stime
.tv_usec
/10000);
192 int hz
= 100; /* XXX */
195 ticks
= hz
* (ru
.ru_utime
.tv_sec
+ ru
.ru_stime
.tv_sec
) +
196 hz
* (ru
.ru_utime
.tv_usec
+ ru
.ru_stime
.tv_usec
) / 1000000;
198 fprintf(stderr
, "%20ld %s\n",
199 ru
.ru_maxrss
, "maximum resident set size");
200 fprintf(stderr
, "%20ld %s\n", ticks
? ru
.ru_ixrss
/ ticks
: 0,
201 "average shared memory size");
202 fprintf(stderr
, "%20ld %s\n", ticks
? ru
.ru_idrss
/ ticks
: 0,
203 "average unshared data size");
204 fprintf(stderr
, "%20ld %s\n", ticks
? ru
.ru_isrss
/ ticks
: 0,
205 "average unshared stack size");
206 fprintf(stderr
, "%20ld %s\n",
207 ru
.ru_minflt
, "page reclaims");
208 fprintf(stderr
, "%20ld %s\n",
209 ru
.ru_majflt
, "page faults");
210 fprintf(stderr
, "%20ld %s\n",
211 ru
.ru_nswap
, "swaps");
212 fprintf(stderr
, "%20ld %s\n",
213 ru
.ru_inblock
, "block input operations");
214 fprintf(stderr
, "%20ld %s\n",
215 ru
.ru_oublock
, "block output operations");
216 fprintf(stderr
, "%20ld %s\n",
217 ru
.ru_msgsnd
, "messages sent");
218 fprintf(stderr
, "%20ld %s\n",
219 ru
.ru_msgrcv
, "messages received");
220 fprintf(stderr
, "%20ld %s\n",
221 ru
.ru_nsignals
, "signals received");
222 fprintf(stderr
, "%20ld %s\n",
223 ru
.ru_nvcsw
, "voluntary context switches");
224 fprintf(stderr
, "%20ld %s\n",
225 ru
.ru_nivcsw
, "involuntary context switches");
227 if (rusage_ret
>= 0) {
228 if (ruinfo
.ri_instructions
> 0) {
229 fprintf(stderr
, "%20" PRIu64
" %s\n", ruinfo
.ri_instructions
,
230 "instructions retired");
232 if (ruinfo
.ri_cycles
> 0) {
233 fprintf(stderr
, "%20" PRIu64
" %s\n", ruinfo
.ri_cycles
,
236 if (ruinfo
.ri_lifetime_max_phys_footprint
> 0) {
237 fprintf(stderr
, "%20" PRIu64
" %s\n",
238 ruinfo
.ri_lifetime_max_phys_footprint
,
239 "peak memory footprint");
244 exit(WIFEXITED(status
) ? WEXITSTATUS(status
) : EXIT_FAILURE
);