mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 15:03:34 +00:00
99 lines
2.9 KiB
C
99 lines
2.9 KiB
C
|
#if 0
|
||
|
/*─────────────────────────────────────────────────────────────────╗
|
||
|
│ To the extent possible under law, Justine Tunney has waived │
|
||
|
│ all copyright and related or neighboring rights to this file, │
|
||
|
│ as it is written in the following disclaimers: │
|
||
|
│ • http://unlicense.org/ │
|
||
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||
|
╚─────────────────────────────────────────────────────────────────*/
|
||
|
#endif
|
||
|
#include "libc/calls/calls.h"
|
||
|
#include "libc/calls/struct/timespec.h"
|
||
|
#include "libc/fmt/itoa.h"
|
||
|
#include "libc/log/log.h"
|
||
|
#include "libc/math.h"
|
||
|
#include "libc/str/str.h"
|
||
|
#include "libc/sysv/consts/ex.h"
|
||
|
#include "libc/time/time.h"
|
||
|
#include "libc/x/x.h"
|
||
|
|
||
|
/**
|
||
|
* @fileoverview command for showing how long a command takes
|
||
|
*
|
||
|
* This offers the following improvements over the existing `time`
|
||
|
* command that's incorporated into most shells:
|
||
|
*
|
||
|
* - This will show microseconds if seconds < 1
|
||
|
* - This will launch APE binaries on systems with broken libc execv()
|
||
|
*/
|
||
|
|
||
|
#define WRITE(FD, STR) write(FD, STR, strlen(STR))
|
||
|
|
||
|
void OnChild(void *arg) {
|
||
|
char **argv = arg;
|
||
|
execv(argv[0], argv);
|
||
|
_exit(127);
|
||
|
}
|
||
|
|
||
|
long double GetTimeval(struct timeval t) {
|
||
|
return t.tv_sec + t.tv_usec * 1e-6l;
|
||
|
}
|
||
|
|
||
|
void PrintMetric(const char *name, long double d) {
|
||
|
char buf[256], *p = buf;
|
||
|
long mins, secs, mils, mics;
|
||
|
mins = d / 60;
|
||
|
secs = fmodl(d, 60);
|
||
|
mils = fmodl(d * 1000, 1000);
|
||
|
mics = fmodl(d * 1000000, 1000);
|
||
|
p = stpcpy(p, name), *p++ = '\t';
|
||
|
p += int64toarray_radix10(mins, p), *p++ = 'm';
|
||
|
p += int64toarray_radix10(secs, p), *p++ = '.';
|
||
|
*p++ = '0' + mils / 100;
|
||
|
*p++ = '0' + mils / 10 % 10;
|
||
|
*p++ = '0' + mils % 10;
|
||
|
if (!secs) {
|
||
|
*p++ = '0' + mics / 100;
|
||
|
*p++ = '0' + mics / 10 % 10;
|
||
|
*p++ = '0' + mics % 10;
|
||
|
}
|
||
|
*p++ = 's';
|
||
|
*p++ = '\n';
|
||
|
write(2, buf, p - buf);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) {
|
||
|
int ws;
|
||
|
char *exepath;
|
||
|
struct rusage r;
|
||
|
long double real;
|
||
|
char exebuf[PATH_MAX];
|
||
|
if (argc >= 2) {
|
||
|
if ((exepath = commandv(argv[1], exebuf))) {
|
||
|
real = nowl();
|
||
|
argv[1] = exepath;
|
||
|
if ((ws = xvspawn(OnChild, argv + 1, &r)) != -1) {
|
||
|
PrintMetric("real", nowl() - real);
|
||
|
PrintMetric("user", GetTimeval(r.ru_utime));
|
||
|
PrintMetric("sys", GetTimeval(r.ru_stime));
|
||
|
if (WIFEXITED(ws)) {
|
||
|
return WEXITSTATUS(ws);
|
||
|
} else {
|
||
|
return 128 + WTERMSIG(ws);
|
||
|
}
|
||
|
} else {
|
||
|
perror("xvspawn");
|
||
|
return 127;
|
||
|
}
|
||
|
} else {
|
||
|
perror(argv[1]);
|
||
|
return 127;
|
||
|
}
|
||
|
} else {
|
||
|
WRITE(2, "Usage: ");
|
||
|
WRITE(2, argv[0]);
|
||
|
WRITE(2, " PROG [ARGS...]\n");
|
||
|
return EX_USAGE;
|
||
|
}
|
||
|
}
|