Click here to Skip to main content
15,886,067 members
Articles / Programming Languages / C++

Testing distributed memory pools

Rate me:
Please Sign up or sign in to vote.
5.00/5 (8 votes)
20 Jun 2009CPOL7 min read 28.6K   799   30  
This article describes a simple approach and test results when creating distributed pools of objects for high-performance applications on a Multi-core PC.
#include "stdafx.h" 
#include "perf_counter.h"
#include "processor_pool.h"
#include "thread_pool.h"


#ifdef TEST_CONTENTION_COUNT
volatile long g_contention_count;
#endif

#if defined(TEST_PROCESSOR_POOL) || defined(TEST_SINGLE_POOL)
#pragma message("===== Using processor_pool namespace =====")
using namespace processor_pool;
#else
#pragma message("===== Using thread_pool namespace =====")
using namespace thread_pool;
#endif



HANDLE g_start_event;
volatile long g_stop_test; 

const int writer_test_iterations = 1000000;
const int number_of_writers = 4;
const int reader_test_iterations = 4000000;
const int number_of_readers = 4;

const int number_of_pools = 4;


#pragma warning(disable:4324)
class test_buffer
{
public:
	bool read(void)
	{
		return (m_checksum == checksum(m_buffer, sizeof(m_buffer)));
	}
	bool write(void)
	{
		if (m_checksum != checksum(m_buffer, sizeof(m_buffer)))
		{
			return false;
		}
		else
		{
			set_buffer();
			return true;
		}
	}
	test_buffer()
	{
		set_buffer();
	}
private:
	USHORT checksum( LPVOID data, int len )
	//
	// The function checksum came from http://ava.org.ua/?2&17&get=87&read=87
	//
	{
		ULONG sum = 0;
		USHORT * dp =  (USHORT *) data;
		USHORT sum_s;
		int words = len >> 1;
		while( words -- )  sum += * dp ++;
		if( len & 1 ) sum += *(UCHAR*) dp;
		sum   = (USHORT) sum + (sum >> 16) & 0xffff;
		sum_s = (USHORT) sum + (USHORT)(sum >> 16);
		return sum_s != 0xffff ? ~sum_s : sum_s;
	}
	void set_buffer(void)
	{
		for(int i = 0; i < sizeof(m_buffer)/sizeof(m_buffer[0]); i ++)
		{
			m_buffer[i] = rand();
		}
		m_checksum = checksum(m_buffer, sizeof(m_buffer));
	}
	enum {BUF_SIZE = 64};
	int m_buffer[BUF_SIZE];
	USHORT m_checksum;
};
#pragma warning(default:4324)


#if defined(TEST_SINGLE_POOL)
#pragma message(" Testing a singe pool Pool_t")
Pool_t<test_buffer, number_of_readers + number_of_writers> g_pool; 
#else
#pragma message(" Testing an array of pools Array_of_pools_t")
Array_of_pools_t<test_buffer, number_of_readers + number_of_writers, number_of_pools> g_pool; 
#endif


template <const int test_iteration>
class Test_worker{
public:
	HANDLE start(void)
	{
		::ResumeThread(m_handle);
		return m_handle;
	}
	double test_duration(void)
	{
		return m_perf_counter.get_duration();
	}
	LONGLONG test_iteration_done(void)
	{
		return m_perf_counter.get_counter();
	}
private:
	static DWORD WINAPI worker_proc(LPVOID lpParam)
	{
		Test_worker& worker = *reinterpret_cast<Test_worker*>(lpParam);

#if !defined(TEST_PROCESSOR_POOL) && !defined(TEST_SINGLE_POOL)
		worker.m_pool_index = g_pool.get_pool_index(); 
#endif

		::WaitForSingleObject(g_start_event, INFINITE );

		worker.m_perf_counter.start();
		int i;

		for (i = 0; i < test_iteration; i++)
		{
			if( false == worker.simulate_work() )
			{
				::RaiseException( STATUS_NONCONTINUABLE_EXCEPTION, 0, 0, 0);
 			}
			else
			{
			}

			if (TRUE == g_stop_test)
			{
				break;
			}
			else
			{
			}

		}
		
		worker.m_perf_counter.end();
		::InterlockedExchange(&g_stop_test, TRUE);
		worker.m_perf_counter.set_iteration_done(i);
		return 0;
	}

	virtual bool simulate_work(void)=0;

	HANDLE m_handle;
	Performance_counter_meter m_perf_counter;
	Test_worker & operator=( const Test_worker & ) {}
protected:
	Test_worker()
	{
		m_handle = ::CreateThread(NULL,0, worker_proc, (LPVOID)this, CREATE_SUSPENDED, NULL);
	}

	size_t m_pool_index;
};


class Writer: public Test_worker <writer_test_iterations>
{
#if defined(TEST_PROCESSOR_POOL) || defined(TEST_SINGLE_POOL)
		virtual bool simulate_work(void)
		{
			test_buffer* buffer = g_pool.pop();
			if (buffer && buffer->write())
			{
				g_pool.push(buffer);
				return true;
			}
			else
			{
				return false;
			}
		}
#else
		virtual bool simulate_work(void)
		{
			test_buffer* buffer = g_pool.pop(m_pool_index);
			if (buffer && buffer->write())
			{
				g_pool.push(buffer, m_pool_index);
				return true;
			}
			else
			{
				return false;
			}
		}
#endif
};

class Reader: public Test_worker <reader_test_iterations>
{
#if defined(TEST_PROCESSOR_POOL) || defined(TEST_SINGLE_POOL)
		virtual bool simulate_work(void)
		{
			test_buffer* buffer = g_pool.pop();
			if (buffer && buffer->read())
			{
				g_pool.push(buffer);
				return true;
			}
			else
			{
				return false;
			}
		}
#else
		virtual bool simulate_work(void)
		{
			test_buffer* buffer = g_pool.pop(m_pool_index);
			if (buffer && buffer->read())
			{
				g_pool.push(buffer, m_pool_index);
				return true;
			}
			else
			{
				return false;
			}
		}
#endif
};


int _tmain(int , _TCHAR*)
{
	g_start_event = ::CreateEvent(NULL,TRUE,FALSE,NULL);

	HANDLE threads[number_of_writers + number_of_readers];

	Writer* writer[number_of_writers];
	for (int i = 0; i < number_of_writers; i++)
	{
		writer[i] = new Writer();
		threads[i] = writer[i]->start();
	}

	Reader* reader[number_of_readers];
	for (int i = 0; i < number_of_readers; i++)
	{
		reader[i] = new Reader();
		threads[i + number_of_writers] = reader[i]->start();
	}

	::SetEvent(g_start_event);
	::WaitForMultipleObjects(sizeof(threads)/sizeof(threads[0]), threads, TRUE, INFINITE);

	for (int i = 0; i < number_of_readers; i++)
	{
		printf("reader iterations done | per operation(ms),%lld,%f\n",
			reader[i]->test_iteration_done(),
			1000*reader[i]->test_duration()/reader[i]->test_iteration_done());
	}

	for (int i = 0; i < number_of_writers; i++)
	{
		printf("writer iterations done | per operation(ms),%lld,%f\n",
			writer[i]->test_iteration_done(),
			1000*writer[i]->test_duration()/writer[i]->test_iteration_done());
	}

	return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions