]> git.saurik.com Git - apple/shell_cmds.git/blame_incremental - systime/systime.c
shell_cmds-198.tar.gz
[apple/shell_cmds.git] / systime / systime.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <mach/mach.h>
25#include <err.h>
26#include <errno.h>
27#include <stdbool.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <libproc.h>
33#include <mach/mach_time.h>
34
35static void usage(void);
36static void do_print(void);
37static void do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle);
38static void do_piddifftime(bool userpercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time);
39static kern_return_t get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle);
40static kern_return_t get_processor_count(int *ncpu);
41static mach_timebase_info_data_t timebase_info;
42
43int
44main(int argc, char *argv[])
45{
46 int ch;
47 const char *optu = NULL;
48 const char *opts = NULL;
49 const char *opti = NULL;
50 const char *tpid = NULL;
51 const char *opt_sleep_time = NULL;
52 int sleep_time = 1;
53 int target_pid;
54 bool systemwide_time = false;
55 int pid;
56 int status;
57 uint64_t olduser, oldsystem, oldidle;
58 uint64_t old_pid_time;
59 uint64_t old_pid_user, old_pid_system;
60 kern_return_t kret;
61 bool usepercent = false;
62 bool recurring = false;
63
64 while ((ch = getopt(argc, argv, "PrT:t:pu:s:i:")) != -1) {
65 switch (ch) {
66 case 'P':
67 usepercent = true;
68 break;
69 case 'r':
70 recurring = true;
71 break;
72 case 't':
73 opt_sleep_time = optarg;
74 break;
75 case 'T':
76 tpid = optarg;
77 break;
78 case 'p':
79 systemwide_time = true;
80 break;
81 case 'u':
82 optu = optarg;
83 break;
84 case 's':
85 opts = optarg;
86 break;
87 case 'i':
88 opti = optarg;
89 break;
90 case '?':
91 default:
92 usage();
93 }
94 }
95
96 mach_timebase_info(&timebase_info);
97
98 if (opt_sleep_time) {
99 char *endstr;
100 sleep_time = (int)strtoul(opt_sleep_time, &endstr, 0);
101 if (opt_sleep_time[0] == '\0' || endstr[0] != '\0')
102 usage();
103 }
104
105 if (systemwide_time) {
106 bool first_pass = true;
107 olduser = oldsystem = oldidle = 0;
108
109 if (recurring != true) {
110 do_print();
111 exit(0);
112 }
113 do {
114 if (first_pass) {
115 do_difftime(false, &olduser, &oldsystem, &oldidle);
116 first_pass = false;
117 } else {
118 do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
119 }
120 sleep(sleep_time);
121 } while (recurring);
122
123 exit(0);
124 }
125
126
127 if (tpid) {
128 char *endstr;
129 bool first_pass = true;
130
131 target_pid = (int)strtoul(tpid, &endstr, 0);
132 if (tpid[0] == '\0' || endstr[0] != '\0')
133 usage();
134
135 olduser = oldsystem = oldidle = 0;
136 old_pid_user = old_pid_system = old_pid_time = 0;
137
138 do {
139 if (first_pass) {
140 do_difftime(false, &olduser, &oldsystem, &oldidle);
141 do_piddifftime(false, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
142 first_pass = false;
143 } else {
144 do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
145 do_piddifftime(usepercent, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
146 }
147
148 sleep(sleep_time);
149 } while (recurring);
150 exit(0);
151 }
152
153 if (optu || opts || opti) {
154 char *endstr;
155
156 if (!optu)
157 usage();
158 olduser = strtoull(optu, &endstr, 0);
159 if (optu[0] == '\0' || endstr[0] != '\0')
160 usage();
161
162 if (!opts)
163 usage();
164 oldsystem = strtoull(opts, &endstr, 0);
165 if (opts[0] == '\0' || endstr[0] != '\0')
166 usage();
167
168 if (!opti)
169 usage();
170 oldidle = strtoull(opti, &endstr, 0);
171 if (opti[0] == '\0' || endstr[0] != '\0')
172 usage();
173
174 do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
175 exit(0);
176 }
177
178 argc -= optind;
179 argv += optind;
180
181 if (argc == 0)
182 usage();
183
184 do {
185 kret = get_processor_time(&olduser, &oldsystem, &oldidle);
186 if (kret)
187 errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
188
189 switch(pid = vfork()) {
190 case -1: /* error */
191 perror("time");
192 exit(1);
193 /* NOTREACHED */
194 case 0: /* child */
195 execvp(*argv, argv);
196 perror(*argv);
197 _exit((errno == ENOENT) ? 127 : 126);
198 /* NOTREACHED */
199 }
200
201 /* parent */
202 (void)signal(SIGINT, SIG_IGN);
203 (void)signal(SIGQUIT, SIG_IGN);
204 while (wait(&status) != pid);
205 (void)signal(SIGINT, SIG_DFL);
206 (void)signal(SIGQUIT, SIG_DFL);
207
208 do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
209
210 sleep(sleep_time);
211 } while (recurring);
212
213 exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
214
215 return 0;
216}
217
218static void
219usage(void)
220{
221 fprintf(stderr, "usage: systime [-P] [-r] [-t sleep_time] utility [argument ...]\n"
222 " systime -p [-r] [-t sleep_time]\n"
223 " systime [-P] -u user -s sys -i idle\n"
224 " systime [-P] [-r] [-t sleep_time] -T target_pid\n");
225 exit(1);
226}
227
228static void
229do_print(void)
230{
231 uint64_t user, system, idle;
232 kern_return_t kret;
233
234 kret = get_processor_time(&user, &system, &idle);
235 if (kret)
236 errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
237
238 printf("systime_user=%llu\n", user);
239 printf("systime_sys=%llu\n", system);
240 printf("systime_idle=%llu\n", idle);
241}
242
243static void
244do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle)
245{
246 uint64_t user, system, idle;
247 uint64_t userelapsed, systemelapsed, idleelapsed, totalelapsed;
248 kern_return_t kret;
249
250 kret = get_processor_time(&user, &system, &idle);
251 if (kret)
252 errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
253
254 userelapsed = user - *olduser;
255 systemelapsed = system - *oldsystem;
256 idleelapsed = idle - *oldidle;
257 totalelapsed = userelapsed + systemelapsed + idleelapsed;
258
259 if (usepercent) {
260 fprintf(stderr, "%1.02f%% user %1.02f%% sys %1.02f%% idle\n",
261 ((double)userelapsed * 100)/totalelapsed,
262 ((double)systemelapsed * 100)/totalelapsed,
263 ((double)idleelapsed * 100)/totalelapsed);
264 } else {
265 int ncpu;
266
267 kret = get_processor_count(&ncpu);
268 if (kret)
269 errx(1, "Error getting processor count: %s (%d)", mach_error_string(kret), kret);
270
271 fprintf(stderr, "%1.02f real %1.02f user %1.02f sys\n",
272 ((double)totalelapsed) / 1000 /* ms per sec */ / ncpu,
273 ((double)userelapsed) / 1000,
274 ((double)systemelapsed) / 1000);
275 }
276 *olduser = user;
277 *oldsystem = system;
278 *oldidle = idle;
279}
280
281static void
282do_piddifftime(bool usepercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time)
283{
284 uint64_t pid_user, pid_system, pid_time;
285 uint64_t userelapsed, systemelapsed, totalelapsed;
286 struct proc_taskinfo info;
287 int size;
288
289 size = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &info, sizeof(info));
290 if (size == PROC_PIDTASKINFO_SIZE) {
291 pid_user = info.pti_total_user;
292 pid_system = info.pti_total_system;
293 } else {
294 fprintf(stderr, "Error in proc_pidinfo(): %s",
295 strerror(errno));
296 exit(1);
297 }
298
299 pid_time = mach_absolute_time();
300
301 userelapsed = pid_user - *old_pid_user;
302 systemelapsed = pid_system - *old_pid_system;
303 totalelapsed = pid_time - *old_pid_time;
304
305 if (usepercent) {
306 fprintf(stderr, "Pid %d: %1.02f%% user %1.02f%% sys\n",
307 pid,
308 ((double)userelapsed * 100)/totalelapsed,
309 ((double)systemelapsed * 100)/totalelapsed);
310 } else {
311 fprintf(stderr, "Pid %d: %1.02f user %1.02f sys\n",
312 pid,
313 (((double)userelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000,
314 (((double)systemelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000);
315 }
316
317 *old_pid_user = pid_user;
318 *old_pid_system = pid_system;
319 *old_pid_time = pid_time;
320
321}
322
323static kern_return_t
324get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle)
325{
326 host_name_port_t host;
327 kern_return_t kret;
328 host_cpu_load_info_data_t host_load;
329 mach_msg_type_number_t count;
330
331 host = mach_host_self();
332
333 count = HOST_CPU_LOAD_INFO_COUNT;
334
335 kret = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&host_load, &count);
336 if (kret)
337 return kret;
338
339 *user = ((uint64_t)host_load.cpu_ticks[CPU_STATE_USER]) * 10 /* ms per tick */;
340 *sys = ((uint64_t)host_load.cpu_ticks[CPU_STATE_SYSTEM]) * 10;
341 *idle = ((uint64_t)host_load.cpu_ticks[CPU_STATE_IDLE]) * 10;
342
343 return KERN_SUCCESS;
344}
345
346static kern_return_t
347get_processor_count(int *ncpu)
348{
349 host_name_port_t host;
350 kern_return_t kret;
351 host_basic_info_data_t hi;
352 mach_msg_type_number_t count;
353
354 host = mach_host_self();
355
356 count = HOST_BASIC_INFO_COUNT;
357
358 kret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &count);
359 if (kret)
360 return kret;
361
362 *ncpu = hi.avail_cpus;
363
364 return KERN_SUCCESS;
365}