-
Notifications
You must be signed in to change notification settings - Fork 1
/
ntime.c
174 lines (140 loc) · 4.72 KB
/
ntime.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* Copyright 2014, 2017 TeamWau Software.
* Licensed under the two-clause BSD license.
* See COPYING for details
*
* TODO: (in order of importance)
* 0. Clean up code, argument parsing, etc.
* 1. Squash compiler warnings (about printing uint64_t's with the format string %llu)
*
*/
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdint.h>
#include <getopt.h>
#define TRUE 1
#define FALSE 0
#define VERSION_NUMBER "1.2.0"
char colour, silent, numOnly;
int stdout_cp, stderr_cp, devnull;
uint64_t getTimeDiff(struct timespec *time_A, struct timespec *time_B)
{
return ((time_A->tv_sec * 1000000000) + time_A->tv_nsec) - ((time_B->tv_sec * 1000000000) + time_B->tv_nsec);
}
uint64_t measureTime(char* program, char** program_args)
{
struct timespec start, end;
pid_t pID;
int rs;
if (program_args == NULL) {
program_args[0] = " ";
}
if (silent == 'y') {
devnull = open("/dev/null", O_WRONLY);
stdout_cp = dup(STDOUT_FILENO);
stderr_cp = dup(STDERR_FILENO);
/* Make sure buffers are clear */
fflush(stdout);
fflush(stderr);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(devnull, STDOUT_FILENO);
dup2(devnull, STDERR_FILENO);
}
/* Starts the timer, forks ntime, then starts the user-specified program under the fork. */
clock_gettime(CLOCK_MONOTONIC, &start);
pID = fork();
if (pID == 0) {
execvp(program, program_args);
} else if (pID < 0) {
return 1;
} else {
waitpid(pID, &rs, 0);
/* Gets the time from the clock then prints its result. */
clock_gettime(CLOCK_MONOTONIC, &end);
uint64_t tdiff = getTimeDiff(&end, &start);
if (silent == 'y') {
/* Clears and restores stdout and stderr to ntime */
fflush(stdout);
fflush(stderr);
dup2(stdout_cp, STDOUT_FILENO);
dup2(stdout_cp, STDERR_FILENO);
close(stdout_cp);
close(stderr_cp);
}
return tdiff;
}
return 1;
}
int formatResult(char* program, char** program_args)
{
uint64_t result = measureTime(program, program_args);
if (result == 1) {
return 1;
} else {
if (numOnly == 'y') {
printf("\n%llu\n", result);
return 0;
} else if (numOnly == 'n') {
if (colour == 'y') {
printf("\n\033[31;1mntime approx. wall time result: \033[32m%llu\033[36mns\033[0m\n", result);
return 0;
} else if (colour == 'n') {
printf("\nntime approx. wall time result: %lluns\n", result);
return 0;
}
}
}
return 1;
}
int main(int argc, char **argv)
{
if (argc == 1) {
printf("%s - precise time program\nInvocation: %s [-dnvs] <program> <args for program>\n", argv[0], argv[0]);
printf("Arguments for %s: \n'-n': disable coloured output.\n'-v': print version and exit.\n'-s': supress ran program's stdout.\n'-d': disable colour and only display the number (useful for scripts when used with -s)\n", argv[0]);
printf("\nNOTICE: Times are \033[1mapproximate\033[0m! As this is a very accurate timer, it measures the overhead time of its own execution, as well as any work done by the kernel.\n"
"What this means is that the times are likely to vary heavily and should probably be averaged versus used as-is as a benchmark.\n"
"\nError: no program specified, terminating.\n"
);
return 1;
}
int opt, flags;
colour = 'y';
silent = 'n';
numOnly = 'n';
/* Parse args for ntime */
while ((opt = getopt(2, argv, "nvsd")) != -1) {
switch (opt) {
case 'n':
flags = TRUE;
colour = 'n';
break;
case 'v':
printf( "%s - version %s\n", argv[0], VERSION_NUMBER );
break;
case 's':
flags = TRUE;
silent = 'y';
break;
case 'd':
flags = TRUE;
numOnly = 'y';
break;
default:
flags = FALSE;
break;
}
}
flags = FALSE;
if (flags == FALSE) {
return formatResult(argv[1], argv + 1);
} else if (flags == TRUE) {
return formatResult(argv[2], argv + 2);
}
//if we get here, it means we didn't call measuretime above. Problem.
printf("Problem.\n");
return 1;
}