1
0
Files
irix-657m-src/eoe/cmd/time/time.c
2022-09-29 17:59:04 +03:00

250 lines
6.1 KiB
C

/*
* time:
*
* Time a process' execution.
*/
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <wait.h>
#include <sys/types.h>
#include <sys/resource.h>
/*
* Built in format declarations.
*/
static char *shortfmt =
"\n"
"real %E\n"
"user %U\n"
"sys %S\n";
static char *longfmt =
"\n"
"elapsed time ........................... %E\n"
" user CPU ........................... %U\n"
" system CPU ......................... %S\n"
" percent busy ....................... %P%%\n"
"page faults ............................ %V\n"
" page reclaims ...................... %R\n"
" page ins ........................... %F\n"
"context switches and swaps ............. %C\n"
" voluntary context switches ......... %w\n"
" involuntary context switches ....... %c\n"
" swaps .............................. %W\n"
"Number of I/O operations ............... %?\n"
" block input operations ............. %I\n"
" block output operations ............ %O\n"
"signals received ....................... %k\n";
/*
* Argument declarations
* =====================
*/
static char *myname; /* name we were executed under */
static char *format; /* resource usage report format */
static char **command; /* command to time */
static pid_t pid; /* PID of process to time */
/*
* Local routine declarations
* ==========================
*/
void main(int argc, char **argv);
static void parseArguments(int argc, char **argv);
static void printUsage(FILE *fp, const char *format,
double dt, const struct rusage *ru);
static __inline double
timeval(const struct timeval *t)
{
return t->tv_sec + t->tv_usec/1.0E6;
}
static __inline double
timespec(const struct timespec *t)
{
return t->tv_sec + t->tv_nsec/1.0E9;
}
static __inline double
timespecdiff(const struct timespec *t0, const struct timespec *tN)
{
return timespec(tN) - timespec(t0);
}
void
main(int argc, char **argv)
{
struct rusage rusage; /* resource usage of children */
int exitstatus; /* exit status of child */
struct timespec t0, tN; /* start and end time of process */
parseArguments(argc, argv);
clock_gettime(CLOCK_REALTIME, &t0);
pid = fork();
if (pid < 0) {
fprintf(stderr, "%s: can't fork: %s\n", myname, strerror(errno));
exit(1); /* POSIX mandates a value between 1-125 */
}
if (pid == 0) {
execvp(command[0], command);
fprintf(stderr, "%s: can't exec %s: %s\n",
myname, command[0], strerror(errno));
exit(errno == ENOENT ? 127 : 126); /* values mandated by POSIX */
}
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
wait3(&exitstatus, 0, &rusage);
clock_gettime(CLOCK_REALTIME, &tN);
if (!WIFEXITED(exitstatus))
fprintf(stderr, "%s: command terminated abnormally\n", myname);
printUsage(stderr, format, timespecdiff(&t0, &tN), &rusage);
exit(WEXITSTATUS(exitstatus));
}
static void
parseArguments(int argc, char **argv)
{
char *s;
int ch;
extern char *optarg;
extern int optind;
myname = strrchr(argv[0], '/');
if (myname != NULL)
myname++;
else
myname = argv[0];
format = shortfmt;
if (s = getenv("TIME"))
format = s;
/* process command line switches */
while ((ch = getopt(argc, argv, "f:lp")) != -1)
switch ((char)ch)
{
default:
case '?':
fprintf(stderr, "%s: unknown option -%c\n", myname, ch);
fprintf(stderr, "usage: %s [-f format | -l | -p] command args ...\n",
myname);
exit(EXIT_FAILURE);
break;
case 'f':
format = optarg;
break;
case 'l':
format = longfmt;
break;
case 'p':
/* note that -p is a POSIX flag and may not be changed */
format = shortfmt;
break;
}
if (argc - optind <= 0)
/* nothing to do ... */
exit(EXIT_SUCCESS);
command = argv+optind;
}
static void
printUsage(FILE *fp, const char *format,
double dt, const struct rusage *ru)
{
const char *fmt;
int c, neednl = 1;
double ut = timeval(&ru->ru_utime);
double st = timeval(&ru->ru_stime);
for (fmt = format; *fmt; *fmt ? fmt++ : 0) {
neednl = 1;
switch (c = *fmt) {
default:
putc(c, fp);
neednl = (c != '\n');
break;
case '\\':
switch (c = *++fmt) {
default:
fprintf(fp, "%s: \\%c?", myname, *fmt ? *fmt : '0');
break;
case '\\': putc('\\', fp); break;
case 'n': putc('\n', fp); neednl = 0; break;
case 'r': putc('\r', fp); break;
case 't': putc('\t', fp); break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': {
int n = 3;
c = 0;
while (*fmt >= '0' && *fmt <= '7' && n-- > 0)
c = 8*c + *fmt++ - '0';
putc(c, fp);
neednl = (c != '\n');
break;
}
}
break;
case '%':
switch (c = *++fmt) {
default:
fprintf(fp, "%s: %%%c?", myname, *fmt ? *fmt : '0');
break;
case '%': putc('%', fp); break;
case 'E': fprintf(fp, "%.3f", dt); break;
case 'U': fprintf(fp, "%.3f", ut); break;
case 'S': fprintf(fp, "%.3f", st); break;
case 'R': fprintf(fp, "%d", ru->ru_minflt); break;
case 'F': fprintf(fp, "%d", ru->ru_majflt); break;
case 'w': fprintf(fp, "%d", ru->ru_nvcsw); break;
case 'c': fprintf(fp, "%d", ru->ru_nivcsw); break;
case 'W': fprintf(fp, "%d", ru->ru_nswap); break;
case 'I': fprintf(fp, "%d", ru->ru_inblock); break;
case 'O': fprintf(fp, "%d", ru->ru_oublock); break;
case 'k': fprintf(fp, "%d", ru->ru_nsignals); break;
case 'P':
fprintf(fp, "%.1f%%", 100*(ut+st)/dt);
break;
case 'V':
fprintf(fp, "%d", ru->ru_minflt + ru->ru_majflt);
break;
case 'C':
fprintf(fp, "%d",
ru->ru_nvcsw + ru->ru_nivcsw + ru->ru_nswap);
break;
case '?':
fprintf(fp, "%d", ru->ru_inblock + ru->ru_oublock);
break;
}
}
}
if (neednl)
putc('\n', fp);
}