xref: /freebsd/contrib/jemalloc/src/cache_bin.c (revision c43cad87172039ccf38172129c79755ea79e6102)
1*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_preamble.h"
2*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_internal_includes.h"
3*c43cad87SWarner Losh 
4*c43cad87SWarner Losh #include "jemalloc/internal/bit_util.h"
5*c43cad87SWarner Losh #include "jemalloc/internal/cache_bin.h"
6*c43cad87SWarner Losh #include "jemalloc/internal/safety_check.h"
7*c43cad87SWarner Losh 
8*c43cad87SWarner Losh void
9*c43cad87SWarner Losh cache_bin_info_init(cache_bin_info_t *info,
10*c43cad87SWarner Losh     cache_bin_sz_t ncached_max) {
11*c43cad87SWarner Losh 	assert(ncached_max <= CACHE_BIN_NCACHED_MAX);
12*c43cad87SWarner Losh 	size_t stack_size = (size_t)ncached_max * sizeof(void *);
13*c43cad87SWarner Losh 	assert(stack_size < ((size_t)1 << (sizeof(cache_bin_sz_t) * 8)));
14*c43cad87SWarner Losh 	info->ncached_max = (cache_bin_sz_t)ncached_max;
15*c43cad87SWarner Losh }
16*c43cad87SWarner Losh 
17*c43cad87SWarner Losh void
18*c43cad87SWarner Losh cache_bin_info_compute_alloc(cache_bin_info_t *infos, szind_t ninfos,
19*c43cad87SWarner Losh     size_t *size, size_t *alignment) {
20*c43cad87SWarner Losh 	/* For the total bin stack region (per tcache), reserve 2 more slots so
21*c43cad87SWarner Losh 	 * that
22*c43cad87SWarner Losh 	 * 1) the empty position can be safely read on the fast path before
23*c43cad87SWarner Losh 	 *    checking "is_empty"; and
24*c43cad87SWarner Losh 	 * 2) the cur_ptr can go beyond the empty position by 1 step safely on
25*c43cad87SWarner Losh 	 * the fast path (i.e. no overflow).
26*c43cad87SWarner Losh 	 */
27*c43cad87SWarner Losh 	*size = sizeof(void *) * 2;
28*c43cad87SWarner Losh 	for (szind_t i = 0; i < ninfos; i++) {
29*c43cad87SWarner Losh 		assert(infos[i].ncached_max > 0);
30*c43cad87SWarner Losh 		*size += infos[i].ncached_max * sizeof(void *);
31*c43cad87SWarner Losh 	}
32*c43cad87SWarner Losh 
33*c43cad87SWarner Losh 	/*
34*c43cad87SWarner Losh 	 * Align to at least PAGE, to minimize the # of TLBs needed by the
35*c43cad87SWarner Losh 	 * smaller sizes; also helps if the larger sizes don't get used at all.
36*c43cad87SWarner Losh 	 */
37*c43cad87SWarner Losh 	*alignment = PAGE;
38*c43cad87SWarner Losh }
39*c43cad87SWarner Losh 
40*c43cad87SWarner Losh void
41*c43cad87SWarner Losh cache_bin_preincrement(cache_bin_info_t *infos, szind_t ninfos, void *alloc,
42*c43cad87SWarner Losh     size_t *cur_offset) {
43*c43cad87SWarner Losh 	if (config_debug) {
44*c43cad87SWarner Losh 		size_t computed_size;
45*c43cad87SWarner Losh 		size_t computed_alignment;
46*c43cad87SWarner Losh 
47*c43cad87SWarner Losh 		/* Pointer should be as aligned as we asked for. */
48*c43cad87SWarner Losh 		cache_bin_info_compute_alloc(infos, ninfos, &computed_size,
49*c43cad87SWarner Losh 		    &computed_alignment);
50*c43cad87SWarner Losh 		assert(((uintptr_t)alloc & (computed_alignment - 1)) == 0);
51*c43cad87SWarner Losh 	}
52*c43cad87SWarner Losh 
53*c43cad87SWarner Losh 	*(uintptr_t *)((uintptr_t)alloc + *cur_offset) =
54*c43cad87SWarner Losh 	    cache_bin_preceding_junk;
55*c43cad87SWarner Losh 	*cur_offset += sizeof(void *);
56*c43cad87SWarner Losh }
57*c43cad87SWarner Losh 
58*c43cad87SWarner Losh void
59*c43cad87SWarner Losh cache_bin_postincrement(cache_bin_info_t *infos, szind_t ninfos, void *alloc,
60*c43cad87SWarner Losh     size_t *cur_offset) {
61*c43cad87SWarner Losh 	*(uintptr_t *)((uintptr_t)alloc + *cur_offset) =
62*c43cad87SWarner Losh 	    cache_bin_trailing_junk;
63*c43cad87SWarner Losh 	*cur_offset += sizeof(void *);
64*c43cad87SWarner Losh }
65*c43cad87SWarner Losh 
66*c43cad87SWarner Losh void
67*c43cad87SWarner Losh cache_bin_init(cache_bin_t *bin, cache_bin_info_t *info, void *alloc,
68*c43cad87SWarner Losh     size_t *cur_offset) {
69*c43cad87SWarner Losh 	/*
70*c43cad87SWarner Losh 	 * The full_position points to the lowest available space.  Allocations
71*c43cad87SWarner Losh 	 * will access the slots toward higher addresses (for the benefit of
72*c43cad87SWarner Losh 	 * adjacent prefetch).
73*c43cad87SWarner Losh 	 */
74*c43cad87SWarner Losh 	void *stack_cur = (void *)((uintptr_t)alloc + *cur_offset);
75*c43cad87SWarner Losh 	void *full_position = stack_cur;
76*c43cad87SWarner Losh 	uint16_t bin_stack_size = info->ncached_max * sizeof(void *);
77*c43cad87SWarner Losh 
78*c43cad87SWarner Losh 	*cur_offset += bin_stack_size;
79*c43cad87SWarner Losh 	void *empty_position = (void *)((uintptr_t)alloc + *cur_offset);
80*c43cad87SWarner Losh 
81*c43cad87SWarner Losh 	/* Init to the empty position. */
82*c43cad87SWarner Losh 	bin->stack_head = (void **)empty_position;
83*c43cad87SWarner Losh 	bin->low_bits_low_water = (uint16_t)(uintptr_t)bin->stack_head;
84*c43cad87SWarner Losh 	bin->low_bits_full = (uint16_t)(uintptr_t)full_position;
85*c43cad87SWarner Losh 	bin->low_bits_empty = (uint16_t)(uintptr_t)empty_position;
86*c43cad87SWarner Losh 	cache_bin_sz_t free_spots = cache_bin_diff(bin,
87*c43cad87SWarner Losh 	    bin->low_bits_full, (uint16_t)(uintptr_t)bin->stack_head,
88*c43cad87SWarner Losh 	    /* racy */ false);
89*c43cad87SWarner Losh 	assert(free_spots == bin_stack_size);
90*c43cad87SWarner Losh 	assert(cache_bin_ncached_get_local(bin, info) == 0);
91*c43cad87SWarner Losh 	assert(cache_bin_empty_position_get(bin) == empty_position);
92*c43cad87SWarner Losh 
93*c43cad87SWarner Losh 	assert(bin_stack_size > 0 || empty_position == full_position);
94*c43cad87SWarner Losh }
95*c43cad87SWarner Losh 
96*c43cad87SWarner Losh bool
97*c43cad87SWarner Losh cache_bin_still_zero_initialized(cache_bin_t *bin) {
98*c43cad87SWarner Losh 	return bin->stack_head == NULL;
99*c43cad87SWarner Losh }
100