#include <mach/mach.h>
#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void usage(void);
static void do_print(void);
static void do_difftime(bool usepercent, uint64_t olduser, uint64_t oldsystem, uint64_t oldidle);
static kern_return_t get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle);
static kern_return_t get_processor_count(int *ncpu);
int
main(int argc, char *argv[])
{
int ch;
const char *optu = NULL;
const char *opts = NULL;
const char *opti = NULL;
int pid;
int status;
uint64_t olduser, oldsystem, oldidle;
kern_return_t kret;
bool usepercent = false;
while ((ch = getopt(argc, argv, "Ppu:s:i:")) != -1) {
switch (ch) {
case 'P':
usepercent = true;
break;
case 'p':
do_print();
exit(0);
break;
case 'u':
optu = optarg;
break;
case 's':
opts = optarg;
break;
case 'i':
opti = optarg;
break;
case '?':
default:
usage();
}
}
if (optu || opts || opti) {
char *endstr;
if (!optu)
usage();
olduser = strtoull(optu, &endstr, 0);
if (optu[0] == '\0' || endstr[0] != '\0')
usage();
if (!opts)
usage();
oldsystem = strtoull(opts, &endstr, 0);
if (opts[0] == '\0' || endstr[0] != '\0')
usage();
if (!opti)
usage();
oldidle = strtoull(opti, &endstr, 0);
if (opti[0] == '\0' || endstr[0] != '\0')
usage();
do_difftime(usepercent, olduser, oldsystem, oldidle);
exit(0);
}
argc -= optind;
argv += optind;
if (argc == 0)
usage();
kret = get_processor_time(&olduser, &oldsystem, &oldidle);
if (kret)
errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
switch(pid = vfork()) {
case -1:
perror("time");
exit(1);
case 0:
execvp(*argv, argv);
perror(*argv);
_exit((errno == ENOENT) ? 127 : 126);
}
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
while (wait(&status) != pid);
do_difftime(usepercent, olduser, oldsystem, oldidle);
exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
return 0;
}
static void
usage(void)
{
fprintf(stderr, "usage: systime [-P] utility [argument ...]\n"
" systime -p\n"
" systime [-P] -u user -s sys -i idle\n");
exit(1);
}
static void
do_print(void)
{
uint64_t user, system, idle;
kern_return_t kret;
kret = get_processor_time(&user, &system, &idle);
if (kret)
errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
printf("systime_user=%llu\n", user);
printf("systime_sys=%llu\n", system);
printf("systime_idle=%llu\n", idle);
}
static void
do_difftime(bool usepercent, uint64_t olduser, uint64_t oldsystem, uint64_t oldidle)
{
uint64_t user, system, idle;
uint64_t userelapsed, systemelapsed, idleelapsed, totalelapsed;
kern_return_t kret;
kret = get_processor_time(&user, &system, &idle);
if (kret)
errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
userelapsed = user - olduser;
systemelapsed = system - oldsystem;
idleelapsed = idle - oldidle;
totalelapsed = userelapsed + systemelapsed + idleelapsed;
if (usepercent) {
fprintf(stderr, "%1.02f%% user %1.02f%% sys %1.02f%% idle\n",
((double)userelapsed * 100)/totalelapsed,
((double)systemelapsed * 100)/totalelapsed,
((double)idleelapsed * 100)/totalelapsed);
} else {
int ncpu;
kret = get_processor_count(&ncpu);
if (kret)
errx(1, "Error getting processor count: %s (%d)", mach_error_string(kret), kret);
fprintf(stderr, "%1.02f real %1.02f user %1.02f sys\n",
((double)totalelapsed) / 1000 / ncpu,
((double)userelapsed) / 1000,
((double)systemelapsed) / 1000);
}
}
static kern_return_t
get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle)
{
host_name_port_t host;
kern_return_t kret;
host_cpu_load_info_data_t host_load;
mach_msg_type_number_t count;
host = mach_host_self();
count = HOST_CPU_LOAD_INFO_COUNT;
kret = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&host_load, &count);
if (kret)
return kret;
*user = ((uint64_t)host_load.cpu_ticks[CPU_STATE_USER]) * 10 ;
*sys = ((uint64_t)host_load.cpu_ticks[CPU_STATE_SYSTEM]) * 10;
*idle = ((uint64_t)host_load.cpu_ticks[CPU_STATE_IDLE]) * 10;
return KERN_SUCCESS;
}
static kern_return_t
get_processor_count(int *ncpu)
{
host_name_port_t host;
kern_return_t kret;
host_basic_info_data_t hi;
mach_msg_type_number_t count;
host = mach_host_self();
count = HOST_BASIC_INFO_COUNT;
kret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &count);
if (kret)
return kret;
*ncpu = hi.avail_cpus;
return KERN_SUCCESS;
}