[cairo-skiplist] Group levels two-by-two in freelists

Most memory allocators allocate in multiples of twice the size of
a pointer.  So there is no point in keeping freelists for both
even and odd levels.  We now round odd levels up to the next
even level for freelist computations.  This reduces the number of
node mallocations.
This commit is contained in:
Behdad Esfahbod 2007-04-08 23:24:50 -04:00
parent 9da86e4a38
commit a7de9501f6
2 changed files with 23 additions and 8 deletions

View file

@ -34,6 +34,14 @@
#define MAX_LEVEL 31
/* Returns the index of the free-list to use for a node at level 'level' */
#define FREELIST_FOR_LEVEL(level) (((level) - 1) / 2)
/* Returns the maximum level that uses the same free-list as 'level' does */
#define FREELIST_MAX_LEVEL_FOR(level) (((level) + 1) & ~1)
#define MAX_FREELIST_LEVEL (FREELIST_FOR_LEVEL (MAX_LEVEL - 1) + 1)
/*
* Skip list element. In order to use the skip list, the caller must
* generate a structure for list elements that has as its final member
@ -58,7 +66,7 @@ typedef struct _skip_list {
size_t elt_size;
size_t data_size;
skip_elt_t *chains[MAX_LEVEL];
skip_elt_t *freelists[MAX_LEVEL];
skip_elt_t *freelists[MAX_FREELIST_LEVEL];
int max_level;
} cairo_skip_list_t;

View file

@ -232,6 +232,9 @@ _cairo_skip_list_init (cairo_skip_list_t *list,
for (i = 0; i < MAX_LEVEL; i++) {
list->chains[i] = NULL;
}
for (i = 0; i < MAX_FREELIST_LEVEL; i++) {
list->freelists[i] = NULL;
}
@ -247,7 +250,7 @@ _cairo_skip_list_fini (cairo_skip_list_t *list)
while ((elt = list->chains[0])) {
_cairo_skip_list_delete_given (list, elt);
}
for (i=0; i<MAX_LEVEL; i++) {
for (i=0; i<MAX_FREELIST_LEVEL; i++) {
elt = list->freelists[i];
while (elt) {
skip_elt_t *nextfree = elt->prev;
@ -282,19 +285,23 @@ random_level (void)
static void *
alloc_node_for_level (cairo_skip_list_t *list, unsigned level)
{
if (list->freelists[level-1]) {
skip_elt_t *elt = list->freelists[level-1];
list->freelists[level-1] = elt->prev;
int freelist_level = FREELIST_FOR_LEVEL (level);
if (list->freelists[freelist_level]) {
skip_elt_t *elt = list->freelists[freelist_level];
list->freelists[freelist_level] = elt->prev;
return ELT_DATA(elt);
}
return malloc (list->elt_size + (level-1) * sizeof (skip_elt_t *));
return malloc (list->elt_size
+ (FREELIST_MAX_LEVEL_FOR (level) - 1) * sizeof (skip_elt_t *));
}
static void
free_elt (cairo_skip_list_t *list, skip_elt_t *elt)
{
elt->prev = list->freelists[elt->prev_index];
list->freelists[elt->prev_index] = elt;
int level = elt->prev_index + 1;
int freelist_level = FREELIST_FOR_LEVEL (level);
elt->prev = list->freelists[freelist_level];
list->freelists[freelist_level] = elt;
}
/*