List:Falcon Storage Engine« Previous MessageNext Message »
From:Jim Starkey Date:November 4 2008 8:50pm
Subject:Stats Class
View as plain text  
Attached is a Stats class that I wrote for Nimbus for keeping track and 
reporting on various internal events.  I could be used to replace a 
modest amount of Falcon code scattered around various sub-systems.

In Nimbus, I used the cycle manager thread to do reporting.  The 
reporting code looks something like this:

        Thread *thread = Thread::getThread("MasterCatalog::cycleManager");
        Stats snapshot;
        snapshot.snapshot(stats);
        int dumpMemory = 0;
       
        while (!shutdown)
            {
            thread->sleep(CYCLE_SLEEP * 1000);

            if (verbose & VERBOSE_STATS)
                {
                snapshot.computeDelta(stats);
               
                if (snapshot.change)
                    snapshot.log(InterestingStats);

                snapshot.snapshot(stats);
                }
              }

There is also a central Stats object (stats) that is updated with code like:

            stats->bump(statNetIn);

in appropriate strategic locations.

Having a single object that is just counters and another to capture the 
initial values for an interval, computer the differences, and report 
(selected) results is really quite convenient.

Consider it donated without encumbrance.

-- 
Jim Starkey
President, NimbusDB, Inc.
978 526-1376


#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <memory.h>
#include "Cloud.h"
#include "Stats.h"
#include "Interlock.h"
#include "Log.h"
#include "LogLock.h"

static const char *names[] = {
	"Objects",
	"created",
	"saved",
	"imported",
	"exported",
	"loaded",
	"purged",
	"dropped",
	"deleted",
	"rcvd",
	"sent",
	"in",
	"out",
	"---"
	};


Stats::Stats(void)
{
	memset(buckets, 0, sizeof(buckets));
	active = true;
	change = false;
}

Stats::~Stats(void)
{
}

void Stats::bump(StatBuckets bucket)
{
	if (active)
		INTERLOCKED_INCREMENT(buckets[bucket]);
}

int64 Stats::getTime(void)
{
#ifdef _WIN32
	return (int64) GetTickCount() * 1000;
#else
	struct timeval microTime;
	int ret = gettimeofday(&microTime, NULL);
	
	return (int64) microTime.tv_sec * 1000000 + microTime.tv_usec;
#endif
}

void Stats::snapshot(Stats* stats)
{
	for (int n = 1; n < statMax; ++n)
		buckets[n] = stats->buckets[n];
		
	buckets[0] = stats->numberObjects();
	startTime = getTime();
}

void Stats::computeDelta(Stats* stats)
{
	change = false;
	
	for (int n = 1; n < statMax; ++n)
		if ( (buckets[n] = stats->buckets[n] - buckets[n]) > 0)
			change = true;
	
	buckets[0] = stats->numberObjects();
	deltaTime = getTime() - startTime;
}

void Stats::log(int mask)
{
	LogLock logLock;
	const char *sep = "";
	
	for (int n = 0; n < statMax; ++n)
		if ((mask & (1 << n)) && buckets[n])
			{
			Log::log(LogInfo, "%s%d %s", sep, buckets[n], names[n]);
			sep = ", ";
			}
			
	if (sep[0])
		Log::log(LogInfo, " in %.1f sec\n", (double) deltaTime / 1000000.0);
}

int Stats::numberObjects(void)
{
	return buckets[statObjectsCreated] + buckets[statObjectsImported] -
		   (buckets[statObjectsDropped] + buckets[statObjectsDeleted]);
}

void Stats::logDelta(int64 start, int64 finish, const char* text, ...)
{
	va_list		args;
	va_start	(args, text);
	char		temp[1024];

	if (vsnprintf (temp, sizeof (temp) - 1, text, args) < 0)
		temp [sizeof (temp) - 1] = 0;
	
	Log::log(LogInfo, "%s in %.1f seconds\n", temp, (double) (finish - start) / 1000000.0);
}

void Stats::printDelta(int64 start, int64 finish, const char* text, ...)
{
	va_list		args;
	va_start	(args, text);
	char		temp[1024];

	if (vsnprintf (temp, sizeof (temp) - 1, text, args) < 0)
		temp [sizeof (temp) - 1] = 0;
	
	printf("%s in %.1f seconds\n", temp, (double) (finish - start) / 1000000.0);
}

#ifndef _STATS_H_
#define _STATS_H_

enum StatBuckets {
	statObjects = 0,
	statObjectsCreated,
	statObjectsSaved,
	statObjectsImported,
	statObjectsExported,
	statObjectsLoaded,
	statObjectsPurged,
	statObjectsDropped,
	statObjectsDeleted,
	statMsgIn,
	statMsgOut,
	statNetIn,
	statNetOut,
	statMax 
	};

#define M(bit)	(1 << bit)
static const int InterestingStats = -1 & ~( M(statNetIn) | M(statNetOut) );
#undef M

class Stats
{
public:
	Stats(void);
	~Stats(void);

	void			bump(StatBuckets bucket);
	void			snapshot(Stats* stats);
	void			computeDelta(Stats* stats);
	void			log(int mask);
	int				numberObjects(void);

	static int64	getTime(void);
	static void		logDelta(int64 start, int64 finish, const char* text, ...);
	static void		printDelta(int64 start, int64 finish, const char* text, ...);
	
	int64			startTime;
	int64			deltaTime;
	int				buckets[statMax];
	bool			change;
	bool			active;
};

#endif

Thread
Stats ClassJim Starkey4 Nov