[Tdg] some bugfixes to the memory pool / idle allocator classes

Graham Wakefield lists at grahamwakefield.net
Wed Feb 21 16:23:21 PST 2007


#ifndef INC_GLV_MEM_POOL_H
#define INC_GLV_MEM_POOL_H

/* From Alex's MemPool class */

/* example:

// Note self-reference in template class definition
// this makes each object have its own pool.

class TypeWithOwnMemPool : public MemPool<TypeWithOwnMemPool>
{
	private:
		unsigned int blah;
};

// To share a single pool between many classes,
// inherit from a shared template class.

class SharedMemPoolType
{
	private:
		unsigned int blah;
		unsigned int blah2;
};

class TypeWithSharedMemPool1 : public MemPool<SharedMemPoolType>
{
	private:
		unsigned int blah;
};

class TypeWithSharedMemPool2 : public MemPool<SharedMemPoolType>
{
	private:
		unsigned int blah;
		unsigned int blah2;
};

int main()
{
	TypeWithOwnMemPool::initMemPool(1);

	TypeWithOwnMemPool * m1 = new TypeWithOwnMemPool;
	TypeWithOwnMemPool * m2 = new TypeWithOwnMemPool;
	delete m1;
	delete m2;	
	
	TypeWithSharedMemPool1 * p1 = new TypeWithSharedMemPool1;
	TypeWithSharedMemPool2 * p2 = new TypeWithSharedMemPool2;
	delete p1;
	delete p2;
}

*/


#include <pthread.h>
#include <queue>
#include <map>
#include <stack>

// comment out this line if you don't want to use doug lea's malloc:
#include "../dlmalloc/malloc-2.8.3.h"

#define GLV_MEM_IDLE_DEBUG
#define GLV_MEM_POOL_DEBUG

#ifdef MALLOC_280_H
	#define glv_malloc	dlmalloc
	#define glv_free	dlfree
#else
	#define glv_malloc	malloc
	#define glv_free	free
#endif



namespace glv {

template <class T>
class MemPool
{
public:
	MemPool(){}
	void *						operator new(size_t num_bytes);
	void						operator delete (void *ptr, size_t bytes);
	
	static void *				pool_alloc(size_t num_bytes);
	static void					pool_free(void *ptr, size_t bytes);
	
	unsigned int				getMemPoolSize() { return cMemPool.size(); }
	unsigned int				getMemPoolItemSize() { return cMemPoolItemSize; }
	
	static void					initMemPool(unsigned int num_elements, size_t  
num_bytes = sizeof(T));
	static void					setMemPoolItemSize(size_t num_bytes);
	
protected:
	static std::stack<void *>	cMemPool;
	static unsigned int			cMemPoolItemSize;	// no. bytes
};

class MemIdle;

class MemIdleTask
{
friend class MemIdle;

public:
	MemIdleTask(size_t size = 0);
	MemIdleTask(void * ptr);
	bool			ready();
	void *			data();

protected:	
	bool			flag;
	void *			memory;
	size_t			size;
	
	
};

class MemIdle
{
public:
	
	static MemIdleTask * request(size_t num_bytes);
	static bool			 allocate(MemIdleTask * m);
	static MemIdleTask * free(void * ptr);
	
protected:

	static void		init();
	static void *	thread_alloc(void * arg);
	
	static bool		thread_initialized;	
	static std::queue<MemIdleTask *>	Q;

};



template <class T>
unsigned int			MemPool<T> :: cMemPoolItemSize = sizeof(T); // no.  
bytes, e.g. sizeof(double) * 8

template <class T>
std::stack<void *>		MemPool<T> :: cMemPool;

template <class T>
inline void * MemPool<T> :: operator new(size_t num_bytes)
{
	void * item;
	if(num_bytes > cMemPoolItemSize){
#ifdef GLV_MEM_POOL_DEBUG
		printf("malloc new MemPool element (element too big)\n");
#endif
		return glv_malloc(num_bytes);
	} else if (cMemPool.empty()){
#ifdef GLV_MEM_POOL_DEBUG
		printf("malloc new MemPool element (pool empty)\n");
#endif
		return glv_malloc(cMemPoolItemSize);
	} else {
#ifdef GLV_MEM_POOL_DEBUG
		printf("dequeue new MemPool element\n");
#endif
		item = cMemPool.top();
		cMemPool.pop();
		return item;
	}
}

template <class T>
void * MemPool<T> :: pool_alloc(size_t num_bytes)
{
	void * item;
	if(num_bytes > cMemPoolItemSize){
#ifdef GLV_MEM_POOL_DEBUG
		printf("malloc new MemPool element (element too big)\n");
#endif
		return glv_malloc(num_bytes);
	} else if (cMemPool.empty()){
#ifdef GLV_MEM_POOL_DEBUG
		printf("malloc new MemPool element (pool empty)\n");
#endif
		return glv_malloc(cMemPoolItemSize);
	} else {
#ifdef GLV_MEM_POOL_DEBUG
		printf("dequeue new MemPool element\n");
#endif
		item = cMemPool.top();
		cMemPool.pop();
		return item;
	}
}

template <class T>
inline void MemPool<T>::operator delete (void * ptr, size_t num_bytes)
{
	if(num_bytes > cMemPoolItemSize){
#ifdef GLV_MEM_POOL_DEBUG
	printf("MemPool free pointer\n");
#endif
		glv_free(ptr);
	} else {
#ifdef GLV_MEM_POOL_DEBUG
		printf("MemPool return to queue\n");
#endif
		cMemPool.push(ptr);
		ptr = NULL;
	}
}

template <class T>
void MemPool<T>::pool_free (void * ptr, size_t num_bytes)
{
	if(num_bytes > cMemPoolItemSize){
#ifdef GLV_MEM_POOL_DEBUG
	printf("MemPool free pointer\n");
#endif
		glv_free(ptr);
	} else {
#ifdef GLV_MEM_POOL_DEBUG
		printf("MemPool return to queue\n");
#endif
		cMemPool.push(ptr);
		ptr = NULL;
	}
}

template <class T>
void MemPool<T>::setMemPoolItemSize(size_t num_bytes)
{	
	if (num_bytes <= cMemPoolItemSize)
	{
		cMemPoolItemSize = num_bytes;
		return;
	}
	
	cMemPoolItemSize = num_bytes;
	
	// otherwise, empty pool:
	while (!cMemPool.empty())
	{
		void * item = cMemPool.top();
		cMemPool.pop();
		glv_free(item);
	}
}

template <class T>
void MemPool<T>::initMemPool(unsigned int num_elements, size_t  
num_bytes)
{
#ifdef GLV_MEM_POOL_DEBUG
		printf("MemPool pre allocate %i x %i = %.2fk\n", num_elements,  
num_bytes, num_elements * num_bytes / 1024.0);
#endif

	setMemPoolItemSize(num_bytes);
	
	// fill up the pool:
	while(cMemPool.size() < num_elements)
	{
		void * item = glv_malloc(cMemPoolItemSize);
		cMemPool.push(item);
	}
}

inline
MemIdleTask :: MemIdleTask(size_t size)
: size(size)
{	
	flag = false;
	memory = NULL;
};

inline
MemIdleTask :: MemIdleTask(void * ptr)
: memory(ptr)
{	
	flag = false;
	size = 0;
};

inline
bool MemIdleTask :: ready() { return flag; }

inline
void * MemIdleTask :: data() { return memory; }

bool						MemIdle :: thread_initialized = false;
std::queue<MemIdleTask *>	MemIdle :: Q;

MemIdleTask *	MemIdle :: request(size_t num_bytes)
{
	if (!thread_initialized) init();
	
	MemIdleTask * m = new MemIdleTask(num_bytes);
	
	Q.push(m);
	
	return m;
}


MemIdleTask * MemIdle :: free(void * ptr)
{
	MemIdleTask * m = new MemIdleTask(ptr);
	
	Q.push(m);
	
	return m;
}

void MemIdle :: init()
{
#ifdef GLV_MEM_IDLE_DEBUG			
	printf(">\t MemIdle thread: initialize\n");
#endif	
	thread_initialized = true;
	
	// create a low priority pthread to allocate the memory:
	pthread_t thread;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	
	// TODO: figure out how to set low priority
//	sched_param schedparam;
//	schedparam.sched_priority = 16;	// is this a low enough priority?
//	pthread_attr_setschedparam(&attr, &schedparam);

	pthread_create(&thread, &attr, thread_alloc, 0);
}

void * MemIdle :: thread_alloc(void * arg)
{
	while (thread_initialized)
	{		
		sleep(1);	// super lazy
		
		if (!Q.empty())
		{
			MemIdleTask * m = Q.front();
			
			printf(">\t MemIdle thread: %p %i %p\n", m, m->size, m->memory);
			
			Q.pop();
			
			if (m->size) {
				m->memory = (void *)glv_malloc(m->size);
				m->flag = true;
#ifdef GLV_MEM_IDLE_DEBUG			
				printf(">\t MemIdle thread: allocated %i bytes to %p at %p\n", m- 
 >size, m, m->memory);
#endif	
			} else {
#ifdef GLV_MEM_IDLE_DEBUG			
				printf(">\t MemIdle thread: free %p %p\n", m, m->memory);
#endif	
				glv_free(m->memory);
				m->memory = NULL;
				m->flag = true;
			}
		}
	}
}

} // namespace

#endif
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.create.ucsb.edu/pipermail/tdg/attachments/20070221/c39f5976/attachment-0002.html 


More information about the Tdg mailing list