"Dmitriy V'jukov" <dvyukov@[EMAIL PROTECTED]
> wrote in message
news:280c8b35-0fe0-403a-9a71-288ae5fd0bdd@[EMAIL PROTECTED]
> Chris M. Thomasson wrote:
>
>> There is a way to minimize the GUID scheme, but it requires two
sections
>> of
>> virtual memory which can be wasteful. It involves block sizes <= chunk
>> size
>> to be allocated from a separate memory pool than block sizes that are >
>> chunk size. The former can use the normal scheme of simple rounding up
>> and
>> subtracting to get chunk header... However, the latter would need to
use
>> the
>> GUID search algorithm.
>
> If object is bigger than 16 pages, I think it's perfectly Ok to spent
> 16 bytes on header.
> What is the point of huge headerless blocks?
But how could I efficiently intermingle large blocks and small blocks from
a
single reserved memory pool? Anyway, I don't think I was thinking clearly
when I wrote the following ****tion of my original message
"There is a way to minimize the GUID scheme, but it requires two sections
of
virtual memory which can be wasteful. It involves block sizes <= chunk
size
to be allocated from a separate memory pool than block sizes that are >
chunk size. The former can use the normal scheme of simple rounding up and
subtracting to get chunk header... However, the latter would need to use
the
GUID search algorithm."
I would not need to use the GUID search algorithm at all if I split the
reserved virtual memory address space into 2 sections and _strictly_
enforced it. For instance, I reserve 4 gigs of memory, and split it into
two
sections; one for allocations <= chunk size, and one for allocations >
chunk
size. But that wastes memory. What if the application only made small
allocations and wanted to use more than 2 gigs? Or if the application only
did large allocations and wanted to use more than 2 gigs? This scheme
would
allow me to get around the search algorithm by using the following
algorithm; pseudo-code:
__________________________________________________________________________
#define CACHE_LINE 128UL
#define PAGE_SIZE 4096UL
#define CHUNK_SIZE (PAGE_SIZE * 16UL)
#define RESERVE_SIZE 0xFFFFFFFFUL
#define LARGE_SIZE (RESERVE_SIZE / 2UL)
static unsigned char* reserved_mem = VirtualAlloc(RESERVE_SIZE);
static unsigned char* small_mem = reserved_mem;
static unsigned char* large_mem = small_mem + LARGE_SIZE;
struct header {
struct header* next;
struct header* prev;
per_thread* thread;
size_t size;
};
/* small chunks aligned on CHUNK_SIZE boundary! */
union chunk {
struct header header;
unsigned char pad[CACHE_LINE];
};
bool
is_mem_large(unsigned char* mem) {
if (mem < large_mem) {
return false;
}
return true;
}
union chunk*
chunk_from_mem(unsigned char* mem) {
union chunk* chunk;
if (! is_mem_large(mem)) {
chunk = (union chunk*)
((ALIGN(mem, CHUNK_SIZE) - sizeof(union chunk))
} else {
chunk = (union chunk*)(mem - sizeof(union chunk);
}
return chunk;
}
void free(void* mem) {
per_thread* const this_thread = pthread_getspecific(...);
union chunk* const chunk = chunk_from_mem(mem);
if (chunk->header.this.thread) {
if (chunk->header.this.thread == this_thread) {
per_thread_local_free(chunk, mem);
} else {
per_thread_remote_free(chunk, mem);
}
} else {
global_free(chunk);
}
}
__________________________________________________________________________
That would work fine, but it has limitations in that small chunks could
not
be allocated from the large chunk pool and vise-versa. However, if I used
the GUID search thing, then the entire reserved memory could be organized
into adjacent chunks and both small and large allocations could use the
same
pool. What am I missing here? I hope its not something ridiculously
simple!
Humm... Perhaps splitting the pool is not so bad. Humm...
;^/


|