blob: 1762f163bc5568bbac9fc200812b62c6b04f49ff [file] [log] [blame]
/*
* 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