/******************************************************************************
 *                                                                         
 *               (C) COPYRIGHT Pacific MindWorks, Inc. 2001-2005
 *                          All rights reserved.
 *
 *****************************************************************************/

#ifndef __NTLPERFMON_INCLUDED
#define __NTLPERFMON_INCLUDED

#ifndef NTL_NO_PERFMON

#include <atlperf.h>


///////////////////////////////////////////////////////////////////////////////
//
//	CDriverPerformanceObject
//
class CDriverPerformanceObject
	: public CPerfObject
{
public:
	HRESULT Initialize()
	{
		return m_critSec.Init();
	}

	HRESULT Close()
	{
		return m_critSec.Term();
	}

public:
	DECLARE_PERF_OBJECT(CDriverPerformanceObject, 1, "IVI Driver", "IVI driver performance object", -1);

	BEGIN_COUNTER_MAP(CDriverPerformanceObject)
		DEFINE_COUNTER(m_nTotalMethodCalls, "Method Calls", "Total number of method calls", PERF_COUNTER_RAWCOUNT, 0)
		DEFINE_COUNTER(m_nTotalMethodCalls, "Method Calls/Sec", "Number of method calls per second", PERF_COUNTER_COUNTER, 0)
		DEFINE_COUNTER(m_nTotalMethodExecutionTime, "Method Average Execution Time", "Average execution time per method call", PERF_AVERAGE_TIMER, 0)
		DEFINE_COUNTER(m_nTotalMethodCalls, "N/A", "N/A", PERF_AVERAGE_BASE, 0)

		DEFINE_COUNTER(m_nTotalIOCalls, "I/O Operations", "Total number of I/O operations", PERF_COUNTER_RAWCOUNT, 0)
		DEFINE_COUNTER(m_nTotalIOCalls, "I/O Operations/Sec", "Number of I/O operations per second", PERF_COUNTER_COUNTER, 0)
		DEFINE_COUNTER(m_nTotalIOCallExecutionTime, "I/O Operation Average Execution Time", "Average execution time per I/O operation", PERF_AVERAGE_TIMER, 0)
		DEFINE_COUNTER(m_nTotalIOCalls, "N/A", "N/A", PERF_AVERAGE_BASE, 0)

		DEFINE_COUNTER(m_nTotalIOBytes, "I/O Bytes Transmitted", "Total number of I/O bytes transmitted", PERF_COUNTER_RAWCOUNT, 0)
		DEFINE_COUNTER(m_nTotalIOBytes, "I/O Bytes Transmitted/Sec", "Number of I/O bytes transmitted per second", PERF_COUNTER_COUNTER, 0)
		DEFINE_COUNTER(m_nTotalIOCallExecutionTime, "I/O Byte Average Transmission TIme", "Average execution time per I/O byte transmitted", PERF_AVERAGE_TIMER, 0)
		DEFINE_COUNTER(m_nTotalIOBytes, "N/A", "N/A", PERF_AVERAGE_BASE, 0)

		DEFINE_COUNTER(m_nTotalIOErrors, "I/O Errors", "Total number of errors", PERF_COUNTER_RAWCOUNT, 0)
		DEFINE_COUNTER(m_nTotalIOErrors, "I/O Errors /Sec", "Number of I/O errors per second", PERF_COUNTER_COUNTER, 0)
		DEFINE_COUNTER(m_nTotalIOErrors, "I/O Error Percentage", "Percentage of I/O operations resulting in an error.", PERF_RAW_FRACTION, 0)
		DEFINE_COUNTER(m_nTotalIOCalls, "N/A", "N/A", PERF_RAW_BASE, 0)

		DEFINE_COUNTER(m_nTotalCachedPropertyCallCount, "Cache Read/Write Attempts", "Total number of cached property reads/writes.", PERF_COUNTER_RAWCOUNT, 0)
		DEFINE_COUNTER(m_nCacheHitCount, "Cache Hits/sec", "Number of cache hits per second.", PERF_COUNTER_COUNTER, 0)
		DEFINE_COUNTER(m_nCacheHitCount, "Cache Hit Ratio", "Ratio of cache hits to total cached property read/writes.", PERF_RAW_FRACTION, 0)
		DEFINE_COUNTER(m_nTotalCachedPropertyCallCount, "N/A", "N/A", PERF_RAW_BASE, 0)

		//DEFINE_COUNTER(m_nStart, "Time elapsed", "Time elapsed", PERF_ELAPSED_TIME, 0)
	END_COUNTER_MAP()

	ULONG m_nTotalMethodCalls;
	ULONG m_nTotalMethodExecutionTime;

	ULONG m_nTotalIOCalls;
	ULONG m_nTotalIOCallExecutionTime;

	ULONG m_nTotalIOBytes;

	ULONG m_nTotalIOErrors;

	ULONG m_nCacheHitCount;
	ULONG m_nTotalCachedPropertyCallCount;

	ULONGLONG m_nStart;

private:
	CComCriticalSection m_critSec;

public:

	// Method call statistics
	void IncrementMethodCallCount(LONG lCount = 1)
	{
		m_critSec.Lock();

		m_nTotalMethodCalls += lCount;

		m_critSec.Unlock();
	}

	// I/O call statistics
	void IncrementIOCallCount(LONG lCount = 1)
	{
		m_critSec.Lock();

		m_nTotalIOCalls += lCount;

		m_critSec.Unlock();
	}

	// I/O bytes statistics
	void IncrementIOByteCount(LONG lCount = 1)
	{
		m_critSec.Lock();

		m_nTotalIOBytes += lCount;

		m_critSec.Unlock();
	}

	// I/O error statistics
	void IncrementIOErrors(LONG lCount = 1)
	{
		m_critSec.Lock();

		m_nTotalIOErrors += lCount;

		m_critSec.Unlock();
	}

	// State-caching statistics
	void IncrementCachedPropertyCallCount(LONG lCount = 1)
	{
		m_critSec.Lock();

		m_nTotalCachedPropertyCallCount += lCount;

		m_critSec.Unlock();
	}

	void IncrementCacheHitCount(LONG lCount = 1)
	{
		m_critSec.Lock();

		m_nCacheHitCount += lCount;

		m_critSec.Unlock();
	}
};

///////////////////////////////////////////////////////////////////////////////
//
//	CDriverPerformanceObjectManager
//

class CDriverPerformanceObjectManager
	: public CPerfMon
{
public:

#define Perf_DriverPerformanceObjectManager _T("Perf_DriverPerformanceObjectManager")

   BEGIN_PERF_MAP(Perf_DriverPerformanceObjectManager)
      CHAIN_PERF_OBJECT(CDriverPerformanceObject)
   END_PERF_MAP()
};

PERFREG_ENTRY(CDriverPerformanceObjectManager);


///////////////////////////////////////////////////////////////////////////////
//
//	CPerfMonManager
//

class CPerfMonManager
{
public:
	CPerfMonManager()
		: m_pDriverPerformanceObject(NULL)
	{}

	HRESULT InitializePerfMonManager(const CString& strDriverIdentifier, const CString& strResourceDescriptor);		// Used to initialize owner of perf object 
	HRESULT InitializePerfMonManager(DWORD dwPerfObjectInstanceID, const CString& strPerfObjectInstanceName);		// Used to initialize non-owner of perf object
	HRESULT ClosePerfMonManager();

	DWORD GetPerformanceObjectInstanceID() { return m_pDriverPerformanceObject->m_dwInstance; }
	CString GetPerformanceObjectInstanceName() { return m_strPerfObjectInstanceName; }

protected:
	HRESULT InitializePerformanceObjectManager(DWORD dwPerfObjectInstanceID, const CString& strPerfObjectInstanceName);

public:
	// Method call statistics
	void IncrementMethodCallCount(LONG lCount = 1) { return m_pDriverPerformanceObject->IncrementMethodCallCount(lCount); }

	// I/O call statistics
	void IncrementIOCallCount(LONG lCount = 1) { return m_pDriverPerformanceObject->IncrementIOCallCount(lCount); }

	// I/O bytes statistics
	void IncrementIOByteCount(LONG lCount = 1) { return m_pDriverPerformanceObject->IncrementIOByteCount(lCount); }

	// I/O error statistics
	void IncrementIOErrors(LONG lCount = 1) { return m_pDriverPerformanceObject->IncrementIOErrors(lCount); }

	// State-caching statistics
	void IncrementCachedPropertyCallCount(LONG lCount = 1) { return m_pDriverPerformanceObject->IncrementCachedPropertyCallCount(lCount); }
	void IncrementCacheHitCount(LONG lCount = 1) { return m_pDriverPerformanceObject->IncrementCacheHitCount(lCount); }

private:
	CString m_strPerfObjectInstanceName;
	CDriverPerformanceObjectManager m_driverPerformanceObjectManager;
	CDriverPerformanceObject* m_pDriverPerformanceObject;

	bool m_bOwnPerfObject;
};

inline 	HRESULT CPerfMonManager::InitializePerfMonManager(const CString& strDriverIdentifier, const CString& strResourceDescriptor)
{
	HRESULT hr = S_OK;

	m_bOwnPerfObject = true;
	hr = m_driverPerformanceObjectManager.Initialize();
	if (SUCCEEDED(hr))
	{
		CPerfLock lock(&m_driverPerformanceObjectManager);
		hr = lock.GetStatus();
		if (SUCCEEDED(hr))
		{
			// Format for instance name is <DriverIdentifier>(<resource descriptor>)
			m_strPerfObjectInstanceName = strDriverIdentifier + " (" + strResourceDescriptor + ")";
			hr = m_driverPerformanceObjectManager.CreateInstanceByName<CDriverPerformanceObject>(CT2W(m_strPerfObjectInstanceName), &m_pDriverPerformanceObject);
			if (SUCCEEDED(hr))
			{
				hr = m_pDriverPerformanceObject->Initialize();
			}
		}
	}

	return hr;
}

inline HRESULT CPerfMonManager::InitializePerfMonManager(DWORD dwPerfObjectInstanceID, const CString& strPerfObjectInstanceName)
{
	HRESULT hr = S_OK;

	m_bOwnPerfObject = false;
	hr = m_driverPerformanceObjectManager.Initialize();
	if (SUCCEEDED(hr))
	{
		CPerfLock lock(&m_driverPerformanceObjectManager);
		hr = lock.GetStatus();
		if (SUCCEEDED(hr))
		{
			hr = m_driverPerformanceObjectManager.CreateInstance<CDriverPerformanceObject>(dwPerfObjectInstanceID, CT2W(strPerfObjectInstanceName), &m_pDriverPerformanceObject);
		}
	}

	return hr;
}

inline HRESULT CPerfMonManager::ClosePerfMonManager()
{
	// NOTE: Close must be called on performance object BEFORE Uninitialize is called on the performance object manager
	if (m_bOwnPerfObject)
	{
		m_pDriverPerformanceObject->Close();
	}
	m_pDriverPerformanceObject = NULL;

	m_driverPerformanceObjectManager.UnInitialize();

	return S_OK;
}

#else

///////////////////////////////////////////////////////////////////////////////
//
//	CPerfMonManager
//

class CPerfMonManager
{
public:
	CPerfMonManager() {}

	// Used to initialize owner of perf object 
	HRESULT InitializePerfMonManager(const CString& strDriverIdentifier, const CString& strResourceDescriptor)
	{
		NTL_UNUSED(strDriverIdentifier);
		NTL_UNUSED(strResourceDescriptor);

		return S_OK;
	}

	// Used to initialize non-owner of perf object
	HRESULT InitializePerfMonManager(DWORD dwPerfObjectInstanceID, const CString& strPerfObjectInstanceName)
	{
		NTL_UNUSED(dwPerfObjectInstanceID);
		NTL_UNUSED(strPerfObjectInstanceName);

		return S_OK;
	}

	HRESULT ClosePerfMonManager() { return S_OK; }

	DWORD GetPerformanceObjectInstanceID() { return 0; }
	CString GetPerformanceObjectInstanceName() { return _T(""); }

protected:
	HRESULT InitializePerformanceObjectManager(DWORD dwPerfObjectInstanceID, const CString& strPerfObjectInstanceName)
	{
		NTL_UNUSED(dwPerfObjectInstanceID);
		NTL_UNUSED(strPerfObjectInstanceName);

		return S_OK;
	}

public:
	// Method call statistics
	void IncrementMethodCallCount(LONG lCount = 1)
	{
		NTL_UNUSED(lCount);
	}

	// I/O call statistics
	void IncrementIOCallCount(LONG lCount = 1)
	{
		NTL_UNUSED(lCount);
	}

	// I/O bytes statistics
	void IncrementIOByteCount(LONG lCount = 1)
	{
		NTL_UNUSED(lCount);
	}

	// I/O error statistics
	void IncrementIOErrors(LONG lCount = 1)
	{
		NTL_UNUSED(lCount);
	}

	// State-caching statistics
	void IncrementCachedPropertyCallCount(LONG lCount = 1)
	{
		NTL_UNUSED(lCount);
	}
	
	void IncrementCacheHitCount(LONG lCount = 1)
	{
		NTL_UNUSED(lCount);
	}
};

#endif // NTL_NO_PERFMON

#endif // __NTLPERFMON_INCLUDED