/**********************************************************************
 * Copyright (c) 2005, 2007 Scapa Technologies Limited and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: perfcalc.c,v 1.4 2007/05/23 21:19:37 dnsmith Exp $
 * 
 * Contributors: 
 * Scapa Technologies Limited - Initial API and implementation
 **********************************************************************/

/* bugzilla 186503 - only include windows.h for WIN32 builds */
#if defined(WIN32) && !defined(_WIN64)
#include <windows.h>
#endif
#include "perfcalc.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "hashtable.h"
#include "perfconstants.h"

static HashTable* XHasht;
static HashTable* YHasht;
static HashTable* BHasht;

static ACCURACY = 1;

double round(double num,int numplaces)
{
	num = num * pow(10,numplaces);
	num = (double)((int) (num / 1));
	num = num / pow(10,numplaces); 
	return num;
}

void createValueTables()
{
	XHasht = tableCreate();
	YHasht = tableCreate();
	BHasht = tableCreate();
}

void freeValueTables()
{
	tableDelete(XHasht);
	tableDelete(YHasht);
	tableDelete(BHasht);
}

void getPERF_100NSEC_MULTI_TIMER (char* output, char* key, PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_COUNTER_DEFINITION PerfCntr2 ,PPERF_DATA_BLOCK PerfData)
{
	XINT64 X1,Y1,X0,Y0,B1;
	double result;
	XDOUBLE tmp1, tmp2;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	Y1 = PerfData->PerfTime100nSec.QuadPart;
	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	B1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	tmp1 = (XDOUBLE)(X1 - X0);
	tmp2 = (XDOUBLE)(Y1 - Y0);

	result = 100*(tmp1/tmp2)/B1;

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, (XINT64) X1);
	tablePut(YHasht, key, (XINT64) Y1);
}

void getPERF_100NSEC_MULTI_TIMER_INV (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_COUNTER_DEFINITION PerfCntr2, PPERF_DATA_BLOCK PerfData)
{
	XINT64 X1,Y1,X0,Y0,B1;
	double result;
	XDOUBLE tmp1, tmp2;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	Y1 = PerfData->PerfTime100nSec.QuadPart;
	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	B1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	tmp1 = (XDOUBLE)(X1 - X0);
	tmp2 = (XDOUBLE)(Y1 - Y0);

	result = 100*(B1 - (tmp1/tmp2))/B1;

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, (XINT64) X1);
	tablePut(YHasht, key, (XINT64) Y1);
}

void getPERF_100NSEC_TIMER (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData)
{
	
	XINT64 X1,Y1,X0,Y0;
	double result;
	XDOUBLE tmp1, tmp2;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	Y1 = PerfData->PerfTime100nSec.QuadPart;

	tmp1 = (XDOUBLE)(X1-X0);
	tmp2 = (XDOUBLE)(Y1-Y0);

	result = (double) (100*(tmp1/tmp2));

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht,key,X1);
	tablePut(YHasht,key,Y1);
}

void getPERF_100NSEC_TIMER_INV (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData )
{
	XINT64 X1,Y1,X0,Y0;
	double result;
	XDOUBLE tmp1, tmp2;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	Y1 = PerfData->PerfTime100nSec.QuadPart;

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	tmp1 = (XDOUBLE)(X1-X0);
	tmp2 = (XDOUBLE)(Y1-Y0);

	result = (double) (100 * (1 - (tmp1/tmp2) ));

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht,key,X1);
	tablePut(YHasht,key,Y1);
}

void getPERF_AVERAGE_BULK (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_COUNTER_DEFINITION PerfCntr2) 
{
	DWORD X1,B1,X0,B0;
	double result;
	XDOUBLE tmp1, tmp2;

	X0 = (DWORD) tableGet(XHasht,key);
	B0 = (DWORD) tableGet(BHasht,key);
	
	X1 = *(DWORD*)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	B1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);
	
	tmp2 = (XDOUBLE) (B1 - B0);
	if (tmp2 == 0)
	{
		result = 0;
	}
	else
	{
		tmp1 = (XDOUBLE) (X1 - X0);
		result = (double)(tmp1/tmp2);
	}

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht,key,X1);
	tablePut(BHasht,key,B1);
}

void getPERF_AVERAGE_TIMER (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_COUNTER_DEFINITION PerfCntr2,PPERF_DATA_BLOCK PerfData) 
{
	DWORD X1,B1,X0,B0;
	XINT64 TB;
	double result;
	XDOUBLE tmp1, tmp2;
	
	// Get Previous Data
	X0 = (DWORD) tableGet(XHasht,key);
	B0 = (DWORD) tableGet(BHasht,key);

	// Get PerfFreq...
	TB = PerfData->PerfFreq.QuadPart;

	X1 = *(DWORD*)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	B1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);
	
	tmp2 = (XDOUBLE) (B1 - B0);

	if (tmp2 == 0)
	{
		result = 0;
	}
	else
	{
		tmp1 = (XDOUBLE) (X1-X0);
		result = (double)((tmp1/TB)/(tmp2));
	}

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, (XINT64) X1);
	tablePut(BHasht, key, (XINT64) B1);
}

void getPERF_COUNTER_BULK_COUNT (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 X1,X0,TB,Y1,Y0;
	double result;
	XDOUBLE tmp1, tmp2;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	TB = PerfData->PerfFreq.QuadPart;
	Y1 = PerfData->PerfTime.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (tmp1/(tmp2/TB));

	sprintf(output,"%f",result);

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}

void getPERF_COUNTER_COUNTER (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 TB, Y1,Y0;
	double result;
	DWORD X1, X0;
	XDOUBLE tmp1, tmp2;

	X0 = (DWORD)  tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime.QuadPart;
	TB = PerfData->PerfFreq.QuadPart;

	tmp1 = (XDOUBLE)(X1-X0);
	tmp2 = (XDOUBLE)(Y1-Y0);
	
	result = (double) (tmp1/(tmp2/TB));

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}

void getPERF_COUNTER_DELTA (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
	DWORD X1,X0;
	double result;

	// Get Previous Data
	X0 = (DWORD) tableGet(XHasht,key);

	X1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	result = (double) (X1-X0);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, (XINT64) X1);
}

void getPERF_COUNTER_LARGE_DELTA (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
	XINT64 X1,X0;
	double result;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	result = (double) (X1-X0);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, (XINT64) X1);
}

void getPERF_COUNTER_LARGE_QUEUELEN_TYPE (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData)
{
	XINT64 X1,Y1;
	XDOUBLE tmp1, tmp2;
	XINT64 X0, Y0;
	double result;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime.QuadPart;

	tmp1 = (XDOUBLE)(X1 - X0);
	tmp2 = (XDOUBLE)(Y1 - Y0);

	result = (double) (tmp1/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht,key,X0);
	tablePut(YHasht,key,Y0);
}

void getPERF_COUNTER_LARGE_RAWCOUNT (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr)
{
	double result;
	XINT64 tmp;

	tmp = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	result = (double) tmp;

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);
}

void getPERF_COUNTER_LARGE_RAWCOUNT_HEX (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
	double result;
	XINT64 tmp;

	tmp = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	result = (double) tmp;

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);
}

void getPERF_COUNTER_MULTI_TIMER (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_COUNTER_DEFINITION PerfCntr2, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 X1,X0,Y1,Y0,TB,B1;
	XDOUBLE tmp1, tmp2;
	double result;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);
	
	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	B1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	Y1 = PerfData->PerfTime.QuadPart;
	TB = PerfData->PerfFreq.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double)(100*(tmp1/(tmp2/TB))/B1);

	result = round(result,ACCURACY);

	sprintf(output,"%I64Ld",result);


	tablePut(XHasht, key, X1);
	tablePut(YHasht, key, Y1);
}

void getPERF_COUNTER_MULTI_TIMER_INV (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_COUNTER_DEFINITION PerfCntr2, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 X1,X0,Y1,Y0,TB,B1;
	XDOUBLE tmp1, tmp2;
	double result;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);
	
	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	B1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	Y1 = PerfData->PerfTime.QuadPart;
	TB = PerfData->PerfFreq.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double)(100*(1-(tmp1/(tmp2/TB)))/B1);

	result = round(result,ACCURACY);

	sprintf(output,"%I64Ld",result);

	tablePut(XHasht, key, X1);
	tablePut(YHasht, key, Y1);
}


void getPERF_COUNTER_NODATA (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
	sprintf(output,"0");
}


void getPERF_COUNTER_QUEUELEN_TYPE (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 Y1,X1,X0,Y0;
	double result;
	XDOUBLE tmp1, tmp2;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);
		
	X1 = *(DWORD*)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (tmp1/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, (XINT64) X1);
	tablePut(YHasht, key, (XINT64) Y1);
}

void getPERF_COUNTER_RAWCOUNT (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
	double result;
	DWORD tmp;

	tmp = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	result = tmp;

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);
}


void getPERF_COUNTER_RAWCOUNT_HEX (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
	double result;
	DWORD tmp;

	tmp = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	result = tmp;

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);
}

void getPERF_COUNTER_TEXT (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr) 
{
//	DWORD len;
//	wchar_t* result;

//	len = *(DWORD*)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	//TODO STILL
}

void getPERF_COUNTER_TIMER (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 Y1, TB, X1,X0,Y0;
	double result;
	XDOUBLE tmp1,tmp2;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(DWORD*)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime.QuadPart;
	TB = PerfData->PerfFreq.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (100*(tmp1/tmp2));

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, X1);
	tablePut(YHasht, key, Y1);
}

void getPERF_COUNTER_TIMER_INV (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData) 
{
	XINT64 Y1, TB, X1,X0,Y0;
	double result;
	XDOUBLE tmp1,tmp2;

	// Get Previous Data
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(DWORD*)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime.QuadPart;
	TB = PerfData->PerfFreq.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (100*(1-(tmp1/tmp2)));

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);

	tablePut(XHasht, key, X1);
	tablePut(YHasht, key, Y1);
}

void getPERF_ELAPSED_TIME (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr, PPERF_DATA_BLOCK PerfData, PPERF_OBJECT_TYPE PerfObj) 
{
	XINT64 X1, Y1, TB;
	double result;

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	Y1 = PerfObj->PerfTime.QuadPart;

	TB = PerfObj->PerfFreq.QuadPart;

	result = (double) ((XDOUBLE)(Y1-X1))/((XDOUBLE) TB);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);
}

void getPERF_RAW_FRACTION (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_COUNTER_DEFINITION PerfCntr2)
{
	DWORD X1, B1;
	double result;

	X1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	B1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	if (B1 > 0)
	{
		result = 100*(((double) X1) / ((double) B1));
	
		result = round(result,ACCURACY);

		sprintf(output,"%f%c",result,'\0');		
	}
}

void getPERF_SAMPLE_COUNTER (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_COUNTER_DEFINITION PerfCntr2) 
{
	DWORD X1, B1, X0, B0;
	XDOUBLE tmp1, tmp2;
	double result;

	X0 = (DWORD) tableGet(XHasht,key);
	B0 = (DWORD) tableGet(BHasht,key);

	X1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	B1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	tmp2 = (XDOUBLE)(B1 - B0);

	if ((B1 > 0) && (tmp2 !=0))
	{
		tmp1 = (XDOUBLE)(X1 - X0);
		result = (double)(tmp1/tmp2);
	}
	else
	{
		result = 0;
	}

	result = round(result,ACCURACY);
	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(BHasht,key,(XINT64) B1);
}

void getPERF_SAMPLE_FRACTION (char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_COUNTER_DEFINITION PerfCntr2) 
{
	DWORD X1, B1, X0, B0;
	XDOUBLE tmp1, tmp2;
	double result;

	X0 = (DWORD) tableGet(XHasht,key);
	B0 = (DWORD) tableGet(BHasht,key);

	X1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

	B1 = *(DWORD*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	tmp2 = (XDOUBLE)(B1 - B0);
	if ((B1 > 0) && (tmp2 !=0))
	{
		tmp1 = (XDOUBLE)(X1 - X0);
		result = (double)(100*tmp1/tmp2);
	}
	else
	{
		result = 0;
	}

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(BHasht,key,(XINT64) B1);
}

void getPERF_OBJ_TIME_TIMER(char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_DATA_BLOCK PerfData)
{
	double result;
	XDOUBLE tmp1, tmp2;
	XINT64 X1, X0, Y1, Y0;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime.QuadPart;

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (tmp1/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}

void getPERF_PRECISION_100NS_TIMER(char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_COUNTER_DEFINITION PerfCntr2,PPERF_DATA_BLOCK PerfData)
{
	double result;
	XDOUBLE tmp1, tmp2;
	XINT64 X1, X0, Y1, Y0;

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	// Precision stored time in next counter
	Y1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (100*tmp1/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}

// THIS IN PARTICULAR HAS NOT BEEN TESTED - I AM NOT 100% SURE YET.
void getPERF_PRECISION_OBJECT_TIMER(char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr,PPERF_COUNTER_DEFINITION PerfCntr2, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_DATA_BLOCK PerfData)
{
	double result;
	XDOUBLE tmp1, tmp2;
	XINT64 X1, X0, Y1, Y0, TB;
	TB = 1;

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);
	TB = PerfData->PerfFreq.QuadPart;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) ((TB*tmp1)/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}

void getPERF_PRECISION_SYSTEM_TIMER(char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr,PPERF_COUNTER_DEFINITION PerfCntr2, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_DATA_BLOCK PerfData)
{
	double result;
	XDOUBLE tmp1, tmp2;
	XINT64 X1, X0, Y1, Y0;

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr2->CounterOffset);
	
	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);

	result = (double) (100*tmp1/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}

void getPERF_COUNTER_100NS_QUEUELEN_TYPE(char* output, char* key,PPERF_COUNTER_BLOCK PtrToCntr, PPERF_COUNTER_DEFINITION PerfCntr,PPERF_DATA_BLOCK PerfData)
{
	double result;
	XDOUBLE tmp1, tmp2;
	XINT64 X1, X0, Y1, Y0;

	X1 = *(XINT64*) ((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
	Y1 = PerfData->PerfTime100nSec.QuadPart;

	X0 = (XINT64) tableGet(XHasht,key);
	Y0 = (XINT64) tableGet(YHasht,key);

	tmp1 = (XDOUBLE) (X1 - X0);
	tmp2 = (XDOUBLE) (Y1 - Y0);
	
	// The MSDN Docs say this should be tmp2/tmp1 but the results that generates are not at all plausible...
	// These results also match perfmon.

	result = (double) (tmp1/tmp2);

	result = round(result,ACCURACY);

	sprintf(output,"%f",result);		

	tablePut(XHasht,key,(XINT64) X1);
	tablePut(YHasht,key,(XINT64) Y1);
}
