1 #include "test/jemalloc_test.h"
2
3 #include "test/extent_hooks.h"
4
5 static 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
16 static 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
TEST_BEGIN(test_base_hooks_default)27 TEST_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 }
53 TEST_END
54
TEST_BEGIN(test_base_hooks_null)55 TEST_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 }
93 TEST_END
94
TEST_BEGIN(test_base_hooks_not_null)95 TEST_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 }
214 TEST_END
215
216 int
main(void)217 main(void)
218 {
219 return (test(
220 test_base_hooks_default,
221 test_base_hooks_null,
222 test_base_hooks_not_null));
223 }
224