| /* |
| * include/linux/simp.h -- simple allocator for cached objects |
| * |
| * This is meant as a faster and simpler (not full-featured) replacement |
| * for SLAB, thus the name "simp" :-) |
| * Use this in places where you don't need the full features of SLAB. |
| * I don't want to compomize simplicity by features, so continue to |
| * use SLAB if you really need it's features. |
| * |
| * Measurements however show a _significant_ performance boost over |
| * SLAB. Just uncomment the BENCHMARK define in mm/simp.c and look. |
| * |
| * NOTE: The original implementation was very simple. The code now |
| * looks ugly because it has been rewritten to _allow_ inlining everything, |
| * even the constructors and destructors. Inlining small constructors |
| * (or elimininating overhead if there is none) has proven to be a |
| * main performance issue. |
| * In order to allow efficient inlining, the system has been changed |
| * to create static SIMP instances by preprocessor macros. |
| * |
| * You may create multiple runtime instances dynamically at runtime |
| * by calling *_create() multiple times with a differrent instance name. |
| * Each of these runtime instances will use the same constructors etc, |
| * so this is only for special-purpose thingies. |
| * |
| * (C) 1997 Thomas Schoebel-Theuer |
| */ |
| |
| #ifndef SIMP_H |
| #define SIMP_H |
| |
| #include <linux/mm.h> |
| |
| /* The next two defines can be independently enabled for debugging */ |
| /*#define SIMP_DEBUG*/ |
| /*#define DEAD_BEEF*/ |
| |
| /* used for constructors / destructors */ |
| typedef void (*structor)(void *); |
| |
| /* Usage: |
| |
| Do a DEF_SIMP_HEADER(NAME,TYPE,SIZE,MODE,ORDER,FIRST_CTOR,AGAIN_CTOR,DTOR,FREE) |
| either in a header file, or at the beginning of your program. |
| |
| NAME : this is used to define <NAME>_alloc() and <NAME>_free() routines, |
| as well as some other ones (read the definition below). |
| TYPE : a TYPE* is used as result type for <NAME>_alloc() and parameter |
| of <NAME>_free(), so you get some type safety. If you don't |
| want that type safety, simply use "void" here, so your |
| routines will use a void* for maximum flexibility. |
| SIZE : object size in bytes, normally sizeof(TYPE). |
| MODE : currently only SIMP_SMALLOBJS is allowed as parameter; |
| reserved for future expansion. |
| ORDER : how large the allocated kernel pages (chunks) will be. |
| 0 = PAGE_SIZE (4K on most machines), |
| 1 = 2 * PAGE_SIZE, 2 = 4 * PAGE_SIZE, and so on powers of two. |
| Setting this number is a tradeoff between speed of allocation |
| vs. space reclaiming. Pools consisting of many small objects |
| should use as small ORDERs as possible, because many of them |
| will reside in a chunk, so there are good chances that some of |
| them remain allocated and simp_garbage() cannot reclaim the whole |
| chunk because of that. Enlarging ORDER will improve performance |
| somewhat, but lower chances for space reclaiming. For objects |
| larger than PAGE_SIZE (or a 2-power of it), you must of course |
| use chunks that are large enough :-), otherwise your objects |
| will not fit into it. |
| Best strategy for the space reclaiming problem is to let your |
| pools not grow too large, and to avoid memory stealing at all, |
| because it is a broken concept to let different pools steal |
| memory from each other IMHO. |
| FIRST_CTOR : If non-NULL, this constructor function is invoked when |
| an object is created *the first time*. |
| AGAIN_CTOR: If non-NULL, this constructor is invoked at each |
| <NAME>_alloc(), to initialize your object. Notes that for |
| completely new objects, _both_ FIRST_CTOR() and AGAIN_CTOR() |
| are called, so your FIRST_CTOR() need not do things that are |
| already done by AGAIN_CTOR(). |
| DTOR : Destructor function, only called by simp_garbage(), to perform |
| optional cleanups. |
| RESERVE : number of chunks that are kept allocated by simp_garbage(). |
| Setting this to values greater 0 is useful for pools which |
| always require reserved chunks, such as io_requests |
| (where it would be quite bad if other memory can be only freed |
| if a request has to be generated for transferring it to disk, |
| but no memory is available for that reqeust, so we would have |
| a deadlock). |
| |
| In _one_ *.c file, you should call the macro DEF_SIMP(NAME,TYPE). |
| This defines instances for the <NAME>_*() _functions_. You may however |
| omit this, so only the __<NAME>_*() inline functions are available. |
| |
| Independent from that, you must at least create one runtime instance |
| of your SIMP by calling *_create() at runtime, and store it's return |
| value in some variable for future use in arguments for the other |
| functions. |
| |
| */ |
| |
| /********************************************************************/ |
| /* for internal use in inline fcuntions, this is not really public! */ |
| #include <linux/simp_i.h> |
| /********************************************************************/ |
| |
| #define SIMP_SMALLOBJS /*not yet used*/ |
| |
| #define DEF_SIMP_HEADER(NAME,TYPE,SIZE,MODE,ORDER,FIRST_CTOR,AGAIN_CTOR,DTOR,RESERVE) \ |
| \ |
| /* create an object cache */ \ |
| extern inline struct NAME##_simp * NAME##_create(char * instance_name) \ |
| { \ |
| extern struct simp * simp_create(char * name, long size, long order, \ |
| structor first_ctor, structor dtor, \ |
| int reserve); \ |
| return (struct NAME##_simp*) \ |
| simp_create(instance_name ? instance_name : #NAME, \ |
| SIZE,ORDER,FIRST_CTOR,DTOR,RESERVE); \ |
| } \ |
| \ |
| /* allocate an object */ \ |
| extern TYPE * NAME##_alloc(struct NAME##_simp * simp); \ |
| \ |
| /* same, but interrupt safe */ \ |
| extern TYPE * NAME##_alloc_irq(struct NAME##_simp * simp); \ |
| \ |
| /* free an object */ \ |
| extern void NAME##_free(TYPE * objp); \ |
| \ |
| extern void NAME##_free_irq(TYPE * objp); \ |
| \ |
| /* return number of usable chunks as function result, number of usable elems \ |
| * in *nr_free, and number of postbuffer-elems in *posted. */\ |
| extern inline int NAME##_statistics(struct NAME##_simp * simp, \ |
| long * nr_free, int * posted) \ |
| { \ |
| extern int __simp_statistics(struct simp * simp, \ |
| long * nr_free, int * posted); \ |
| return __simp_statistics((struct simp*)simp, nr_free, posted); \ |
| } \ |
| \ |
| /* return number of allocated elemts; if 0, deallocate everything and \ |
| * delete simp */ \ |
| extern long NAME##_try_delete(struct NAME##_simp * simp) \ |
| { \ |
| extern long __try_delete(struct simp * simp); \ |
| return __try_delete((struct simp*)simp); \ |
| } \ |
| \ |
| /* Inline versions. |
| * For those who want to clobber their local register set ;-) |
| * |
| * Note: at least on Intel, using the inline version is not always |
| * advantageous, because it may lead to register trashing (loading / |
| * unloading of dirty registers to stack). |
| * Try it out; if you use the __*_{alloc,free}() versions at places |
| * where less registers are alive (such as the very beginning or |
| * ending of your routine), you have _very_ good chances to |
| * get another speedup over the non-underscore versions ;-) |
| */ \ |
| extern inline TYPE * __##NAME##_alloc(struct NAME##_simp * _simp) \ |
| { \ |
| extern void ** bunch_alloc(struct simp * simp, void ** buffer); \ |
| extern void test_dead_beef(struct simp * simp, void * objp); \ |
| \ |
| struct simp * simp = (struct simp*)_simp; \ |
| struct per_cpu * priv = simp->private; \ |
| void ** buffer_pos; \ |
| void * res; \ |
| \ |
| _SMP( \ |
| priv += smp_processor_id(); \ |
| ) \ |
| \ |
| buffer_pos = priv->buffer_pos; \ |
| if(buffer_pos == priv->postbuffer) { \ |
| buffer_pos = bunch_alloc(simp, buffer_pos); \ |
| } \ |
| buffer_pos--; \ |
| res = *buffer_pos; \ |
| priv->buffer_pos = buffer_pos; \ |
| _DEAD_BEEF( \ |
| { \ |
| test_dead_beef(simp, res); \ |
| if((unsigned long)(FIRST_CTOR)) \ |
| (FIRST_CTOR)(res); \ |
| } \ |
| ) \ |
| if((unsigned long)(AGAIN_CTOR)) \ |
| (AGAIN_CTOR)(res); \ |
| return res; \ |
| } \ |
| \ |
| /* this is more than 10% faster than __*_free() in case you have the \ |
| * simp pointer already handy somewhere (but don't fiddle to get the \ |
| * pointer -- __*_free() is really fast though! \ |
| */ \ |
| extern inline void __##NAME##_dealloc(struct NAME##_simp * _simp, TYPE * objp)\ |
| { \ |
| struct simp * simp = (struct simp*)_simp; \ |
| void ** buffer_pos; \ |
| struct per_cpu * private; \ |
| \ |
| extern long check_header(struct simp_header * hdr, void * ptr); \ |
| extern void ** bunch_free(struct simp * simp, void ** buffer); \ |
| extern void make_dead_beef(struct simp_header * hdr, void * objp); \ |
| \ |
| _SIMP_DEBUG( \ |
| if(check_header(CHUNK_BASE(MODE,objp,CHUNK_SIZE(ORDER)), objp)) \ |
| return; \ |
| ) \ |
| \ |
| private = simp->private; \ |
| _SMP( \ |
| private += smp_processor_id(); \ |
| ) \ |
| buffer_pos = private->buffer_pos; \ |
| if(buffer_pos >= private->postbuffer+POSTBUFFER_SIZE) { \ |
| buffer_pos = bunch_free(simp, buffer_pos); \ |
| } \ |
| \ |
| *buffer_pos++ = objp; \ |
| private->buffer_pos = buffer_pos; \ |
| \ |
| _DEAD_BEEF( \ |
| make_dead_beef(CHUNK_BASE(MODE,objp,CHUNK_SIZE(ORDER)), objp); \ |
| ) \ |
| } \ |
| \ |
| extern inline void __##NAME##_free(TYPE * objp) \ |
| { \ |
| struct simp_header * hdr = CHUNK_BASE(MODE,objp,CHUNK_SIZE(ORDER)); \ |
| __##NAME##_dealloc((struct NAME##_simp *)hdr->father, objp); \ |
| } \ |
| \ |
| /* Versions for use in interrupt routines */ \ |
| extern inline TYPE * __##NAME##_alloc_irq(struct NAME##_simp * simp) \ |
| { \ |
| int flags; \ |
| void * res; \ |
| __save_flags(flags); \ |
| __cli(); \ |
| res = __##NAME##_alloc(simp); \ |
| __restore_flags(flags); \ |
| return res; \ |
| } \ |
| \ |
| extern inline void __##NAME##_free_irq(TYPE * objp) \ |
| { \ |
| int flags; \ |
| __save_flags(flags); \ |
| __cli(); \ |
| __##NAME##_free(objp); \ |
| __restore_flags(flags); \ |
| } \ |
| \ |
| extern inline long NAME##_garbage(struct NAME##_simp * simp) \ |
| { \ |
| extern long __simp_garbage(struct simp * simp); \ |
| return __simp_garbage((struct simp*)simp); \ |
| } |
| |
| #define DEF_SIMP(NAME) \ |
| TYPE * NAME##_alloc(struct NAME##_simp * simp) \ |
| { \ |
| __##NAME##_alloc(simp); \ |
| } \ |
| \ |
| TYPE * NAME##_alloc_irq(struct NAME##_simp * simp) \ |
| { \ |
| return __##NAME##_alloc_irq(simp); \ |
| } \ |
| \ |
| void NAME##_free(TYPE * objp) \ |
| { \ |
| __##NAME##_free(objp); \ |
| } \ |
| \ |
| void NAME##_free_irq(TYPE * objp) \ |
| { \ |
| __##NAME##_free_irq(void * objp); \ |
| } \ |
| |
| |
| extern void * always_get_pages(int gfp_mask, unsigned long gfporder); |
| |
| extern long simp_garbage(void); |
| |
| extern int get_simpinfo(char * buf); |
| |
| #endif |