diff --git a/doc/Changelog b/doc/Changelog index a11a15d29..57ac174b1 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,6 @@ 6 March 2007: Wouter - Testbed works with threading (different machines, different options). + - alloc work, does the special type. 2 March 2007: Wouter - do not compile fork funcs unless needed. Otherwise will give diff --git a/util/alloc.c b/util/alloc.c index 9e17bd2da..af6066700 100644 --- a/util/alloc.c +++ b/util/alloc.c @@ -42,3 +42,141 @@ #include "config.h" #include "util/alloc.h" +/** prealloc some entries in the cache. To minimize contention. + * @param alloc: the structure to fill up. + */ +static void +prealloc(struct alloc_cache* alloc) +{ + alloc_special_t* p; + int i; + for(i=0; iquar; + alloc->quar = p; + alloc->num_quar++; + } +} + +void +alloc_init(struct alloc_cache* alloc, struct alloc_cache* super) +{ + memset(alloc, 0, sizeof(*alloc)); + alloc->super = super; + lock_quick_init(&alloc->lock); +} + +void +alloc_delete(struct alloc_cache* alloc) +{ + alloc_special_t* p, *np; + if(!alloc) + return; + lock_quick_destroy(&alloc->lock); + if(alloc->super && alloc->quar) { + /* push entire list into super */ + p = alloc->quar; + while(alloc_special_next(p)) /* find last */ + p = alloc_special_next(p); + lock_quick_lock(&alloc->super->lock); + alloc_special_next(p) = alloc->super->quar; + alloc->super->quar = alloc->quar; + alloc->super->num_quar += alloc->num_quar; + lock_quick_unlock(&alloc->super->lock); + } else { + /* free */ + p = alloc->quar; + while(p) { + np = alloc_special_next(p); + free(p); + p = np; + } + } + alloc->quar = 0; + alloc->num_quar = 0; +} + +alloc_special_t* +alloc_special_obtain(struct alloc_cache* alloc) +{ + alloc_special_t* p; + log_assert(alloc); + /* see if in local cache */ + if(alloc->quar) { + p = alloc->quar; + alloc->quar = alloc_special_next(p); + alloc->num_quar--; + alloc->special_allocated++; + return p; + } + /* see if in global cache */ + if(alloc->super) { + lock_quick_lock(&alloc->super->lock); + if((p = alloc->super->quar)) { + alloc->super->quar = alloc_special_next(p); + alloc->super->num_quar--; + } + lock_quick_unlock(&alloc->super->lock); + if(p) { + alloc->special_allocated++; + return p; + } + } + /* allocate new */ + prealloc(alloc); + if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) + fatal_exit("alloc_special_obtain: out of memory"); + alloc->special_allocated++; + return p; +} + +/** push mem and some more items to the super */ +static void +pushintosuper(struct alloc_cache* alloc, alloc_special_t* mem) +{ + int i; + alloc_special_t *p = alloc->quar; + log_assert(p); + log_assert(alloc && alloc->super && + alloc->num_quar >= ALLOC_SPECIAL_MAX); + /* push ALLOC_SPECIAL_MAX/2 after mem */ + alloc_special_next(mem) = alloc->quar; + for(i=1; iquar = alloc_special_next(p); + alloc->num_quar -= ALLOC_SPECIAL_MAX/2; + + lock_quick_lock(&alloc->super->lock); + alloc_special_next(p) = alloc->super->quar; + alloc->super->quar = mem; + alloc->super->num_quar += ALLOC_SPECIAL_MAX/2 + 1; + lock_quick_unlock(&alloc->super->lock); +} + +void +alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem) +{ + log_assert(alloc); + if(!mem) + return; + if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) { + /* push it to the super structure */ + alloc->special_allocated --; + pushintosuper(alloc, mem); + return; + } + + alloc_special_next(mem) = alloc->quar; + alloc->quar = mem; + alloc->num_quar++; + alloc->special_allocated--; +} + +void +alloc_stats(struct alloc_cache* alloc) +{ + log_info("%salloc: %d allocated, %d in cache.", alloc->super?"":"sup", + (int)alloc->special_allocated, (int)alloc->num_quar); +} diff --git a/util/alloc.h b/util/alloc.h index d1ccd6696..2801c8e89 100644 --- a/util/alloc.h +++ b/util/alloc.h @@ -42,10 +42,6 @@ * o Avoid locking costs of getting global lock to call malloc(). * o The packed rrset type needs to be kept on special freelists, * so that they are reused for other packet rrset allocations. - * o This service is not there to improve speed of malloc. - * Some caching is performed to help avoid locking costs. - * o This service does not prevent fragmentation. - * The caching will help somewhat for this. * * Design choices: * o The global malloc/free is used to handle fragmentation, etc. @@ -61,120 +57,67 @@ #include "util/locks.h" -/** all allocations are in multiples of this size */ -#define ALLOC_ALIGN 32 /* bytes */ - -/** - * This size and smaller is kept in cached lists by size. - * Must be a multiple of ALLOC_ALIGN. - */ -#define ALLOC_LARGESIZE 1024 /* bytes */ - -/** number of bins */ -#define ALLOC_BINS (ALLOC_LARGESIZE / ALLOC_ALIGN) - /** The special type, packed rrset. Not allowed to be used for other memory */ typedef uint64_t alloc_special_t; /** clean the special type. Pass pointer. */ #define alloc_special_clean(x) memset(x, 0, sizeof(alloc_special_t)) /** access next pointer. (in available spot). Pass pointer. */ -#define alloc_special_next(x) ((alloc_special_t*)(*(x))) +#define alloc_special_next(x) (*((alloc_special_t**)(x))) -/** The number of cached items. */ -#define ALLOC_CACHENUM 10 /* memory blocks */ +/** how many blocks to cache locally. */ +#define ALLOC_SPECIAL_MAX 10 -/** Preallocated per thread. This number for every size. */ -#define ALLOC_PREALLOC 32 /* memory blocks */ - -/** shorthand */ -typedef struct alloc_cache alloc_t; /** - * Structure that provides caching based on size. Used one per thread. + * Structure that provides allocation. Use one per thread. + * The one on top has a NULL super pointer. */ struct alloc_cache { + /** lock, only used for the super. */ + lock_quick_t lock; /** global allocator above this one. NULL for none (malloc/free) */ - struct alloc_super* super; - /** singly linked lists per size: [0]32, [1]64, ... [n-1]LARGESIZE */ - void* bins[ALLOC_BINS]; - /** the number of items per bin. */ - size_t nums[ALLOC_BINS]; + struct alloc_cache* super; /** singly linked lists of special type. These are free for use. */ alloc_special_t* quar; /** number of items in quarantine. */ size_t num_quar; - /* some statistics */ - /** amount allocated. */ - size_t bytes_allocated; - /** number of items allocated. */ - size_t items_allocated; - /** wasted space due to assigning oversized aligned blocks. */ - size_t internal_frag; - /** amount in cache. */ - size_t bytes_in_bins; /** number of special type allocated */ size_t special_allocated; }; -/** - * Structure with lock to provide global cache of special items and allocs. - */ -struct alloc_super { - /** lock for single access. */ - lock_quick_t lock; - /** singly linked lists of special type. These are free for use. */ - alloc_special_t* quar; - /** number of items in quarantine. */ - size_t num_quar; -}; - -/** - * Init super alloc. (zeroes the struct, inits the lock). - * @param super: to init. - */ -void asuper_init(struct alloc_super* super); - /** * Init alloc (zeroes the struct). * @param alloc: this parameter is allocated by the caller. * @param super: super to use (init that before with super_init). */ -void alloc_init(alloc_t* alloc, struct alloc_super* super); +void alloc_init(struct alloc_cache* alloc, struct alloc_cache* super); /** * Free the alloc. Pushes all the cached items into the super structure. + * Or deletes them if super is NULL. + * Does not free the alloc struct itself. * @param alloc: is almost zeroed on exit (except some stats). */ -void alloc_delete(alloc_t* alloc); - -/** - * Allocate memory - * @param alloc: where to alloc it. - * @param size: how much. - * @return: memory block. Will not return NULL (instead fatal_exit). - */ -void* alloc_alloc(alloc_t* alloc, size_t size); - -/** - * Free memory. - * @param alloc: where to alloc it. - * @param mem: block to free. - */ -void alloc_free(alloc_t* alloc, void* mem); +void alloc_delete(struct alloc_cache* alloc); /** * Get a new special_t element. * @param alloc: where to alloc it. * @return: memory block. Will not return NULL (instead fatal_exit). */ -alloc_special_t* alloc_special_alloc(alloc_t* alloc); +alloc_special_t* alloc_special_obtain(struct alloc_cache* alloc); /** * Return special_t back to pool. * @param alloc: where to alloc it. * @param mem: block to free. */ -void alloc_special_free(alloc_t* alloc, alloc_special_t* mem); +void alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem); +/** + * Print debug information (statistics). + * @param alloc: on what alloc. + */ +void alloc_stats(struct alloc_cache* alloc); #endif /* UTIL_ALLOC_H */