1#include "test/jemalloc_test.h"
2
3#include "test/extent_hooks.h"
4
5static extent_hooks_t hooks_null = {
6	extent_alloc_hook,
7	NULL, /* dalloc */
8	NULL, /* commit */
9	NULL, /* decommit */
10	NULL, /* purge_lazy */
11	NULL, /* purge_forced */
12	NULL, /* split */
13	NULL /* merge */
14};
15
16static extent_hooks_t hooks_not_null = {
17	extent_alloc_hook,
18	extent_dalloc_hook,
19	NULL, /* commit */
20	extent_decommit_hook,
21	extent_purge_lazy_hook,
22	extent_purge_forced_hook,
23	NULL, /* split */
24	NULL /* merge */
25};
26
27TEST_BEGIN(test_base_hooks_default)
28{
29	tsdn_t *tsdn;
30	base_t *base;
31	size_t allocated0, allocated1, resident, mapped;
32
33	tsdn = tsdn_fetch();
34	base = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default);
35
36	if (config_stats) {
37		base_stats_get(tsdn, base, &allocated0, &resident, &mapped);
38		assert_zu_ge(allocated0, sizeof(base_t),
39		    "Base header should count as allocated");
40	}
41
42	assert_ptr_not_null(base_alloc(tsdn, base, 42, 1),
43	    "Unexpected base_alloc() failure");
44
45	if (config_stats) {
46		base_stats_get(tsdn, base, &allocated1, &resident, &mapped);
47		assert_zu_ge(allocated1 - allocated0, 42,
48		    "At least 42 bytes were allocated by base_alloc()");
49	}
50
51	base_delete(base);
52}
53TEST_END
54
55TEST_BEGIN(test_base_hooks_null)
56{
57	extent_hooks_t hooks_orig;
58	tsdn_t *tsdn;
59	base_t *base;
60	size_t allocated0, allocated1, resident, mapped;
61
62	extent_hooks_prep();
63	try_dalloc = false;
64	try_decommit = false;
65	try_purge_lazy = false;
66	try_purge_forced = false;
67	memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t));
68	memcpy(&hooks, &hooks_null, sizeof(extent_hooks_t));
69
70	tsdn = tsdn_fetch();
71	base = base_new(tsdn, 0, &hooks);
72	assert_ptr_not_null(base, "Unexpected base_new() failure");
73
74	if (config_stats) {
75		base_stats_get(tsdn, base, &allocated0, &resident, &mapped);
76		assert_zu_ge(allocated0, sizeof(base_t),
77		    "Base header should count as allocated");
78	}
79
80	assert_ptr_not_null(base_alloc(tsdn, base, 42, 1),
81	    "Unexpected base_alloc() failure");
82
83	if (config_stats) {
84		base_stats_get(tsdn, base, &allocated1, &resident, &mapped);
85		assert_zu_ge(allocated1 - allocated0, 42,
86		    "At least 42 bytes were allocated by base_alloc()");
87	}
88
89	base_delete(base);
90
91	memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t));
92}
93TEST_END
94
95TEST_BEGIN(test_base_hooks_not_null)
96{
97	extent_hooks_t hooks_orig;
98	tsdn_t *tsdn;
99	base_t *base;
100	void *p, *q, *r, *r_exp;
101
102	extent_hooks_prep();
103	try_dalloc = false;
104	try_decommit = false;
105	try_purge_lazy = false;
106	try_purge_forced = false;
107	memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t));
108	memcpy(&hooks, &hooks_not_null, sizeof(extent_hooks_t));
109
110	tsdn = tsdn_fetch();
111	did_alloc = false;
112	base = base_new(tsdn, 0, &hooks);
113	assert_ptr_not_null(base, "Unexpected base_new() failure");
114	assert_true(did_alloc, "Expected alloc");
115
116	/*
117	 * Check for tight packing at specified alignment under simple
118	 * conditions.
119	 */
120	{
121		const size_t alignments[] = {
122			1,
123			QUANTUM,
124			QUANTUM << 1,
125			CACHELINE,
126			CACHELINE << 1,
127		};
128		unsigned i;
129
130		for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) {
131			size_t alignment = alignments[i];
132			size_t align_ceil = ALIGNMENT_CEILING(alignment,
133			    QUANTUM);
134			p = base_alloc(tsdn, base, 1, alignment);
135			assert_ptr_not_null(p,
136			    "Unexpected base_alloc() failure");
137			assert_ptr_eq(p,
138			    (void *)(ALIGNMENT_CEILING((uintptr_t)p,
139			    alignment)), "Expected quantum alignment");
140			q = base_alloc(tsdn, base, alignment, alignment);
141			assert_ptr_not_null(q,
142			    "Unexpected base_alloc() failure");
143			assert_ptr_eq((void *)((uintptr_t)p + align_ceil), q,
144			    "Minimal allocation should take up %zu bytes",
145			    align_ceil);
146			r = base_alloc(tsdn, base, 1, alignment);
147			assert_ptr_not_null(r,
148			    "Unexpected base_alloc() failure");
149			assert_ptr_eq((void *)((uintptr_t)q + align_ceil), r,
150			    "Minimal allocation should take up %zu bytes",
151			    align_ceil);
152		}
153	}
154
155	/*
156	 * Allocate an object that cannot fit in the first block, then verify
157	 * that the first block's remaining space is considered for subsequent
158	 * allocation.
159	 */
160	assert_zu_ge(extent_size_get(&base->blocks->extent), QUANTUM,
161	    "Remainder insufficient for test");
162	/* Use up all but one quantum of block. */
163	while (extent_size_get(&base->blocks->extent) > QUANTUM) {
164		p = base_alloc(tsdn, base, QUANTUM, QUANTUM);
165		assert_ptr_not_null(p, "Unexpected base_alloc() failure");
166	}
167	r_exp = extent_addr_get(&base->blocks->extent);
168	assert_zu_eq(base->extent_sn_next, 1, "One extant block expected");
169	q = base_alloc(tsdn, base, QUANTUM + 1, QUANTUM);
170	assert_ptr_not_null(q, "Unexpected base_alloc() failure");
171	assert_ptr_ne(q, r_exp, "Expected allocation from new block");
172	assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected");
173	r = base_alloc(tsdn, base, QUANTUM, QUANTUM);
174	assert_ptr_not_null(r, "Unexpected base_alloc() failure");
175	assert_ptr_eq(r, r_exp, "Expected allocation from first block");
176	assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected");
177
178	/*
179	 * Check for proper alignment support when normal blocks are too small.
180	 */
181	{
182		const size_t alignments[] = {
183			HUGEPAGE,
184			HUGEPAGE << 1
185		};
186		unsigned i;
187
188		for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) {
189			size_t alignment = alignments[i];
190			p = base_alloc(tsdn, base, QUANTUM, alignment);
191			assert_ptr_not_null(p,
192			    "Unexpected base_alloc() failure");
193			assert_ptr_eq(p,
194			    (void *)(ALIGNMENT_CEILING((uintptr_t)p,
195			    alignment)), "Expected %zu-byte alignment",
196			    alignment);
197		}
198	}
199
200	called_dalloc = called_decommit = called_purge_lazy =
201	    called_purge_forced = false;
202	base_delete(base);
203	assert_true(called_dalloc, "Expected dalloc call");
204	assert_true(called_decommit, "Expected decommit call");
205	assert_true(called_purge_lazy, "Expected purge_lazy call");
206	assert_true(called_purge_forced, "Expected purge_forced call");
207
208	try_dalloc = true;
209	try_decommit = true;
210	try_purge_lazy = true;
211	try_purge_forced = true;
212	memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t));
213}
214TEST_END
215
216int
217main(void)
218{
219	return (test(
220	    test_base_hooks_default,
221	    test_base_hooks_null,
222	    test_base_hooks_not_null));
223}
224