VirtualBox

source: kBuild/trunk/src/misc/kmk_time.c

Last change on this file was 3336, checked in by bird, 5 years ago

kmk_time: Windows quoting bug for multiple iterations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1/* $Id: kmk_time.c 3336 2020-04-22 12:08:35Z bird $ */
2/** @file
3 * kmk_time - Time program execution.
4 *
5 * This is based on kmk/kmkbuiltin/redirect.c.
6 */
7
8/*
9 * Copyright (c) 2007-2010 knut st. osmundsen <[email protected]>
10 *
11 * This file is part of kBuild.
12 *
13 * kBuild is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * kBuild is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
25 *
26 */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <time.h>
37#if defined(_MSC_VER)
38# include <io.h>
39# include <direct.h>
40# include <process.h>
41# include <Windows.h>
42# include "quote_argv.h"
43#else
44# include <unistd.h>
45# include <sys/time.h>
46# include <sys/wait.h>
47# include <signal.h>
48#endif
49
50#ifdef __OS2__
51# define INCL_BASE
52# include <os2.h>
53# ifndef LIBPATHSTRICT
54# define LIBPATHSTRICT 3
55# endif
56#endif
57
58#ifndef _MSC_VER
59static const char *my_strsignal(int signo)
60{
61#define CASE_SIG_RET_STR(sig) if (signo == SIG##sig) return #sig
62#ifdef SIGHUP
63 CASE_SIG_RET_STR(HUP);
64#endif
65#ifdef SIGINT
66 CASE_SIG_RET_STR(INT);
67#endif
68#ifdef SIGQUIT
69 CASE_SIG_RET_STR(QUIT);
70#endif
71#ifdef SIGILL
72 CASE_SIG_RET_STR(ILL);
73#endif
74#ifdef SIGTRAP
75 CASE_SIG_RET_STR(TRAP);
76#endif
77#ifdef SIGABRT
78 CASE_SIG_RET_STR(ABRT);
79#endif
80#ifdef SIGIOT
81 CASE_SIG_RET_STR(IOT);
82#endif
83#ifdef SIGBUS
84 CASE_SIG_RET_STR(BUS);
85#endif
86#ifdef SIGFPE
87 CASE_SIG_RET_STR(FPE);
88#endif
89#ifdef SIGKILL
90 CASE_SIG_RET_STR(KILL);
91#endif
92#ifdef SIGUSR1
93 CASE_SIG_RET_STR(USR1);
94#endif
95#ifdef SIGSEGV
96 CASE_SIG_RET_STR(SEGV);
97#endif
98#ifdef SIGUSR2
99 CASE_SIG_RET_STR(USR2);
100#endif
101#ifdef SIGPIPE
102 CASE_SIG_RET_STR(PIPE);
103#endif
104#ifdef SIGALRM
105 CASE_SIG_RET_STR(ALRM);
106#endif
107#ifdef SIGTERM
108 CASE_SIG_RET_STR(TERM);
109#endif
110#ifdef SIGSTKFLT
111 CASE_SIG_RET_STR(STKFLT);
112#endif
113#ifdef SIGCHLD
114 CASE_SIG_RET_STR(CHLD);
115#endif
116#ifdef SIGCONT
117 CASE_SIG_RET_STR(CONT);
118#endif
119#ifdef SIGSTOP
120 CASE_SIG_RET_STR(STOP);
121#endif
122#ifdef SIGTSTP
123 CASE_SIG_RET_STR(TSTP);
124#endif
125#ifdef SIGTTIN
126 CASE_SIG_RET_STR(TTIN);
127#endif
128#ifdef SIGTTOU
129 CASE_SIG_RET_STR(TTOU);
130#endif
131#ifdef SIGURG
132 CASE_SIG_RET_STR(URG);
133#endif
134#ifdef SIGXCPU
135 CASE_SIG_RET_STR(XCPU);
136#endif
137#ifdef SIGXFSZ
138 CASE_SIG_RET_STR(XFSZ);
139#endif
140#ifdef SIGVTALRM
141 CASE_SIG_RET_STR(VTALRM);
142#endif
143#ifdef SIGPROF
144 CASE_SIG_RET_STR(PROF);
145#endif
146#ifdef SIGWINCH
147 CASE_SIG_RET_STR(WINCH);
148#endif
149#ifdef SIGIO
150 CASE_SIG_RET_STR(IO);
151#endif
152#ifdef SIGPWR
153 CASE_SIG_RET_STR(PWR);
154#endif
155#ifdef SIGSYS
156 CASE_SIG_RET_STR(SYS);
157#endif
158#ifdef SIGBREAK
159 CASE_SIG_RET_STR(BREAK);
160#endif
161#undef CASE_SIG_RET_STR
162 return "???";
163}
164#endif /* unix */
165
166static const char *name(const char *pszName)
167{
168 const char *psz = strrchr(pszName, '/');
169#if defined(_MSC_VER) || defined(__OS2__)
170 const char *psz2 = strrchr(pszName, '\\');
171 if (!psz2)
172 psz2 = strrchr(pszName, ':');
173 if (psz2 && (!psz || psz2 > psz))
174 psz = psz2;
175#endif
176 return psz ? psz + 1 : pszName;
177}
178
179
180static int usage(FILE *pOut, const char *argv0)
181{
182 fprintf(pOut,
183 "usage: %s [options] [--] <program> [args]\n"
184 " or: %s --help\n"
185 " or: %s --version\n"
186 "\n"
187 "Options:\n"
188 " -i <count>, --iteration <count>\n"
189 " Run the program <count> times and display minium, maximum and average\n"
190 " run times at the end.\n"
191 ,
192 argv0, argv0, argv0);
193#ifdef _MSC_VER
194 fprintf(pOut,
195 " --unquoted\n"
196 " Windows only: No argument quoting, use them as-is.\n");
197#endif
198 return 1;
199}
200
201
202int main(int argc, char **argv)
203{
204 int i, j;
205 int cTimes = 1;
206#if defined(_MSC_VER)
207 int fUnquoted = 0;
208 FILETIME ftStart, ft;
209 unsigned _int64 usMin, usMax, usAvg, usTotal, usCur;
210 unsigned _int64 iStart;
211 intptr_t rc;
212#else
213 struct timeval tvStart, tv;
214 unsigned long long usMin, usMax, usAvg, usTotal, usCur;
215 pid_t pid;
216 int rc;
217#endif
218 int rcExit = 0;
219
220 /*
221 * Parse arguments.
222 */
223 if (argc <= 1)
224 return usage(stderr, name(argv[0]));
225 for (i = 1; i < argc; i++)
226 {
227 char *psz = &argv[i][0];
228 if (*psz++ != '-')
229 break;
230
231 if (*psz == '-')
232 {
233 /* '--' ? */
234 if (!psz[1])
235 {
236 i++;
237 break;
238 }
239
240 /* convert to short. */
241 if (!strcmp(psz, "-help"))
242 psz = "h";
243 else if (!strcmp(psz, "-version"))
244 psz = "V";
245 else if (!strcmp(psz, "-iterations"))
246 psz = "i";
247#if defined(_MSC_VER)
248 else if (!strcmp(psz, "-unquoted"))
249 {
250 fUnquoted = 1;
251 continue;
252 }
253#endif
254 }
255
256 switch (*psz)
257 {
258 case 'h':
259 usage(stdout, name(argv[0]));
260 return 0;
261
262 case 'V':
263 printf("kmk_time - kBuild version %d.%d.%d (r%u)\n"
264 "Copyright (C) 2007-2018 knut st. osmundsen\n",
265 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
266 KBUILD_SVN_REV);
267 return 0;
268
269 case 'i':
270 if (i + 1 >= argc)
271 {
272 fprintf(stderr, "%s: syntax error: missing iteration count\n", name(argv[0]));
273 return 1;
274 }
275 cTimes = atoi(argv[++i]);
276 if (cTimes <= 0)
277 {
278 fprintf(stderr, "%s: error: invalid interation count '%s'.\n", name(argv[0]), argv[i]);
279 return 1;
280 }
281 break;
282
283 default:
284 fprintf(stderr, "%s: error: syntax error '%s'\n", name(argv[0]), argv[i]);
285 return 1;
286 }
287 }
288
289 /*
290 * Make sure there's something to execute.
291 */
292 if (i >= argc)
293 {
294 fprintf(stderr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
295 return usage(stderr, name(argv[0]));
296 }
297
298 /*
299 * Execute the program the specified number of times.
300 */
301 usMax = usMin = usTotal = 0;
302 usMin--; /* wraps to max value */
303 for (j = 0; j < cTimes; j++)
304 {
305 /*
306 * Execute the program (it's actually supposed to be a command I think, but wtf).
307 */
308#if defined(_MSC_VER)
309 if (!fUnquoted)
310 {
311 if (quote_argv(argc - i, &argv[i], 0 /*fWatcomBrainDamage*/, 0 /*fFreeOrLeak*/) != 0)
312 {
313 fprintf(stderr, "%s: error: quote_argv failed\n");
314 return 8;
315 }
316 fUnquoted = 1; /* Don't quote them again in the next iteration. */
317 }
318
319 GetSystemTimeAsFileTime(&ftStart);
320 rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
321 if (rc == -1)
322 {
323 fprintf(stderr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
324 return 8;
325 }
326
327 GetSystemTimeAsFileTime(&ft);
328
329 iStart = ftStart.dwLowDateTime | ((unsigned _int64)ftStart.dwHighDateTime << 32);
330 usCur = ft.dwLowDateTime | ((unsigned _int64)ft.dwHighDateTime << 32);
331 usCur -= iStart;
332 usCur /= 10; /* to usecs */
333
334 printf("%s: ", name(argv[0]));
335 if (cTimes != 1)
336 printf("#%02u ", j + 1);
337 printf("%um%u.%06us - exit code: %d\n",
338 (unsigned)(usCur / (60 * 1000000)),
339 (unsigned)(usCur % (60 * 1000000)) / 1000000,
340 (unsigned)(usCur % 1000000),
341 rc);
342
343#else /* unix: */
344 gettimeofday(&tvStart, NULL);
345 pid = fork();
346 if (!pid)
347 {
348 /* child */
349 execvp(argv[i], &argv[i]);
350 fprintf(stderr, "%s: error: _execvp(\"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
351 return 8;
352 }
353 if (pid < 0)
354 {
355 fprintf(stderr, "%s: error: fork() failed: %s\n", name(argv[0]), strerror(errno));
356 return 9;
357 }
358
359 /* parent, wait for child. */
360 rc = 9;
361 while (waitpid(pid, &rc, 0) == -1 && errno == EINTR)
362 /* nothing */;
363 gettimeofday(&tv, NULL);
364
365 /* calc elapsed time */
366 tv.tv_sec -= tvStart.tv_sec;
367 if (tv.tv_usec > tvStart.tv_usec)
368 tv.tv_usec -= tvStart.tv_usec;
369 else
370 {
371 tv.tv_sec--;
372 tv.tv_usec = tv.tv_usec + 1000000 - tvStart.tv_usec;
373 }
374 usCur = tv.tv_sec * 1000000ULL
375 + tv.tv_usec;
376
377 printf("%s: ", name(argv[0]));
378 if (cTimes != 1)
379 printf("#%02u ", j + 1);
380 printf("%um%u.%06us",
381 (unsigned)(tv.tv_sec / 60),
382 (unsigned)(tv.tv_sec % 60),
383 (unsigned)tv.tv_usec);
384 if (WIFEXITED(rc))
385 {
386 printf(" - normal exit: %d\n", WEXITSTATUS(rc));
387 rc = WEXITSTATUS(rc);
388 }
389# ifndef __HAIKU__ /**@todo figure how haiku signals that a core was dumped. */
390 else if (WIFSIGNALED(rc) && WCOREDUMP(rc))
391 {
392 printf(" - dumped core: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc));
393 rc = 10;
394 }
395# endif
396 else if (WIFSIGNALED(rc))
397 {
398 printf(" - killed by: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc));
399 rc = 11;
400 }
401 else if (WIFSTOPPED(rc))
402 {
403 printf(" - stopped by: %s (%d)\n", my_strsignal(WSTOPSIG(rc)), WSTOPSIG(rc));
404 rc = 12;
405 }
406 else
407 {
408 printf(" unknown exit status %#x (%d)\n", rc, rc);
409 rc = 13;
410 }
411#endif /* unix */
412 if (rc && !rcExit)
413 rcExit = (int)rc;
414
415 /* calc min/max/avg */
416 usTotal += usCur;
417 if (usMax < usCur)
418 usMax = usCur;
419 if (usMin > usCur)
420 usMin = usCur;
421 }
422
423 /*
424 * Summary if more than one run.
425 */
426 if (cTimes != 1)
427 {
428 usAvg = usTotal / cTimes;
429
430 printf("%s: avg %um%u.%06us\n", name(argv[0]), (unsigned)(usAvg / 60000000), (unsigned)(usAvg % 60000000) / 1000000, (unsigned)(usAvg % 1000000));
431 printf("%s: min %um%u.%06us\n", name(argv[0]), (unsigned)(usMin / 60000000), (unsigned)(usMin % 60000000) / 1000000, (unsigned)(usMin % 1000000));
432 printf("%s: max %um%u.%06us\n", name(argv[0]), (unsigned)(usMax / 60000000), (unsigned)(usMax % 60000000) / 1000000, (unsigned)(usMax % 1000000));
433 }
434
435 return rcExit;
436}
437
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette