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