VirtualBox

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

Last change on this file since 3208 was 3208, checked in by bird, 7 years ago

kmk_time: Quote the arguments properly on windows.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: kmk_time.c 3208 2018-03-29 03:54:02Z 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 <bird-kBuild-spamx@anduin.net>
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 <program> [args]\n"
184 " or: %s --help\n"
185 " or: %s --version\n"
186 ,
187 argv0, argv0, argv0);
188 return 1;
189}
190
191
192int main(int argc, char **argv)
193{
194 int i, j;
195 int cTimes = 1;
196#if defined(_MSC_VER)
197 int fUnquoted = 0;
198 FILETIME ftStart, ft;
199 unsigned _int64 usMin, usMax, usAvg, usTotal, usCur;
200 unsigned _int64 iStart;
201 intptr_t rc;
202#else
203 struct timeval tvStart, tv;
204 unsigned long long usMin, usMax, usAvg, usTotal, usCur;
205 pid_t pid;
206 int rc;
207#endif
208 int rcExit = 0;
209
210 /*
211 * Parse arguments.
212 */
213 if (argc <= 1)
214 return usage(stderr, name(argv[0]));
215 for (i = 1; i < argc; i++)
216 {
217 char *psz = &argv[i][0];
218 if (*psz++ != '-')
219 break;
220
221 if (*psz == '-')
222 {
223 /* '--' ? */
224 if (!psz[1])
225 {
226 i++;
227 break;
228 }
229
230 /* convert to short. */
231 if (!strcmp(psz, "-help"))
232 psz = "h";
233 else if (!strcmp(psz, "-version"))
234 psz = "V";
235 else if (!strcmp(psz, "-iterations"))
236 psz = "i";
237#if defined(_MSC_VER)
238 else if (!strcmp(psz, "-unquoted"))
239 {
240 fUnquoted = 1;
241 continue;
242 }
243#endif
244 }
245
246 switch (*psz)
247 {
248 case 'h':
249 usage(stdout, name(argv[0]));
250 return 0;
251
252 case 'V':
253 printf("kmk_time - kBuild version %d.%d.%d (r%u)\n"
254 "Copyright (C) 2007-2018 knut st. osmundsen\n",
255 KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
256 KBUILD_SVN_REV);
257 return 0;
258
259 case 'i':
260 if (i + 1 >= argc)
261 {
262 fprintf(stderr, "%s: syntax error: missing iteration count\n", name(argv[0]));
263 return 1;
264 }
265 cTimes = atoi(argv[++i]);
266 if (cTimes <= 0)
267 {
268 fprintf(stderr, "%s: error: invalid interation count '%s'.\n", name(argv[0]), argv[i]);
269 return 1;
270 }
271 break;
272
273 default:
274 fprintf(stderr, "%s: error: syntax error '%s'\n", name(argv[0]), argv[i]);
275 return 1;
276 }
277 }
278
279 /*
280 * Make sure there's something to execute.
281 */
282 if (i >= argc)
283 {
284 fprintf(stderr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
285 return usage(stderr, name(argv[0]));
286 }
287
288 /*
289 * Execute the program the specified number of times.
290 */
291 usMax = usMin = usTotal = 0;
292 usMin--; /* wraps to max value */
293 for (j = 0; j < cTimes; j++)
294 {
295 /*
296 * Execute the program (it's actually supposed to be a command I think, but wtf).
297 */
298#if defined(_MSC_VER)
299 if (!fUnquoted)
300 {
301 if (quote_argv(argc - i, &argv[i], 0 /*fWatcomBrainDamage*/, 0 /*fFreeOrLeak*/) != 0)
302 {
303 fprintf(stderr, "%s: error: quote_argv failed\n");
304 return 8;
305 }
306 }
307
308 GetSystemTimeAsFileTime(&ftStart);
309 rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
310 if (rc == -1)
311 {
312 fprintf(stderr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
313 return 8;
314 }
315
316 GetSystemTimeAsFileTime(&ft);
317
318 iStart = ftStart.dwLowDateTime | ((unsigned _int64)ftStart.dwHighDateTime << 32);
319 usCur = ft.dwLowDateTime | ((unsigned _int64)ft.dwHighDateTime << 32);
320 usCur -= iStart;
321 usCur /= 10; /* to usecs */
322
323 printf("%s: ", name(argv[0]));
324 if (cTimes != 1)
325 printf("#%02u ", j + 1);
326 printf("%um%u.%06us - exit code: %d\n",
327 (unsigned)(usCur / (60 * 1000000)),
328 (unsigned)(usCur % (60 * 1000000)) / 1000000,
329 (unsigned)(usCur % 1000000),
330 rc);
331
332#else /* unix: */
333 gettimeofday(&tvStart, NULL);
334 pid = fork();
335 if (!pid)
336 {
337 /* child */
338 execvp(argv[i], &argv[i]);
339 fprintf(stderr, "%s: error: _execvp(\"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
340 return 8;
341 }
342 if (pid < 0)
343 {
344 fprintf(stderr, "%s: error: fork() failed: %s\n", name(argv[0]), strerror(errno));
345 return 9;
346 }
347
348 /* parent, wait for child. */
349 rc = 9;
350 while (waitpid(pid, &rc, 0) == -1 && errno == EINTR)
351 /* nothing */;
352 gettimeofday(&tv, NULL);
353
354 /* calc elapsed time */
355 tv.tv_sec -= tvStart.tv_sec;
356 if (tv.tv_usec > tvStart.tv_usec)
357 tv.tv_usec -= tvStart.tv_usec;
358 else
359 {
360 tv.tv_sec--;
361 tv.tv_usec = tv.tv_usec + 1000000 - tvStart.tv_usec;
362 }
363 usCur = tv.tv_sec * 1000000ULL
364 + tv.tv_usec;
365
366 printf("%s: ", name(argv[0]));
367 if (cTimes != 1)
368 printf("#%02u ", j + 1);
369 printf("%um%u.%06us",
370 (unsigned)(tv.tv_sec / 60),
371 (unsigned)(tv.tv_sec % 60),
372 (unsigned)tv.tv_usec);
373 if (WIFEXITED(rc))
374 {
375 printf(" - normal exit: %d\n", WEXITSTATUS(rc));
376 rc = WEXITSTATUS(rc);
377 }
378# ifndef __HAIKU__ /**@todo figure how haiku signals that a core was dumped. */
379 else if (WIFSIGNALED(rc) && WCOREDUMP(rc))
380 {
381 printf(" - dumped core: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc));
382 rc = 10;
383 }
384# endif
385 else if (WIFSIGNALED(rc))
386 {
387 printf(" - killed by: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc));
388 rc = 11;
389 }
390 else if (WIFSTOPPED(rc))
391 {
392 printf(" - stopped by: %s (%d)\n", my_strsignal(WSTOPSIG(rc)), WSTOPSIG(rc));
393 rc = 12;
394 }
395 else
396 {
397 printf(" unknown exit status %#x (%d)\n", rc, rc);
398 rc = 13;
399 }
400#endif /* unix */
401 if (rc && !rcExit)
402 rcExit = (int)rc;
403
404 /* calc min/max/avg */
405 usTotal += usCur;
406 if (usMax < usCur)
407 usMax = usCur;
408 if (usMin > usCur)
409 usMin = usCur;
410 }
411
412 /*
413 * Summary if more than one run.
414 */
415 if (cTimes != 1)
416 {
417 usAvg = usTotal / cTimes;
418
419 printf("%s: avg %um%u.%06us\n", name(argv[0]), (unsigned)(usAvg / 60000000), (unsigned)(usAvg % 60000000) / 1000000, (unsigned)(usAvg % 1000000));
420 printf("%s: min %um%u.%06us\n", name(argv[0]), (unsigned)(usMin / 60000000), (unsigned)(usMin % 60000000) / 1000000, (unsigned)(usMin % 1000000));
421 printf("%s: max %um%u.%06us\n", name(argv[0]), (unsigned)(usMax / 60000000), (unsigned)(usMax % 60000000) / 1000000, (unsigned)(usMax % 1000000));
422 }
423
424 return rcExit;
425}
426
Note: See TracBrowser for help on using the repository browser.

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