timevar.c revision 132718
1250003Sadrian/* Timing variables for measuring compiler performance. 2250003Sadrian Copyright (C) 2000, 2003 Free Software Foundation, Inc. 3250003Sadrian Contributed by Alex Samuel <samuel@codesourcery.com> 4250003Sadrian 5250003SadrianThis file is part of GCC. 6250003Sadrian 7250003SadrianGCC is free software; you can redistribute it and/or modify it under 8250003Sadrianthe terms of the GNU General Public License as published by the Free 9250003SadrianSoftware Foundation; either version 2, or (at your option) any later 10250003Sadrianversion. 11250003Sadrian 12250003SadrianGCC is distributed in the hope that it will be useful, but WITHOUT ANY 13250003SadrianWARRANTY; without even the implied warranty of MERCHANTABILITY or 14250003SadrianFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15250003Sadrianfor more details. 16250003Sadrian 17250003SadrianYou should have received a copy of the GNU General Public License 18250003Sadrianalong with GCC; see the file COPYING. If not, write to the Free 19250003SadrianSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 20250003Sadrian02111-1307, USA. */ 21250003Sadrian 22250003Sadrian#include "config.h" 23250003Sadrian#include "system.h" 24250003Sadrian#ifdef HAVE_SYS_TIMES_H 25250003Sadrian# include <sys/times.h> 26250003Sadrian#endif 27250003Sadrian#ifdef HAVE_SYS_RESOURCE_H 28250003Sadrian#include <sys/resource.h> 29250003Sadrian#endif 30250003Sadrian#include "coretypes.h" 31250003Sadrian#include "tm.h" 32250003Sadrian#include "intl.h" 33250003Sadrian#include "rtl.h" 34250003Sadrian#include "toplev.h" 35250003Sadrian 36250003Sadrian#ifndef HAVE_CLOCK_T 37250003Sadriantypedef int clock_t; 38250003Sadrian#endif 39250003Sadrian 40250003Sadrian#ifndef HAVE_STRUCT_TMS 41250003Sadrianstruct tms 42250003Sadrian{ 43250003Sadrian clock_t tms_utime; 44250003Sadrian clock_t tms_stime; 45250003Sadrian clock_t tms_cutime; 46250003Sadrian clock_t tms_cstime; 47250003Sadrian}; 48250003Sadrian#endif 49250003Sadrian 50250003Sadrian#ifndef RUSAGE_SELF 51250003Sadrian# define RUSAGE_SELF 0 52250003Sadrian#endif 53250003Sadrian 54250003Sadrian/* Calculation of scale factor to convert ticks to microseconds. 55250003Sadrian We mustn't use CLOCKS_PER_SEC except with clock(). */ 56250003Sadrian#if HAVE_SYSCONF && defined _SC_CLK_TCK 57250003Sadrian# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */ 58250003Sadrian#else 59250003Sadrian# ifdef CLK_TCK 60250003Sadrian# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */ 61250003Sadrian# else 62250003Sadrian# ifdef HZ 63250003Sadrian# define TICKS_PER_SECOND HZ /* traditional UNIX */ 64250003Sadrian# else 65250003Sadrian# define TICKS_PER_SECOND 100 /* often the correct value */ 66250003Sadrian# endif 67250003Sadrian# endif 68250003Sadrian#endif 69250003Sadrian 70250003Sadrian/* Prefer times to getrusage to clock (each gives successively less 71250003Sadrian information). */ 72250003Sadrian#ifdef HAVE_TIMES 73250003Sadrian# if defined HAVE_DECL_TIMES && !HAVE_DECL_TIMES 74250003Sadrian extern clock_t times (struct tms *); 75250003Sadrian# endif 76250003Sadrian# define USE_TIMES 77250003Sadrian# define HAVE_USER_TIME 78250003Sadrian# define HAVE_SYS_TIME 79250003Sadrian# define HAVE_WALL_TIME 80250003Sadrian#else 81250003Sadrian#ifdef HAVE_GETRUSAGE 82250003Sadrian# if defined HAVE_DECL_GETRUSAGE && !HAVE_DECL_GETRUSAGE 83250003Sadrian extern int getrusage (int, struct rusage *); 84250003Sadrian# endif 85250003Sadrian# define USE_GETRUSAGE 86250003Sadrian# define HAVE_USER_TIME 87250003Sadrian# define HAVE_SYS_TIME 88250003Sadrian#else 89250003Sadrian#ifdef HAVE_CLOCK 90250003Sadrian# if defined HAVE_DECL_CLOCK && !HAVE_DECL_CLOCK 91250003Sadrian extern clock_t clock (void); 92250003Sadrian# endif 93250003Sadrian# define USE_CLOCK 94250003Sadrian# define HAVE_USER_TIME 95250003Sadrian#endif 96250003Sadrian#endif 97250003Sadrian#endif 98250003Sadrian 99250003Sadrian/* libc is very likely to have snuck a call to sysconf() into one of 100250003Sadrian the underlying constants, and that can be very slow, so we have to 101250003Sadrian precompute them. Whose wonderful idea was it to make all those 102250003Sadrian _constants_ variable at run time, anyway? */ 103250003Sadrian#ifdef USE_TIMES 104250003Sadrianstatic double ticks_to_msec; 105250003Sadrian#define TICKS_TO_MSEC (1 / (double)TICKS_PER_SECOND) 106250003Sadrian#endif 107250003Sadrian 108250003Sadrian#ifdef USE_CLOCK 109250003Sadrianstatic double clocks_to_msec; 110250003Sadrian#define CLOCKS_TO_MSEC (1 / (double)CLOCKS_PER_SEC) 111250003Sadrian#endif 112250003Sadrian 113250003Sadrian#include "flags.h" 114250003Sadrian#include "timevar.h" 115250003Sadrian 116250003Sadrianstatic bool timevar_enable; 117250003Sadrian 118250003Sadrian/* See timevar.h for an explanation of timing variables. */ 119250003Sadrian 120250003Sadrian/* A timing variable. */ 121250003Sadrian 122250003Sadrianstruct timevar_def 123250003Sadrian{ 124250003Sadrian /* Elapsed time for this variable. */ 125250003Sadrian struct timevar_time_def elapsed; 126250003Sadrian 127250003Sadrian /* If this variable is timed independently of the timing stack, 128250003Sadrian using timevar_start, this contains the start time. */ 129250003Sadrian struct timevar_time_def start_time; 130250003Sadrian 131250003Sadrian /* The name of this timing variable. */ 132250003Sadrian const char *name; 133250003Sadrian 134250003Sadrian /* Nonzero if this timing variable is running as a standalone 135250003Sadrian timer. */ 136250003Sadrian unsigned standalone : 1; 137250003Sadrian 138250003Sadrian /* Nonzero if this timing variable was ever started or pushed onto 139250003Sadrian the timing stack. */ 140250003Sadrian unsigned used : 1; 141250003Sadrian}; 142250003Sadrian 143250003Sadrian/* An element on the timing stack. Elapsed time is attributed to the 144250003Sadrian topmost timing variable on the stack. */ 145250003Sadrian 146250003Sadrianstruct timevar_stack_def 147250003Sadrian{ 148250003Sadrian /* The timing variable at this stack level. */ 149250003Sadrian struct timevar_def *timevar; 150250003Sadrian 151250003Sadrian /* The next lower timing variable context in the stack. */ 152250003Sadrian struct timevar_stack_def *next; 153250003Sadrian}; 154250003Sadrian 155250003Sadrian/* Declared timing variables. Constructed from the contents of 156250003Sadrian timevar.def. */ 157250003Sadrianstatic struct timevar_def timevars[TIMEVAR_LAST]; 158250003Sadrian 159250003Sadrian/* The top of the timing stack. */ 160250003Sadrianstatic struct timevar_stack_def *stack; 161250003Sadrian 162250003Sadrian/* A list of unused (i.e. allocated and subsequently popped) 163250003Sadrian timevar_stack_def instances. */ 164250003Sadrianstatic struct timevar_stack_def *unused_stack_instances; 165250003Sadrian 166250003Sadrian/* The time at which the topmost element on the timing stack was 167250003Sadrian pushed. Time elapsed since then is attributed to the topmost 168250003Sadrian element. */ 169250003Sadrianstatic struct timevar_time_def start_time; 170250003Sadrian 171250003Sadrianstatic void get_time (struct timevar_time_def *); 172250003Sadrianstatic void timevar_accumulate (struct timevar_time_def *, 173250003Sadrian struct timevar_time_def *, 174250003Sadrian struct timevar_time_def *); 175250003Sadrian 176250003Sadrian/* Fill the current times into TIME. The definition of this function 177250003Sadrian also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and 178250003Sadrian HAVE_WALL_TIME macros. */ 179250003Sadrian 180250003Sadrianstatic void 181250003Sadrianget_time (struct timevar_time_def *now) 182250003Sadrian{ 183250003Sadrian now->user = 0; 184250003Sadrian now->sys = 0; 185250003Sadrian now->wall = 0; 186250003Sadrian 187250003Sadrian if (!timevar_enable) 188250003Sadrian return; 189250003Sadrian 190250003Sadrian { 191250003Sadrian#ifdef USE_TIMES 192250003Sadrian struct tms tms; 193250003Sadrian now->wall = times (&tms) * ticks_to_msec; 194250003Sadrian now->user = tms.tms_utime * ticks_to_msec; 195250003Sadrian now->sys = tms.tms_stime * ticks_to_msec; 196250003Sadrian#endif 197250003Sadrian#ifdef USE_GETRUSAGE 198250003Sadrian struct rusage rusage; 199250003Sadrian getrusage (RUSAGE_SELF, &rusage); 200250003Sadrian now->user = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec * 1e-6; 201250003Sadrian now->sys = rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec * 1e-6; 202250003Sadrian#endif 203250003Sadrian#ifdef USE_CLOCK 204250003Sadrian now->user = clock () * clocks_to_msec; 205250003Sadrian#endif 206250003Sadrian } 207250003Sadrian} 208250003Sadrian 209250003Sadrian/* Add the difference between STOP_TIME and START_TIME to TIMER. */ 210250003Sadrian 211250003Sadrianstatic void 212250003Sadriantimevar_accumulate (struct timevar_time_def *timer, 213250003Sadrian struct timevar_time_def *start_time, 214250003Sadrian struct timevar_time_def *stop_time) 215250003Sadrian{ 216250003Sadrian timer->user += stop_time->user - start_time->user; 217250003Sadrian timer->sys += stop_time->sys - start_time->sys; 218250003Sadrian timer->wall += stop_time->wall - start_time->wall; 219250003Sadrian} 220250003Sadrian 221250003Sadrian/* Initialize timing variables. */ 222250003Sadrian 223250003Sadrianvoid 224250003Sadriantimevar_init (void) 225250003Sadrian{ 226250003Sadrian timevar_enable = true; 227250003Sadrian 228250003Sadrian /* Zero all elapsed times. */ 229250003Sadrian memset (timevars, 0, sizeof (timevars)); 230250003Sadrian 231250003Sadrian /* Initialize the names of timing variables. */ 232250003Sadrian#define DEFTIMEVAR(identifier__, name__) \ 233250003Sadrian timevars[identifier__].name = name__; 234250003Sadrian#include "timevar.def" 235250003Sadrian#undef DEFTIMEVAR 236250003Sadrian 237250003Sadrian#ifdef USE_TIMES 238250003Sadrian ticks_to_msec = TICKS_TO_MSEC; 239250003Sadrian#endif 240250003Sadrian#ifdef USE_CLOCK 241250003Sadrian clocks_to_msec = CLOCKS_TO_MSEC; 242250003Sadrian#endif 243250003Sadrian} 244250003Sadrian 245250003Sadrian/* Push TIMEVAR onto the timing stack. No further elapsed time is 246250003Sadrian attributed to the previous topmost timing variable on the stack; 247250003Sadrian subsequent elapsed time is attributed to TIMEVAR, until it is 248250003Sadrian popped or another element is pushed on top. 249250003Sadrian 250250003Sadrian TIMEVAR cannot be running as a standalone timer. */ 251250003Sadrian 252250003Sadrianvoid 253250003Sadriantimevar_push (timevar_id_t timevar) 254250003Sadrian{ 255250003Sadrian struct timevar_def *tv = &timevars[timevar]; 256250003Sadrian struct timevar_stack_def *context; 257250003Sadrian struct timevar_time_def now; 258250003Sadrian 259250003Sadrian if (!timevar_enable) 260250003Sadrian return; 261250003Sadrian 262250003Sadrian /* Mark this timing variable as used. */ 263250003Sadrian tv->used = 1; 264250003Sadrian 265250003Sadrian /* Can't push a standalone timer. */ 266250003Sadrian if (tv->standalone) 267250003Sadrian abort (); 268250003Sadrian 269250003Sadrian /* What time is it? */ 270250003Sadrian get_time (&now); 271250003Sadrian 272250003Sadrian /* If the stack isn't empty, attribute the current elapsed time to 273250003Sadrian the old topmost element. */ 274250003Sadrian if (stack) 275250003Sadrian timevar_accumulate (&stack->timevar->elapsed, &start_time, &now); 276250003Sadrian 277250003Sadrian /* Reset the start time; from now on, time is attributed to 278250003Sadrian TIMEVAR. */ 279250003Sadrian start_time = now; 280250003Sadrian 281250003Sadrian /* See if we have a previously-allocated stack instance. If so, 282250003Sadrian take it off the list. If not, malloc a new one. */ 283250003Sadrian if (unused_stack_instances != NULL) 284250003Sadrian { 285250003Sadrian context = unused_stack_instances; 286250003Sadrian unused_stack_instances = unused_stack_instances->next; 287250003Sadrian } 288250003Sadrian else 289250003Sadrian context = xmalloc (sizeof (struct timevar_stack_def)); 290250003Sadrian 291250003Sadrian /* Fill it in and put it on the stack. */ 292250003Sadrian context->timevar = tv; 293250003Sadrian context->next = stack; 294250003Sadrian stack = context; 295250003Sadrian} 296250003Sadrian 297250003Sadrian/* Pop the topmost timing variable element off the timing stack. The 298250003Sadrian popped variable must be TIMEVAR. Elapsed time since the that 299250003Sadrian element was pushed on, or since it was last exposed on top of the 300250003Sadrian stack when the element above it was popped off, is credited to that 301250003Sadrian timing variable. */ 302250003Sadrian 303250003Sadrianvoid 304250003Sadriantimevar_pop (timevar_id_t timevar) 305250003Sadrian{ 306250003Sadrian struct timevar_time_def now; 307250003Sadrian struct timevar_stack_def *popped = stack; 308250003Sadrian 309250003Sadrian if (!timevar_enable) 310250003Sadrian return; 311250003Sadrian 312250003Sadrian if (&timevars[timevar] != stack->timevar) 313250003Sadrian { 314250003Sadrian sorry ("cannot timevar_pop '%s' when top of timevars stack is '%s'", 315250003Sadrian timevars[timevar].name, stack->timevar->name); 316250003Sadrian abort (); 317250003Sadrian } 318250003Sadrian 319250003Sadrian /* What time is it? */ 320250003Sadrian get_time (&now); 321250003Sadrian 322250003Sadrian /* Attribute the elapsed time to the element we're popping. */ 323250003Sadrian timevar_accumulate (&popped->timevar->elapsed, &start_time, &now); 324250003Sadrian 325250003Sadrian /* Reset the start time; from now on, time is attributed to the 326250003Sadrian element just exposed on the stack. */ 327250003Sadrian start_time = now; 328250003Sadrian 329250003Sadrian /* Take the item off the stack. */ 330250003Sadrian stack = stack->next; 331250003Sadrian 332250003Sadrian /* Don't delete the stack element; instead, add it to the list of 333250003Sadrian unused elements for later use. */ 334250003Sadrian popped->next = unused_stack_instances; 335250003Sadrian unused_stack_instances = popped; 336250003Sadrian} 337250003Sadrian 338250003Sadrian/* Start timing TIMEVAR independently of the timing stack. Elapsed 339250003Sadrian time until timevar_stop is called for the same timing variable is 340250003Sadrian attributed to TIMEVAR. */ 341250003Sadrian 342250003Sadrianvoid 343250003Sadriantimevar_start (timevar_id_t timevar) 344250003Sadrian{ 345250003Sadrian struct timevar_def *tv = &timevars[timevar]; 346250003Sadrian 347250003Sadrian if (!timevar_enable) 348250003Sadrian return; 349250003Sadrian 350250003Sadrian /* Mark this timing variable as used. */ 351250003Sadrian tv->used = 1; 352250003Sadrian 353250003Sadrian /* Don't allow the same timing variable to be started more than 354250003Sadrian once. */ 355250003Sadrian if (tv->standalone) 356250003Sadrian abort (); 357250003Sadrian tv->standalone = 1; 358250003Sadrian 359250003Sadrian get_time (&tv->start_time); 360250003Sadrian} 361250003Sadrian 362250003Sadrian/* Stop timing TIMEVAR. Time elapsed since timevar_start was called 363250003Sadrian is attributed to it. */ 364250003Sadrian 365250003Sadrianvoid 366250003Sadriantimevar_stop (timevar_id_t timevar) 367250003Sadrian{ 368250003Sadrian struct timevar_def *tv = &timevars[timevar]; 369250003Sadrian struct timevar_time_def now; 370250003Sadrian 371250003Sadrian if (!timevar_enable) 372250003Sadrian return; 373250003Sadrian 374250003Sadrian /* TIMEVAR must have been started via timevar_start. */ 375250003Sadrian if (!tv->standalone) 376250003Sadrian abort (); 377250003Sadrian 378250003Sadrian get_time (&now); 379250003Sadrian timevar_accumulate (&tv->elapsed, &tv->start_time, &now); 380250003Sadrian} 381250003Sadrian 382250003Sadrian/* Fill the elapsed time for TIMEVAR into ELAPSED. Returns 383250003Sadrian update-to-date information even if TIMEVAR is currently running. */ 384250003Sadrian 385250003Sadrianvoid 386250003Sadriantimevar_get (timevar_id_t timevar, struct timevar_time_def *elapsed) 387250003Sadrian{ 388250003Sadrian struct timevar_def *tv = &timevars[timevar]; 389250003Sadrian struct timevar_time_def now; 390250003Sadrian 391250003Sadrian *elapsed = tv->elapsed; 392250003Sadrian 393250003Sadrian /* Is TIMEVAR currently running as a standalone timer? */ 394250003Sadrian if (tv->standalone) 395250003Sadrian { 396250003Sadrian get_time (&now); 397250003Sadrian timevar_accumulate (elapsed, &tv->start_time, &now); 398250003Sadrian } 399250003Sadrian /* Or is TIMEVAR at the top of the timer stack? */ 400250003Sadrian else if (stack->timevar == tv) 401250003Sadrian { 402250003Sadrian get_time (&now); 403250003Sadrian timevar_accumulate (elapsed, &start_time, &now); 404250003Sadrian } 405250003Sadrian} 406250003Sadrian 407250003Sadrian/* Summarize timing variables to FP. The timing variable TV_TOTAL has 408250003Sadrian a special meaning -- it's considered to be the total elapsed time, 409250003Sadrian for normalizing the others, and is displayed last. */ 410250003Sadrian 411250003Sadrianvoid 412250003Sadriantimevar_print (FILE *fp) 413250003Sadrian{ 414250003Sadrian /* Only print stuff if we have some sort of time information. */ 415250003Sadrian#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME) 416250003Sadrian unsigned int /* timevar_id_t */ id; 417250003Sadrian struct timevar_time_def *total = &timevars[TV_TOTAL].elapsed; 418250003Sadrian struct timevar_time_def now; 419250003Sadrian 420250003Sadrian if (!timevar_enable) 421250003Sadrian return; 422250003Sadrian 423250003Sadrian /* Update timing information in case we're calling this from GDB. */ 424250003Sadrian 425250003Sadrian if (fp == 0) 426250003Sadrian fp = stderr; 427250003Sadrian 428250003Sadrian /* What time is it? */ 429250003Sadrian get_time (&now); 430250003Sadrian 431250003Sadrian /* If the stack isn't empty, attribute the current elapsed time to 432250003Sadrian the old topmost element. */ 433250003Sadrian if (stack) 434250003Sadrian timevar_accumulate (&stack->timevar->elapsed, &start_time, &now); 435250003Sadrian 436250003Sadrian /* Reset the start time; from now on, time is attributed to 437250003Sadrian TIMEVAR. */ 438250003Sadrian start_time = now; 439250003Sadrian 440250003Sadrian fputs (_("\nExecution times (seconds)\n"), fp); 441250003Sadrian for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id) 442250003Sadrian { 443250003Sadrian struct timevar_def *tv = &timevars[(timevar_id_t) id]; 444250003Sadrian const double tiny = 5e-3; 445250003Sadrian 446250003Sadrian /* Don't print the total execution time here; that goes at the 447250003Sadrian end. */ 448250003Sadrian if ((timevar_id_t) id == TV_TOTAL) 449250003Sadrian continue; 450250003Sadrian 451250003Sadrian /* Don't print timing variables that were never used. */ 452250003Sadrian if (!tv->used) 453250003Sadrian continue; 454250003Sadrian 455250003Sadrian /* Don't print timing variables if we're going to get a row of 456250003Sadrian zeroes. */ 457250003Sadrian if (tv->elapsed.user < tiny 458250003Sadrian && tv->elapsed.sys < tiny 459250003Sadrian && tv->elapsed.wall < tiny) 460250003Sadrian continue; 461250003Sadrian 462250003Sadrian /* The timing variable name. */ 463250003Sadrian fprintf (fp, " %-22s:", tv->name); 464250003Sadrian 465250003Sadrian#ifdef HAVE_USER_TIME 466250003Sadrian /* Print user-mode time for this process. */ 467250003Sadrian fprintf (fp, "%7.2f (%2.0f%%) usr", 468250003Sadrian tv->elapsed.user, 469250003Sadrian (total->user == 0 ? 0 : tv->elapsed.user / total->user) * 100); 470250003Sadrian#endif /* HAVE_USER_TIME */ 471250003Sadrian 472250003Sadrian#ifdef HAVE_SYS_TIME 473250003Sadrian /* Print system-mode time for this process. */ 474250003Sadrian fprintf (fp, "%7.2f (%2.0f%%) sys", 475250003Sadrian tv->elapsed.sys, 476250003Sadrian (total->sys == 0 ? 0 : tv->elapsed.sys / total->sys) * 100); 477250003Sadrian#endif /* HAVE_SYS_TIME */ 478250003Sadrian 479250003Sadrian#ifdef HAVE_WALL_TIME 480250003Sadrian /* Print wall clock time elapsed. */ 481250003Sadrian fprintf (fp, "%7.2f (%2.0f%%) wall", 482250003Sadrian tv->elapsed.wall, 483250003Sadrian (total->wall == 0 ? 0 : tv->elapsed.wall / total->wall) * 100); 484250003Sadrian#endif /* HAVE_WALL_TIME */ 485250003Sadrian 486250003Sadrian putc ('\n', fp); 487250003Sadrian } 488250003Sadrian 489250003Sadrian /* Print total time. */ 490250003Sadrian fputs (_(" TOTAL :"), fp); 491250003Sadrian#ifdef HAVE_USER_TIME 492250003Sadrian fprintf (fp, "%7.2f ", total->user); 493250003Sadrian#endif 494250003Sadrian#ifdef HAVE_SYS_TIME 495250003Sadrian fprintf (fp, "%7.2f ", total->sys); 496250003Sadrian#endif 497250003Sadrian#ifdef HAVE_WALL_TIME 498250003Sadrian fprintf (fp, "%7.2f\n", total->wall); 499250003Sadrian#endif 500250003Sadrian 501250003Sadrian#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) 502250003Sadrian || defined (HAVE_WALL_TIME) */ 503250003Sadrian} 504250003Sadrian 505250003Sadrian/* Prints a message to stderr stating that time elapsed in STR is 506250003Sadrian TOTAL (given in microseconds). */ 507250003Sadrian 508250003Sadrianvoid 509250003Sadrianprint_time (const char *str, long total) 510250003Sadrian{ 511250003Sadrian long all_time = get_run_time (); 512250003Sadrian fprintf (stderr, 513250003Sadrian _("time in %s: %ld.%06ld (%ld%%)\n"), 514250003Sadrian str, total / 1000000, total % 1000000, 515250003Sadrian all_time == 0 ? 0 516250003Sadrian : (long) (((100.0 * (double) total) / (double) all_time) + .5)); 517250003Sadrian} 518250003Sadrian