C.2. Source Code for msacct /* * Run a command and print all field resource * usage and microstat accounting fields when process terminates. * * Borrowed largely from ptime.c * (Thanks Roger Faulkner and Mike Shapiro) * * Usage: msacct command * */ #include <sys/types.h> #include <sys/time.h> #include <procfs.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <math.h> #include <wait.h> #include <signal.h> static int look(pid_t); static void hr_min_sec(char *, long); static void prtime(char *, timestruc_t *); static int perr(const char *); static void tsadd(timestruc_t *result, timestruc_t *a, timestruc_t *b); static void tssub(timestruc_t *result, timestruc_t *a, timestruc_t *b); static char *command; static char procname[64]; main(int argc, char **argv) { pid_t pid; struct siginfo info; int status; if ((command = strrchr(argv[0], ,ÄÔ/,ÄÔ)) != NULL) command++; else command = argv[0]; if (argc <= 1) { (void) fprintf(stderr, "usage:%s command [ args ... ]\n", command); (void) fprintf(stderr, " (time a command using microstate accounting)\n"); return (1); } switch (pid = fork()) { case -1: (void) fprintf(stderr, "%s: cannot fork\n", command); return (2); case 0: /* newly created child process */ (void) execvp(argv[1], &argv[1]); (void) fprintf(stderr, "%s: exec failed\n", command); if (errno == ENOENT) _exit(127); else _exit(126); } (void) sprintf("%d", procname, (int)pid); /* for perr() */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); (void) waitid(P_PID, pid, &info, WEXITED | WNOWAIT); (void) look(pid); (void) waitpid(pid, &status, 0); if (WIFEXITED(status)) return (WEXITSTATUS(status)); else return ((status & ~WCOREFLG) | 0200); } static int look(pid_t pid) { char pathname[100]; int rval = 0; int fd; prusage_t prusage; timestruc_t real, user, sys; prusage_t *pup = &prusage; (void) sprintf(pathname, "/proc/%d/usage", (int)pid); if ((fd = open(pathname, O_RDONLY)) < 0) return (perr("open usage")); if (read(fd, &prusage, sizeof (prusage)) != sizeof (prusage)) rval = perr("read usage"); else { real = pup->pr_term; tssub(&real, &real, &pup->pr_create); user = pup->pr_utime; sys = pup->pr_stime; tsadd(&sys, &sys, &pup->pr_ttime); (void) fprintf(stderr, "\n"); printf("*** Usage Counters *** \n"); printf("Minor Faults:................. %ld\n", pup->pr_minf); printf("Major Faults:................. %ld\n", pup->pr_majf); printf("Swaps:........................ %ld\n", pup->pr_nswap); printf("Input Blocks:................. %ld\n", pup->pr_inblk); printf("Output Blocks:................ %ld\n", pup->pr_oublk); printf("STREAMS Messages Sent:........ %ld\n", pup->pr_msnd); printf("STREAMS Messages Received:.... %ld\n", pup->pr_mrcv); printf("Signals:...................... %ld\n", pup->pr_sigs); printf("Voluntary Context Switches:... %ld\n", pup->pr_vctx); printf("Involuntary Context Switches:. %ld\n", pup->pr_ictx); printf("System Calls:................. %ld\n", pup->pr_sysc); printf("Read/Write Characters:........ %ld\n", pup->pr_ioch); printf("*** State Times *** \n"); prtime("Total Elapsed Time:........... ", &real); prtime("Total User Time:.............. ", &user); prtime("Total System Time:............ ", &sys); prtime("Other System Trap Time:....... ", &pup->pr_ttime); prtime("Text Page Fault Sleep Time.... ", &pup->pr_tftime); prtime("Data Page Fault Sleep Time.... ", &pup->pr_dftime); prtime("Kernel Page Fault Sleep Time.. ", &pup->pr_kftime); prtime("User Lock Wait Sleep Time..... ", &pup->pr_ltime); prtime("All Other Sleep Time.......... ", &pup->pr_slptime); prtime("Time Waiting for a CPU........ ", &pup->pr_wtime); prtime("Stopped Time.................. ", &pup->pr_stoptime); } (void) close(fd); return (rval); } static void hr_min_sec(char *buf, long sec) { if (sec >= 3600) (void) sprintf(buf, "%ld:%.2ld:%.2ld", sec / 3600, (sec % 3600) / 60, sec % 60); else if (sec >= 60) (void) sprintf(buf, "%ld:%.2ld", sec / 60, sec % 60); else { (void) sprintf(buf, "%ld", sec); } } static void prtime(char *name, timestruc_t *ts) { char buf[32]; hr_min_sec(buf, ts->tv_sec); (void) fprintf(stderr, "%s%s.%.3u\n", name, buf, (u_int)ts->tv_nsec/1000000); } static int perr(const char *s) { if (s) (void) fprintf(stderr, "%s: ", procname); else s = procname; perror(s); return (1); } static void tsadd(timestruc_t *result, timestruc_t *a, timestruc_t *b) { result->tv_sec = a->tv_sec + b->tv_sec; if ((result->tv_nsec = a->tv_nsec + b->tv_nsec) >= 1000000000) { result->tv_nsec -= 1000000000; result->tv_sec += 1; } } static void tssub(timestruc_t *result, timestruc_t *a, timestruc_t *b) { result->tv_sec = a->tv_sec - b->tv_sec; if ((result->tv_nsec = a->tv_nsec - b->tv_nsec) < 0) { result->tv_nsec += 1000000000; result->tv_sec -= 1; } } |