static char *SccsId = "@(#)clock.c 4.4 (TU-Delft) 01/28/93";
/**********************************************************

Name/Version      : aux/4.4

Language          : C
Operating system  : UNIX SYSTEM V
Host machine      : HP9000

Authors           : A.J. van Genderen
                  : N.P. van der Meijs
Creation date     : 15-Mar-1988
Modified by       :
Modification date :


        Delft University of Technology
        Department of Electrical Engineering
        Network Theory Section
        Mekelweg 4 - P.O.Box 5031
        2600 GA DELFT
        The Netherlands

        Phone : 015 - 786234

        COPYRIGHT (C) 1988. All rights reserved.
**********************************************************/
#include "stdio.h"
#include "sys/types.h"
#include "sys/times.h"

#define MAXCLOCKS 1000
#define FALSE 0
#define TRUE  1

#ifdef BSD
#include <sys/timeb.h>
#define times(t) my_times(t)
static time_t my_times ();
#endif

struct clock {
    long user, sys, real;
    int ticks;
    char * name;
} clocks [MAXCLOCKS];

static int maxclocks = 0;
static int enable    = 0;

#define  User(i) (clocks[i].user)
#define   Sys(i) (clocks[i].sys)
#define  Real(i) (clocks[i].real)
#define Ticks(i) (clocks[i].ticks)
#define  Name(i) (clocks[i].name)

void clockInit ();
void tick ();
void tock ();
void clockPrintAll ();
void clockPrintTime ();
void prtime ();

/*
 * This clock module maintains a number of up to MAXCLOCK
 * timers, identified by a string given in the tick and tock
 * functions.
 * The tick function starts a given timer.
 * The tock function stops a given timer.
 * Timers can be stopped and restarted many times.
 *
 * Example:
 *     ...
 *     clockInit ();
 *     ...
 *     tick ("doit");		-- or inside doit
 *     doit ();
 *     tock ("doit");
 *     ...
 *     clockPrintAll (stdout);
 *     clockPrintTime (stdout)
 *     ...
 *
 * clockInit - start up this module
 * Must be called once at startup of the program,
 * or whenever the timers must be reset.
 *
 */
void clockInit ()
{
    maxclocks = 0;
    enable = 1;
    tick ("total time");
}

/*
 * Start or restart the timer <s>.
 * No special actions are needed to start
 * a timer for the first time.
 */
void tick (s)
char * s;
{
    int i;
    struct tms tms;
    char * strsave ();

    if (enable == 0) return;

    for (i = 0; i < maxclocks; i++)
	if (strcmp (s, Name (i)) == 0)
	    break;
    
    if (i == maxclocks && maxclocks < MAXCLOCKS) {
	Name (i) = strsave (s);
	User (i) = Sys (i) = Real (i) = 0;
	Ticks (i) = 0;
	maxclocks++;
    }

    if (i < maxclocks) {
	Ticks (i) += 1;
	Real (i)  -= times (&tms);
	Sys (i)   -= tms.tms_stime;
	User (i)  -= tms.tms_utime;
    }
}

/*
 * Stop the timer <s>.
 */
void tock (s)
char * s;
{
    int i;
    struct tms tms;

    if (enable == 0) return;

    for (i = 0; i < maxclocks; i++)
	if (strcmp (s, Name (i)) == 0)
	    break;

    if (i < maxclocks) {
	Ticks (i) -= 1;
	Real (i)  += times (&tms);
	Sys (i)   += tms.tms_stime;
	User (i)  += tms.tms_utime;
    }
}

/*
 * Print a table with the real, user and sys times
 * of all timers, to the stream indicated by <fp>
 */
void clockPrintAll (fp)
FILE * fp;
{
    int i;
    fprintf (fp, "\n%-22s%11s%11s%11s\n",
	"procedure", "real", "user", "sys");

    for (i = 0; i < maxclocks; i++) {
	if ((Ticks(i) == 0) && (*Name(i) != '_')) {
	    fprintf (fp, "%-22s", Name (i));
	    prtime  (fp, Real (i));
	    prtime  (fp, User (i));
	    prtime  (fp, Sys (i));
	    if (Real (i))
		fprintf (fp, "%4d%%\n", 100 * (User (i) + Sys (i)) / Real (i));
	    else
		fprintf (fp, "%4d%%\n", 100);
	}
    }
    fprintf (fp, "\n");
}

/*
 * Print total times (user, cpu and sys) to <fp>
 */
void clockPrintTime (fp)
FILE * fp;
{
    tock ("total time");
    fprintf (fp, "\tuser time          : ");
    prtime  (fp, User (0));
    fprintf (fp, "\n\tsystem time        : ");
    prtime  (fp, Sys (0));
    fprintf (fp, "\n\treal time          : ");
    prtime  (fp, Real (0));
    if (Real (0))
	fprintf (fp, "%4d%%\n", 100 * (User (0) + Sys (0)) / Real (0));
    else
	fprintf (fp, "%4d%%\n", 100);
    fprintf (fp, "\n");
    tick ("total time");
}

#if defined (hp9000s800)
#define	HZ	100
#else
#if defined (hp9000s300)
#define HZ	50
#else
#define HZ	60
#endif
#endif

/* converts a long to a time expression and prints it */
static void prtime (fp, t)
FILE * fp;
long t;
{
    long h;
    long m;
    long s;
    long d;
    int flag;

    t = (10 * t) / HZ; /* convert t to tenths of seconds */

    h = t / 36000;
    t = t % 36000;
    m = t / 600;
    t = t % 600;
    s = t / 10;
    t = t % 10;
    d = t;

    flag = FALSE;

    if (h > 0) {
        fprintf (fp, "%3d:", h);
	flag = TRUE;
    }
    else {
	fprintf (fp, "    ");
    }

    if (m > 0 || flag) {
	if (m < 10 && flag)
            fprintf (fp, "0%1d:", m);
	else 
            fprintf (fp, "%2d:", m);
	flag = TRUE;
    }
    else {
	fprintf (fp, "   ");
    }

    if (s < 10 && flag)
        fprintf (fp, "0%1d.", s);
    else
        fprintf (fp, "%2d.", s);
    fprintf (fp, "%d", d);
}

#ifdef BSD
#undef times

static time_t my_times (tms)
struct tms *tms;
{
    struct timeb timeb;
    times (tms);
    ftime (&timeb);
    return (60 * timeb.time + (60 * timeb.millitm) / 1000);
}
#endif


#ifdef DRIVER
/* test driver and example
 */
main ()
{
    int i;
    clockInit ();

    tick ("system");
    for (i = 0; i< 10; i++)
	system ("echo hello world > /dev/null");
    tock ("system");

    tick ("loop");
    for (i = 0; i< 1000000; i++) strlen ("abcd");
    tock ("loop");

    tick ("syscall");
    for (i = 0; i < 10000; i++) access ("/usr/abc/def", 0);
    tock ("syscall");

    clockPrintAll (stdout);
    clockPrintTime (stdout);
}
#endif
