Using GMemChunks
- From: Elliot Lee <sopwith redhat com>
- To: gtk-devel-list redhat com
- Subject: Using GMemChunks
- Date: Wed, 22 Jul 1998 02:49:59 -0400 (EDT)
I'm profiling memory usage in GNOME, and noticed that a lot of places
allocate fixed-size blocks of memory. For example, gdk_window_new and
gdk_window_foreign_new allocate tons (257 in testgnome using a repeatable
test pattern) of GdkWindowPrivate structures directly, using g_malloc().
How efficient is GMemChunk, and how much of a gain would be given by using
it in even just this specific example? Is there a better way?
<ramblings to partially answer the question>
A LOT of places seem to use 8-byte memory chunks. Would it be reasonable
to make a generic "extern GMemChunk *eight_byte_chunk;" in glib for use by
any routines that see fit? (Half the problem is that GTree nodes are 24
bytes, and there's possibly a lot of overhead there just in storing the
list of free chunks :-)
I've attached a program that I've been using to test, in case it's
helpful. It seems to indicate that GMemChunk is only useful for small
memchunks, but I'm not confident enough in the test program to be sure.
GMemChunk also seems slower in all cases.
Suggestions welcomed,
-- Elliot
Do you ever just feel thankful that you know me and have access to my
dementia? Explain. Be prepared to discuss in class.
/* Elliot's Wacky Memory Allocation Efficiency Tester */
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdio.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NITERS 65535
#define NITEMS 4096
#ifdef PROFILING_VERSION
#define NRUNS 10
#endif
int start_memused;
void start_memsizing(void)
{
struct mallinfo mi = mallinfo();
start_memused = mi.uordblks;
}
int end_memsizing(int chunksize)
{
struct mallinfo mi = mallinfo();
return (mi.uordblks - start_memused) - (chunksize * NITEMS);
}
void
print_timediff(struct timeval *starttime, struct timeval *endtime)
{
long long usecdiff;
usecdiff = endtime->tv_sec * 1000000 /* cvt to microseconds */;
usecdiff += endtime->tv_usec;
usecdiff -= starttime->tv_sec * 1000000 /* cvt to microseconds */;
usecdiff -= starttime->tv_usec;
printf("%lld usecs\n", usecdiff);
}
int docheck_memchunk(int chunksize)
{
gpointer array[NITEMS];
int i, n;
GMemChunk *mc;
#ifndef PROFILING_VERSION
start_memsizing();
#endif
mc = g_mem_chunk_new("Testme", chunksize, 1024, G_ALLOC_AND_FREE);
for(i = 0; i < NITEMS; i++)
array[i] = g_mem_chunk_alloc(mc);
for(i = 0; i < NITERS; i++) {
n = rand() % NITEMS;
if(array[n]) {
g_mem_chunk_free(mc, array[n]);
array[n] = NULL;
} else {
array[n] = g_mem_chunk_alloc(mc);
}
}
for(i = 0; i < NITEMS; i++)
if(!array[i]) array[i] = g_mem_chunk_alloc(mc);
#ifdef PROFILING_VERSION
for(i = 0; i < NITEMS; i++)
g_mem_chunk_free(mc, array[i]);
g_mem_chunk_destroy(mc);
#endif
#ifndef PROFILING_VERSION
g_print("memchunk diff with chunksize %d is %d\n",
chunksize, end_memsizing(chunksize));
#endif
return 0;
}
int docheck_malloc(int chunksize)
{
gpointer array[NITEMS];
int i, n;
#ifndef PROFILING_VERSION
start_memsizing();
#endif
for(i = 0; i < NITEMS; i++)
array[i] = g_malloc(chunksize);
for(i = 0; i < NITERS; i++) {
n = rand() % NITEMS;
if(array[n]) {
g_free(array[n]);
array[n] = NULL;
} else {
array[n] = g_malloc(chunksize);
}
}
for(i = 0; i < NITEMS; i++)
if(!array[i]) array[i] = g_malloc(chunksize);
#ifdef PROFILING_VERSION
for(i = 0; i < NITEMS; i++)
g_free(array[i]);
#endif
#ifndef PROFILING_VERSION
g_print("malloc diff with chunksize %d is %d\n",
chunksize,
end_memsizing(chunksize));
#endif
return 0;
}
void docheck(int chunksize)
{
#ifdef PROFILING_VERSION
int i;
struct timeval starttime, endtime;
#else
int pid, st;
#endif
#ifdef PROFILING_VERSION
gettimeofday(&starttime, NULL);
for(i = 0; i < NRUNS; i++) {
#endif
/* We have to fork so we can get accurate alloc difference */
#ifdef PROFILING_VERSION
docheck_memchunk(chunksize);
#else
pid = fork();
if(pid)
waitpid(pid, &st, 0);
else {
docheck_memchunk(chunksize);
fflush(stdout);
_exit(0);
}
#endif
#ifdef PROFILING_VERSION
}
gettimeofday(&endtime, NULL);
printf("memchunk run on chunksize %d took ", chunksize);
print_timediff(&starttime, &endtime);
fflush(stdout);
gettimeofday(&starttime, NULL);
for(i = 0; i < NRUNS; i++) {
#endif
#ifdef PROFILING_VERSION
docheck_malloc(chunksize);
#else
pid = fork();
if(pid)
waitpid(pid, &st, 0);
else {
docheck_malloc(chunksize);
fflush(stdout);
_exit(0);
}
#endif
#ifdef PROFILING_VERSION
}
gettimeofday(&endtime, NULL);
printf("malloc run on chunksize %d took ", chunksize);
print_timediff(&starttime, &endtime);
printf("\n");
fflush(stdout);
#endif
}
int main(int argc, char *argv[])
{
int i;
if(argc > 1)
docheck(atoi(argv[1]));
else
for(i = 8; i < 256; i = (int)((double)i * 1.5))
docheck(i);
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]