(root)/
binutils-2.41/
gprofng/
testsuite/
gprofng.display/
synprog/
stopwatch.c
       1  /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
       2     Contributed by Oracle.
       3  
       4     This file is part of GNU Binutils.
       5  
       6     This program is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software
      18     Foundation, 51 Franklin Street - Fifth Floor, Boston,
      19     MA 02110-1301, USA.  */
      20  
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  #include <errno.h>
      25  #include <unistd.h>
      26  #include <sys/types.h>
      27  #include <sys/stat.h>
      28  #include <fcntl.h>
      29  
      30  #include "stopwatch.h"
      31  
      32  static char *prhrdelta (hrtime_t);
      33  static char *prhrvdelta (hrtime_t);
      34  void init_micro_acct ();
      35  
      36  /* stopwatch routines */
      37  void
      38  stpwtch_calibrate ()
      39  {
      40    struct timeval ttime;
      41    char buf[1024];
      42  
      43    (void) gettimeofday (&ttime, NULL);
      44    time_t secs = (time_t) ttime.tv_sec;
      45    sprintf (buf, "%s Stopwatch calibration", prtime (&secs));
      46    wlog (buf, NULL);
      47  
      48    init_micro_acct ();
      49    stopwatch_t *inner = stpwtch_alloc ("inner", 0);
      50    stopwatch_t *outer = stpwtch_alloc ("outer", 0);
      51    for (int i = 0; i < 1000; i++)
      52      {
      53        stpwtch_start (outer);
      54        stpwtch_start (inner);
      55        stpwtch_stop (inner);
      56        stpwtch_stop (outer);
      57      }
      58    stpwtch_print (inner);
      59    stpwtch_print (outer);
      60    free ((void *) inner);
      61    free ((void *) outer);
      62  }
      63  
      64  stopwatch_t *
      65  stpwtch_alloc (char *name, int histo)
      66  {
      67    stopwatch_t *w = (stopwatch_t *) malloc (sizeof (stopwatch_t));
      68    if (w == NULL)
      69      {
      70        fprintf (stderr, "stpwtch_alloc(%s, %d): malloc failed\n", name, histo);
      71        return NULL;
      72      }
      73    w->sum = 0.;
      74    w->sumsq = 0.;
      75    w->count = 0;
      76    w->min = 0;
      77    w->last = 0;
      78    w->name = strdup (name);
      79    stpwtch_start (w);
      80    w->begin = w->start;
      81  
      82    return w;
      83  }
      84  
      85  void
      86  stpwtch_start (stopwatch_t *w)
      87  {
      88    w->start = gethrtime ();
      89  }
      90  
      91  void
      92  stpwtch_stop (stopwatch_t *w)
      93  {
      94    if (w->start == 0)    /* if never started, ignore the call */
      95      return;
      96  
      97    /* get stopping high-res time */
      98    w->tempus = gethrtime ();
      99  
     100    /* bump count of stops */
     101    w->count++;
     102  
     103    /* compute the delta for this call */
     104    w->delta = w->tempus - w->start;
     105  
     106    /* add in this one */
     107    w->last = (double) (w->delta);
     108    w->sum = w->sum + w->last;
     109    w->sumsq = w->sumsq + w->last * w->last;
     110  
     111    if (w->max == 0)
     112      w->max = w->last;
     113    else if (w->max < w->last)
     114      w->max = w->last;
     115    if (w->min == 0)
     116      w->min = w->last;
     117    else if (w->min > w->last)
     118      w->min = w->last;
     119  
     120    /* show stopwatch stopped */
     121    w->start = 0;
     122  }
     123  
     124  void
     125  stpwtch_print (stopwatch_t *w)
     126  {
     127    char cvdbuf[1024];
     128  
     129    /* get stopping high-res time */
     130    w->tempus = gethrtime ();
     131    double duration = (double) (w->tempus - w->begin);
     132  
     133    if (w->count == 0)
     134      sprintf (cvdbuf, "       0.       s. ( 0. %% of %12.6f s.) -- %s\n",
     135               (duration / 1000000000.), w->name);
     136    else if (w->count == 1)
     137      sprintf (cvdbuf, "    %12.6f s. (%4.1f %%%% of %.6f s.) -- %s\n",
     138               w->sum / 1000000000., (100. * w->sum) / duration,
     139               duration / 1000000000., w->name);
     140    else
     141      sprintf (cvdbuf,
     142               "    %12.6f s.  (%4.1f %%%% of %.6f s.) -- %s\n\tN = %d,"
     143               " avg = %.3f us., min = %.3f, max = %.3f\n",
     144               w->sum / 1000000000., (100. * w->sum) / duration,
     145               duration / 1000000000., w->name, w->count,
     146               w->sum / 1000. / ((double) (w->count > 0 ? w->count : 1)),
     147               ((double) w->min / 1000.), ((double) w->max / 1000.));
     148    fprintf (stderr, cvdbuf);
     149  }
     150  
     151  /* hrtime routines */
     152  int
     153  whrlog (hrtime_t delta, char *event, char *string)
     154  {
     155    char buf[1024];
     156    if (string == NULL)
     157      sprintf (buf, "  %s secs. in %s\n", prhrdelta (delta), event);
     158    else
     159      sprintf (buf, "  %s secs. in %s\n\t%s\n", prhrdelta (delta), event, string);
     160    int bytes = fprintf (stderr, "%s", buf);
     161    return bytes;
     162  }
     163  
     164  /* hrtime routines */
     165  int
     166  whrvlog (hrtime_t delta, hrtime_t vdelta, char *event, char *string)
     167  {
     168    char buf[1024];
     169    if (string == NULL)
     170      sprintf (buf, "  %s wall-secs., %s CPU-secs., in %s\n",
     171               prhrdelta (delta), prhrvdelta (vdelta), event);
     172    else
     173      sprintf (buf, "  %s wall-secs., %s CPU-secs., in %s\n\t%s\n",
     174               prhrdelta (delta), prhrvdelta (vdelta), event, string);
     175    int bytes = fprintf (stderr, "%s", buf);
     176    return bytes;
     177  }
     178  
     179  /* prhrdelta (hrtime_t delta)
     180   *  returns a pointer to a static string in the form:
     181   *      sec.micros
     182   *       1.123456
     183   *      0123456789
     184   *
     185   *  prhrvdelta is the same, but uses a different static buffer
     186   */
     187  static char *
     188  prhrdelta (hrtime_t delta)
     189  {
     190    static char cvdbuf[26];
     191  
     192    /* convert to seconds */
     193    double tempus = ((double) delta) / (double) 1000000000.;
     194    sprintf (cvdbuf, "%10.6f", tempus);
     195    return cvdbuf;
     196  }
     197  
     198  static char *
     199  prhrvdelta (hrtime_t delta)
     200  {
     201    static char cvdbuf[26];
     202  
     203    /* convert to seconds */
     204    double tempus = ((double) delta) / (double) 1000000000.;
     205    sprintf (cvdbuf, "%10.6f", tempus);
     206    return cvdbuf;
     207  }
     208  
     209  /* time of day routines */
     210  
     211  /* starting time - first timestamp; initialized on first call */
     212  static struct timeval starttime = {0, 0};
     213  static struct timeval ttime;        /* last-recorded timestamp */
     214  static struct timeval deltatime;    /* delta of last-rec'd timestamp */
     215  
     216  static void
     217  snaptod ()
     218  {
     219    (void) gettimeofday (&ttime, NULL);
     220    if (starttime.tv_sec == 0)
     221      starttime = ttime;
     222  
     223    deltatime.tv_sec = ttime.tv_sec - starttime.tv_sec;
     224    deltatime.tv_usec = ttime.tv_usec - starttime.tv_usec;
     225    while (deltatime.tv_usec < 0)
     226      {
     227        deltatime.tv_sec--;
     228        deltatime.tv_usec += 1000000;
     229      }
     230  }
     231  
     232  int
     233  wlog (char *event, char *string)
     234  {
     235    char buf[1024];
     236  
     237    snaptod ();
     238    if (string == NULL)
     239      sprintf (buf, "%s ===== (%d) %s\n", prdelta (deltatime),
     240               (int) getpid (), event);
     241    else
     242      sprintf (buf, "%s ===== (%d) %s\n\t%s\n", prdelta (deltatime),
     243               (int) getpid (), event, string);
     244    int bytes = fprintf (stderr, "%s", buf);
     245    return bytes;
     246  }
     247  
     248  /* prtime (ttime)
     249   *  returns a pointer to a static string in the form:
     250   *      Thu  01 Jan 90  00:00:00\0
     251   *      01234567890122345678901234
     252   *
     253   *  ttime is a pointer to a UNIX time in seconds since epoch
     254   *  library routine localtime() is used
     255   */
     256  char *
     257  prtime (time_t *ttime)
     258  {
     259    static char *days[] = {
     260      "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
     261    };
     262    static char *months[] = {
     263      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     264      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     265    };
     266    static char cvbuf[26];
     267  
     268    /* get the date and time */
     269    struct tm *tp = localtime (ttime);
     270  
     271    /* convert to string */
     272    sprintf (cvbuf, "%3s  %02d %s %02d  %02d:%02d:%02d", days[tp->tm_wday],
     273             tp->tm_mday, months[tp->tm_mon], tp->tm_year % 100,
     274             tp->tm_hour, tp->tm_min, tp->tm_sec);
     275    return cvbuf;
     276  }
     277  
     278  char *
     279  prdelta (struct timeval tempus)
     280  {
     281    static char cvdbuf[26];
     282    while (tempus.tv_usec < 0)
     283      {
     284        tempus.tv_sec--;
     285        tempus.tv_usec += 1000000;
     286      }
     287    long seconds = tempus.tv_sec % 60;
     288    long minutes = tempus.tv_sec / 60;
     289    long hours = minutes / 60;
     290    minutes = minutes % 60;
     291    sprintf (cvdbuf, "%02ld:%02ld:%02ld.%03ld ",
     292             hours, minutes, seconds, (long) tempus.tv_usec / 1000);
     293    return cvdbuf;
     294  }