Re: Efficient per-class allocator
On Oct 25, 12:13 pm, Lance Diduck <lancedid...@nyc.rr.com> wrote:
The answer is going to depend a lot oon the answers to :
1) is create() called by more than one thread?
no
2) is delete is called in the same thread that called create()?
yes
3) do you need to trim excess capacity or not? ( recall the space/
speed tradeoff -- any solution that is going to be faster is going to
take up more memory from the heap)
not sure
4) how portable does this have to be?
only one platform
5) do the members of Foo also allocate memory?
possibly
6) does Foo have a trivial destructor?
no
7) is this for shared memory, or process specific?
no
8) will it be used in an STL container?
no
Page 570 of Stroustrup's The C++ Programming Language (special
edition)
contains some code that serves my purpose. Page 472 of the second
edition also has some code. Combining the code from the two editions
yields a workable solution. In the following code:
test_x(1000 * 1000 * 10) takes 50 / 70 seconds
test_y(1000 * 1000 * 10) takes 310 / 70 seconds
test_func(1000 * 1000 * 10) takes 7 / 70 seconds
Therefore test_x (which uses a per-class allocator)
is an order of magnitude faster than test_y (which uses
the built-in operator new and delete. The function
test_x is not quite as fast as the "do nothing"
function test_func() but it is satisfactory for my
purposes.
What follows is the code:
#include "../../2006/nogc2/global.hh"
class Pool
{
struct Link
{
Link* next;
};
struct Chunk
{
enum { size = 8 * 1024 - 16 };
char mem[size];
Chunk* next;
};
Chunk* chunks;
const unsigned int esize;
Link* head;
Pool(Pool&);
void operator= (Pool&);
void grow();
public:
Pool(unsigned int n);
~Pool();
void* alloc();
void free(void* b);
};
void* Pool::alloc()
{
if (head == 0)
{
grow();
}
Link* p = head;
head = p->next;
return p;
}
void Pool::free(void* b)
{
Link* p = static_cast<Link*>(b);
p->next = head;
head = p;
}
Pool::Pool(unsigned int sz) : esize(sz<sizeof(Link)? sizeof(Link) :
sz)
{
head = 0;
chunks = 0;
}
Pool::~Pool()
{
Chunk* n = chunks;
while (n != 0)
{
Chunk* p = n;
n = n->next;
delete p;
}
}
void Pool::grow()
{
Chunk* n = new Chunk();
n->next = chunks;
chunks = n;
const int nelem = Chunk::size / esize;
char* start = n->mem;
char* last = start + (nelem - 1) * esize;
for (char* p = start; p<last; p+=esize)
{
(reinterpret_cast<Link*>(p))->next = reinterpret_cast<Link*>(p
+esize);
}
(reinterpret_cast<Link*>(last))->next = 0;
head = reinterpret_cast<Link*>(start);
}
class X
{
int data;
static Pool pool;
public:
void* operator new(size_t) { return pool.alloc(); }
void operator delete(void* p) { pool.free(p); }
};
class Y
{
int data;
};
Pool X::pool(sizeof(X));
extern void test_x(int len);
extern void test_y(int len);
extern void test_func(int len);
extern void func();
int main()
{
allegro_init_first_windowed(640,480);
const int len = 1000 * 1000 * 10;
retrace_count = 0;
test_x(len);
int time_x = retrace_count;
retrace_count = 0;
test_y(len);
int time_y = retrace_count;
retrace_count = 0;
test_func(len);
int time_func = retrace_count;
textout(screen,font,(string() + "time_x=" +
time_x).const_char_star(),0,0,allegro_col_white);
textout(screen,font,(string() + "time_y=" +
time_y).const_char_star(),0,8,allegro_col_white);
textout(screen,font,(string() + "time_func=" +
time_func).const_char_star(),0,16,allegro_col_white);
readkey();
return EXIT_SUCCESS;
}
END_OF_MAIN();
void test_x(const int ILEN)
{
for (int i=0; i<ILEN; i++)
{
X* x = new X();
delete x;
}
}
void test_y(const int ILEN)
{
for (int i=0; i<ILEN; i++)
{
Y* y = new Y();
delete y;
}
}
void test_func(const int ILEN)
{
for (int i=0; i<ILEN; i++)
{
func();
func();
}
}
void func()
{
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]