DragonFly On-Line Manual Pages
OBJCACHE(9) DragonFly Kernel Developer's Manual OBJCACHE(9)
NAME
objcache_create, objcache_create_mbacked, objcache_create_simple,
objcache_destroy, objcache_dtor, objcache_get, objcache_malloc_alloc,
objcache_malloc_free, objcache_nop_alloc, objcache_nop_free,
objcache_put, objcache_reclaimlist - object caching facility
SYNOPSIS
#include <sys/objcache.h>
typedef boolean_t (objcache_ctor_fn)(void *obj, void *privdata, int ocflags);
typedef void (objcache_dtor_fn)(void *obj, void *privdata);
typedef void *(objcache_alloc_fn)(void *allocator_args, int ocflags);
typedef void (objcache_free_fn)(void *obj, void *allocator_args);
struct objcache_malloc_args {
size_t objsize;
malloc_type_t mtype;
};
struct objcache *
objcache_create(const char *name, int cluster_limit, int mag_capacity,
objcache_ctor_fn *ctor, objcache_dtor_fn *dtor, void *privdata,
objcache_alloc_fn *alloc, objcache_free_fn *free,
void *allocator_args);
struct objcache *
objcache_create_mbacked(malloc_type_t mtype, size_t objsize,
int cluster_limit, int mag_capacity, objcache_ctor_fn *ctor,
objcache_dtor_fn *dtor, void *privdata);
struct objcache *
objcache_create_simple(malloc_type_t mtype, size_t objsize);
void
objcache_destroy(struct objcache *oc);
void
objcache_dtor(struct objcache *oc, void *obj);
void *
objcache_get(struct objcache *oc, int ocflags);
void *
objcache_malloc_alloc(void *allocator_args, int ocflags);
void
objcache_malloc_free(void *obj, void *allocator_args);
void *
objcache_nop_alloc(void *allocator_args, int ocflags);
void
objcache_nop_free(void *obj, void *allocator_args);
void
objcache_put(struct objcache *oc, void *obj);
boolean_t
objcache_reclaimlist(struct objcache *oc[], int nlist);
DESCRIPTION
Object caching is a technique for manipulating objects that are
frequently allocated and freed. The idea behind caching is to preserve
the invariant portion of an object's initial state between uses, so it
does not have to be destroyed and reborn every time the object is used.
objcache_create() creates a new object cache. It is identified by name,
which is used to distinguish the object in diagnostic output. The
cluster_limit determines the number of available magazines in the depot
layer. It must be at least (mag_capacity * ncpus * 8). If 0 is given,
then there is no limit to the number of magazines the depot can have
(aside from the inherent limitation imposed by the restricted nature of
the back end allocator). The mag_capacity describes the capacity of the
magazine, that is the largest number of objects it can hold. If set to
0, the default value is used as defined in sys/kern/kern_objcache.c.
Currently, the default value is 64. The object caching system itself may
adjust the cluster limit and/or magazines' capacity based on the number
of available CPUs. ctor specifies a function that constructs (i.e.,
performs the one-time initialization of) an object in the cache. It is
defined as:
boolean_t foo_ctor(void *obj, void *privdata, int ocflags);
If no constructor is needed, it must be set to NULL. dtor specifies a
destructor function that destroys the cached object, before it is
released to the back end that manages the flow of real memory. It is
defined as:
void foo_dtor(void *obj, void *privdata);
If no destructor is needed, it must be set to NULL. The interface to
underlying allocator is provided by alloc, free and allocator_args. It
must adhere to the following form:
void *foo_alloc(void *allocator_args, int ocflags);
void foo_free(void *obj, void *allocator_args);
objcache_malloc_alloc() and objcache_malloc_free() are wrappers for
kmalloc(9) allocation functions. Whereas, objcache_nop_alloc() and
objcache_nop_free() are wrappers for allocation policies that pre-
allocate at initialization time instead of doing run-time allocation.
objcache_create_mbacked() creates a new object cache of size objsize,
backed with a malloc_type_t argument. The latter is used to perform
statistics in memory usage and for basic sanity checks. For the
underlying allocator, kmalloc(9) functions are employed.
objcache_create_simple() creates a new object cache of size objsize,
backed with a malloc_type_t argument. The cluster_limit is set to 0 and
the default value for magazines' capacity is used. ctor and dtor are set
to NULL. privdata is set to NULL as well. For the underlying
allocator, kmalloc(9) functions are employed.
objcache_get() returns an object from the oc object cache. The object is
in its initialized state. Newly allocated objects are subjected to the
object cache's constructor function, if not NULL, prior to being
returned. ocflags is only used when the depot does not have any non-
empty magazines and a new object needs to be allocated using the back end
allocator. In this case we cannot depend on flags such as M_ZERO. If
the back end allocator fails, or if the depot's object limit has been
reached and M_WAITOK is not specified, NULL is returned.
objcache_put() returns obj to the oc object cache. The object must be in
its initialized state prior to this call. If there is no empty magazine,
the object destructor is called and the object is freed.
objcache_dtor() puts obj back into the oc object cache, indicating that
the object is not in any shape to be reused and should be destructed and
freed immediately.
objcache_reclaimlist() iterates over the oclist[] list with nlist
elements and tries to free up some memory. For each object cache in the
reclaim list, the current per-CPU cache is tried first and then the full
magazine depot. The function returns TRUE as soon as some free memory is
found and FALSE otherwise.
objcache_destroy() destroys the oc object cache. The object must have no
existing references.
IMPLEMENTATION NOTES
Magazine
A magazine is the very basic functional unit of the object caching
scheme. The number of objects it can hold is fixed and determined by its
capacity. The term magazine is used as an analogy with automatic weapon
(a firearm that can fire several rounds without reloading).
Per-CPU object cache
The reasoning behind per-CPU caches is to allow CPUs to perform their
transactions (i.e., allocations, frees) in a parallel, yet lockless
manner.
Each CPU is given two magazines, an active and a backup. This is done in
order to avoid a situation where a tight loop of two allocations followed
by two frees can cause thrashing at the magazine boundary.
If we need to add an object to the cache and the active magazine is full,
room is searched in the backup magazine. If the backup has room, we swap
active with backup and add the object. If both magazines are full, we
get an empty magazine from the depot and move a fully loaded magazine to
the depot.
Magazine depot
Each object cache manages a global supply of magazines, the depot, that
is available across all CPUs. The depot maintains two lists of
magazines. One for completely full and one for completely free
magazines. The per-CPU object caches only exchange completely full or
completely empty magazines with the depot layer.
EXAMPLES
/* This is the data structure we are going to cache. */
struct foo {
int x;
char str[32];
};
MALLOC_DEFINE(M_FOOBUF, "foobuf", "Buffer to my little precious data");
struct objcache_malloc_args foo_malloc_args = {
sizeof(struct foo), M_FOOBUF };
struct objcache *foo_cache;
/*
* Object cache constructor.
*/
static boolean_t
foo_cache_ctor(void *obj, void *privdata, int ocflags)
{
struct foo *myfoo = obj;
/*
* Do any initialization of the object here. Let's just zero out
* the data structure for the fun of it.
*/
bzero(myfoo, sizeof(*myfoo));
return (TRUE);
}
/*
* Object cache destructor.
*/
static void
foo_cache_dtor(void *obj, void *privdata)
{
struct foo *myfoo = obj;
/*
* Do any clean up here. E.g., if you have kmalloc'ed() inside
* the constructor, this is the right place and time to kfree().
*/
}
/*
* Initialize our subsystem.
*/
static void
foo_init(void)
{
/* Create the object cache. */
foo_cache = objcache_create("foo",
0, /* infinite depot's capacity */
0, /* default magazine's capacity */
foo_ctor, foo_dtor, NULL,
objcache_malloc_alloc,
objcache_malloc_free,
&foo_malloc_args);
}
/*
* Random function.
*/
static void
foo_random(...)
{
struct foo *myfoo;
/* Get a `foo' object from the object cache. */
myfoo = objcache_get(foo_cache, M_WAITOK);
/* Do stuff with it. */
/* ... */
/* We don't need it anymore. Put it back in object cache. */
objcache_put(foo_cache, myfoo);
}
/*
* Shutdown our subsystem.
*/
static void
foo_uninit(void)
{
/* Destroy the object cache. */
objcache_destroy(foo_cache);
}
SEE ALSO
memory(9)
Jeff Bonwick, The Slab Allocator: An Object-Caching Kernel Memory
Allocator, USENIX Summer 1994 Technical Conference.
Jeff Bonwick and Jonathan Adams, Magazines and Vmem: Extending the Slab
Allocator to Many CPUs and Arbitrary Resources, USENIX 2001 Technical
Conference.
HISTORY
The object caching system appeared in DragonFly 1.3.
AUTHORS
The object caching system was written by Jeffrey M. Hsu
<hsu@freebsd.org>. This manual page was written by Stathis Kamperis
<ekamperi@gmail.com>.
DragonFly 6.5-DEVELOPMENT January 25, 2024 DragonFly 6.5-DEVELOPMENT