pool_cache_init,
pool_cache_destroy —
per CPU caching of pool items
#include
<sys/pool.h>
void
pool_cache_init(
struct
pool *pp);
void
pool_cache_destroy(
struct
pool *pp);
By default, pools protect their internal state using a single lock, so
concurrent access to a pool may suffer contention on that lock. The pool API
provides support for caching free pool items on each CPU which can be enabled
to mitigate against this contention.
When per CPU caches are enabled on a pool, each CPU maintains an active and
inactive list of free pool items. A global depot of free lists is initialised
in the pool structure to store excess lists of free items that may accumulate
on CPUs.
pool_cache_init() allocates the free lists on each
CPU, initialises the global depot of free lists, and enables their use to
handle
pool_get(9) and
pool_put(9) operations.
pool_cache_destroy() disables the use of the free
lists on each CPU, returns items cached on all the free lists in the subsystem
back to the normal pool allocator, and finally frees the per CPU data
structures.
Once per CPU caches are enabled, items returned to a pool with
pool_put(9) are placed on the
current CPU's active free list. If the active list becomes full, it becomes
the inactive list and a new active list is initialised for the free item to go
on. If an inactive list already exists when the active list becomes full, the
inactive list is moved to the global depot of free lists before the active
list is moved into its place.
Attempts to allocate items with
pool_get(9) first try to get
an item from the active free list on the CPU it is called on. If the active
free list is empty but an inactive list of items is available, the inactive
list is moved back into place as the active list so it can satisfy the
request. If no lists are available on the current CPU, an attempt to allocate
a free list from the global depot is made. Finally, if no free list is
available,
pool_get(9) falls
through to allocating a pool item normally.
The maximum number of items cached on a free list is dynamically scaled for each
pool based on the contention on the lock around the global depot of free
lists. A garbage collector runs periodically to recover idle free lists and
make the memory they consume available to the system for use elsewhere.
Information about the current state of the per CPU caches and counters of
operations they handle are available via
sysctl(2), or displayed in the
pcache view in
systat(1).
The
kinfo_pool_cache struct provides
information about the global state of a pool's caches via a node for each pool
under the
CTL_KERN
,
KERN_POOL
,
KERN_POOL_CACHE
sysctl(2) MIB hierarchy.
struct kinfo_pool_cache {
uint64_t pr_ngc;
unsigned int pr_len;
unsigned int pr_nitems;
unsigned int pr_contention;
};
pr_ngc indicates the number of times the
garbage collector has recovered an idle item free list.
pr_len shows the maximum number of items that
can be cached on a CPU's active free list.
pr_nitems shows the number of free items that
are currently stored in the global depot.
pr_contention indicates the number of times
that there was contention on the lock protecting the global depot.
The
kinfo_pool_cache_cpus struct provides
information about the number of times the cache on a CPU handled certain
operations. These counters may be accessed via a node for each pool under the
CTL_KERN
,
KERN_POOL
,
KERN_POOL_CACHE_CPUS
sysctl(2) MIB hierarchy. This
sysctl returns an array of
kinfo_pool_cache_cpus structures sized by the
number of CPUs found in the system. The number of CPUs in the system can be
read from the
CTL_HW
,
HW_NCPUFOUND
sysctl MIB.
struct kinfo_pool_cache_cpu {
unsigned int pr_cpu;
uint64_t pr_nget;
uint64_t pr_nfail;
uint64_t pr_nput;
uint64_t pr_nlget;
uint64_t pr_nlfail;
uint64_t pr_nlput;
};
pr_cpu indicates which CPU performed the
relevant operations.
pr_nget and
pr_nfail show the number of times the CPU
successfully or unsuccessfully handled a
pool_get(9) operation
respectively.
pr_nput shows the number of
times the CPU handled a
pool_put(9) operation.
pr_nlget and
pr_nlfail show the number of times the CPU
successfully or unsuccessfully requested a list of free items from the global
depot.
pr_nlput shows the number of times the
CPU pushed a list of free items to the global depot.
pool_cache_init() and
pool_cache_destroy() can be called from process
context.
The pool implementation is in the file
sys/kern/subr_pool.c.
systat(1),
sysctl(2),
pool_get(9)
Because the intention of per CPU pool caches is to avoid having all CPUs
coordinate via shared data structures for handling
pool_get(9) and
pool_put(9) operations, any
limits set on the pool with
pool_sethardlimit(9)
are ignored. If limits on the memory used by a pool with per CPU caches
enabled are needed, they must be enforced by a page allocator specified when a
pool is set up with
pool_init(9).