#include	<stdio.h>
#include	<sys/time.h>

#include	"logging.h"
#include	"timer.h"

unsigned	start[MAXTIMERS];
unsigned	cumulative[MAXTIMERS];
unsigned	count[MAXTIMERS];

unsigned	last_summary;

int		maxtimer = 0;

/*
 * This package is a quick hack to allow me to draw some conclusions
 * about INN and "where the time goes" without having to run profiling
 * and continually stop/restart the server.
 *
 * Functions that should have their time monitored need to call
 * TMRstart(n) at the beginning of the segment of code and TMRstop(n)
 * at the end.  The time spent will be accumulated and added to the
 * total for the counter 'n'.  'n' is probably one of the constants in 
 * timer.h.  You probably want to add a description to TMRsummary
 * explaining what your 'n' represents.
 *
 * There are no sanity checks to see if you have failed to start a timer,
 * etc., etc.  It is assumed that the user is moderately intelligent and
 * can properly deploy this code.
 *
 * Recursion is not allowed on a given timer.  Setting multiple timers
 * is fine (i.e., you may have a timer for the total time to write an
 * article, how long the disk write takes, how long the history update
 * takes, blah blah.. which are components of the total art write time)
 *
 * This package is written with the assumption that TMRmainloophook()
 * will be called with none of the timers started.  The statistics are
 * generated here.  It may not be fatal to have a timer running, but
 * it will not be properly accounted for (at least within that time slice).
 */

/*
 * This function is designed to report the number of milliseconds since
 * the first invocation.  I wanted better resolution than time(), and
 * something easier to work with than gettimeofday()'s struct timeval's.
 */

unsigned	gettime()
{
	static			init = 0;
	static struct timeval	start_tv;
	struct timeval		tv;

	if (! init) {
		gettimeofday(&start_tv, NULL);
		init++;
	}
	gettimeofday(&tv, NULL);
	return((tv.tv_sec - start_tv.tv_sec) * 1000 + (tv.tv_usec - start_tv.tv_usec) / 1000);
}





void		TMRinit()
{
	int i;

	last_summary = gettime();	/* First invocation */

	for (i = 0; i < MAXTIMERS; i++) {
		count[i] = start[i] = cumulative[i] = 0;
	}
}





void		dosummary(secs)
unsigned	secs;
{
	char buffer[8192];
	char buf[256];
	char *str;
	int i;

	sprintf(buffer, "ME time %d ", secs);
	for (i = 0; i < maxtimer; i++) {
		str = "???";
		switch (i) {
			case TMR_IDLE:		str = "idle";  break;
			case TMR_ARTWRITE:	str = "artwrite";  break;
			case TMR_ARTLINK:	str = "artlink";  break;
			case TMR_HISWRITE:	str = "hiswrite";  break;
			case TMR_HISSYNC:	str = "hissync";  break;
			case TMR_SITESEND:	str = "sitesend";  break;
			case TMR_ARTCTRL:	str = "artctrl";  break;
			case TMR_ARTCNCL:	str = "artcncl";  break;
			case TMR_HISHAVE:	str = "hishave";  break;
			case TMR_HISGREP:	str = "hisgrep";  break;
		}
		sprintf(buf, "%s %d(%d) ", str, cumulative[i], count[i]);
		cumulative[i] = count[i] = 0;
		strcat(buffer, buf);
	}
	syslog(L_NOTICE, "%s", buffer);
}





void		TMRmainloophook()
{
	unsigned now = gettime();

	if (now - last_summary > SUMMARY_INTERVAL) {
		dosummary(now - last_summary);
		last_summary = now;
	}
}





void		TMRstart(n)
int n;
{
	if (n >= maxtimer) {
		maxtimer = n + 1;
	}
	start[n] = gettime();
}




void		TMRstop(n)
int n;
{
	cumulative[n] += gettime() - start[n];
	count[n]++;
}
