1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 #include <gtest/gtest.h>
7 #include "os/bluestore/fastbmap_allocator_impl.h"
9 class TestAllocatorLevel01
: public AllocatorLevel01Loose
12 void init(uint64_t capacity
, uint64_t alloc_unit
)
14 _init(capacity
, alloc_unit
);
16 interval_t
allocate_l1_cont(uint64_t length
, uint64_t min_length
,
17 uint64_t pos_start
, uint64_t pos_end
)
19 return _allocate_l1_contiguous(length
, min_length
, 0, pos_start
, pos_end
);
21 void free_l1(const interval_t
& r
)
23 _free_l1(r
.offset
, r
.length
);
27 class TestAllocatorLevel02
: public AllocatorLevel02
<AllocatorLevel01Loose
>
30 void init(uint64_t capacity
, uint64_t alloc_unit
)
32 _init(capacity
, alloc_unit
);
34 void allocate_l2(uint64_t length
, uint64_t min_length
,
36 interval_vector_t
* res
)
38 uint64_t allocated
= 0;
39 uint64_t hint
= 0; // trigger internal l2 hint support
40 _allocate_l2(length
, min_length
, 0, hint
, &allocated
, res
);
41 *allocated0
+= allocated
;
43 void free_l2(const interval_vector_t
& r
)
47 void mark_free(uint64_t o
, uint64_t len
)
51 void mark_allocated(uint64_t o
, uint64_t len
)
53 _mark_allocated(o
, len
);
57 const uint64_t _1m
= 1024 * 1024;
58 const uint64_t _2m
= 2 * 1024 * 1024;
60 TEST(TestAllocatorLevel01
, test_l1
)
62 TestAllocatorLevel01 al1
;
63 uint64_t num_l1_entries
= 3 * 256;
64 uint64_t capacity
= num_l1_entries
* 512 * 4096;
65 al1
.init(capacity
, 0x1000);
66 ASSERT_EQ(capacity
, al1
.debug_get_free());
68 auto i1
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
69 ASSERT_EQ(i1
.offset
, 0u);
70 ASSERT_EQ(i1
.length
, 0x1000u
);
71 ASSERT_EQ(capacity
- 0x1000, al1
.debug_get_free());
73 auto i2
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
74 ASSERT_EQ(i2
.offset
, 0x1000u
);
75 ASSERT_EQ(i2
.length
, 0x1000u
);
78 i1
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
79 ASSERT_EQ(i1
.offset
, 0u);
80 ASSERT_EQ(i1
.length
, 0x1000u
);
81 i2
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
82 ASSERT_EQ(i2
.offset
, 0x1000u
);
83 ASSERT_EQ(i2
.length
, 0x1000u
);
87 i1
= al1
.allocate_l1_cont(0x2000, 0x1000, 0, num_l1_entries
);
88 ASSERT_EQ(i1
.offset
, 0u);
89 ASSERT_EQ(i1
.length
, 0x2000u
);
91 i2
= al1
.allocate_l1_cont(0x3000, 0x1000, 0, num_l1_entries
);
92 ASSERT_EQ(i2
.offset
, 0x2000u
);
93 ASSERT_EQ(i2
.length
, 0x3000u
);
98 i1
= al1
.allocate_l1_cont(0x2000, 0x1000, 0, num_l1_entries
);
99 ASSERT_EQ(i1
.offset
, 0u);
100 ASSERT_EQ(i1
.length
, 0x2000u
);
102 i2
= al1
.allocate_l1_cont(2 * 1024 * 1024, 0x1000, 0, num_l1_entries
);
103 ASSERT_EQ(i2
.offset
, 2u * 1024u * 1024u);
104 ASSERT_EQ(i2
.length
, 2u * 1024u * 1024u);
107 i1
= al1
.allocate_l1_cont(1024 * 1024, 0x1000, 0, num_l1_entries
);
108 ASSERT_EQ(i1
.offset
, 0u);
109 ASSERT_EQ(i1
.length
, 1024u * 1024u);
111 auto i3
= al1
.allocate_l1_cont(1024 * 1024 + 0x1000, 0x1000, 0, num_l1_entries
);
112 ASSERT_EQ(i3
.offset
, 2u * 2u * 1024u * 1024u);
113 ASSERT_EQ(i3
.length
, 1024u * 1024u + 0x1000u
);
115 // here we have the following layout:
116 // Alloc: 0~1M, 2M~2M, 4M~1M+4K
117 // Free: 1M~1M, 4M+4K ~ 2M-4K, 6M ~...
119 auto i4
= al1
.allocate_l1_cont(1024 * 1024, 0x1000, 0, num_l1_entries
);
120 ASSERT_EQ(1 * 1024 * 1024u, i4
.offset
);
121 ASSERT_EQ(1024 * 1024u, i4
.length
);
124 i4
= al1
.allocate_l1_cont(1024 * 1024 - 0x1000, 0x1000, 0, num_l1_entries
);
125 ASSERT_EQ(i4
.offset
, 5u * 1024u * 1024u + 0x1000u
);
126 ASSERT_EQ(i4
.length
, 1024u * 1024u - 0x1000u
);
129 i4
= al1
.allocate_l1_cont(1024 * 1024 + 0x1000, 0x1000, 0, num_l1_entries
);
130 ASSERT_EQ(i4
.offset
, 6u * 1024u * 1024u);
131 //ASSERT_EQ(i4.offset, 5 * 1024 * 1024 + 0x1000);
132 ASSERT_EQ(i4
.length
, 1024u * 1024u + 0x1000u
);
139 i1
= al1
.allocate_l1_cont(1024 * 1024, 0x1000, 0, num_l1_entries
);
140 ASSERT_EQ(i1
.offset
, 0u);
141 ASSERT_EQ(i1
.length
, 1024u * 1024u);
143 i2
= al1
.allocate_l1_cont(1024 * 1024, 0x1000, 0, num_l1_entries
);
144 ASSERT_EQ(i2
.offset
, 1u * 1024u * 1024u);
145 ASSERT_EQ(i2
.length
, 1024u * 1024u);
147 i3
= al1
.allocate_l1_cont(512 * 1024, 0x1000, 0, num_l1_entries
);
148 ASSERT_EQ(i3
.offset
, 2u * 1024u * 1024u);
149 ASSERT_EQ(i3
.length
, 512u * 1024u);
151 i4
= al1
.allocate_l1_cont(1536 * 1024, 0x1000, 0, num_l1_entries
);
152 ASSERT_EQ(i4
.offset
, (2u * 1024u + 512u) * 1024u);
153 ASSERT_EQ(i4
.length
, 1536u * 1024u);
154 // making a hole 1.5 Mb length
157 // and trying to fill it
158 i2
= al1
.allocate_l1_cont(1536 * 1024, 0x1000, 0, num_l1_entries
);
159 ASSERT_EQ(i2
.offset
, 1024u * 1024u);
160 ASSERT_EQ(i2
.length
, 1536u * 1024u);
163 // and trying to fill it partially
164 i2
= al1
.allocate_l1_cont(1528 * 1024, 0x1000, 0, num_l1_entries
);
165 ASSERT_EQ(i2
.offset
, 1024u * 1024u);
166 ASSERT_EQ(i2
.length
, 1528u * 1024u);
168 i3
= al1
.allocate_l1_cont(8 * 1024, 0x1000, 0, num_l1_entries
);
169 ASSERT_EQ(i3
.offset
, 2552u * 1024u);
170 ASSERT_EQ(i3
.length
, 8u * 1024u);
173 // here we have the following layout:
174 // Alloc: 0~1M, 2552K~8K, num_l1_entries0K~1.5M
175 // Free: 1M~1528K, 4M ~...
177 i2
= al1
.allocate_l1_cont(1536 * 1024, 0x1000, 0, num_l1_entries
);
178 ASSERT_EQ(i2
.offset
, 4u * 1024u * 1024u);
179 ASSERT_EQ(i2
.length
, 1536u * 1024u);
185 ASSERT_EQ(capacity
, al1
.debug_get_free());
187 for (uint64_t i
= 0; i
< capacity
; i
+= _2m
) {
188 i1
= al1
.allocate_l1_cont(_2m
, _2m
, 0, num_l1_entries
);
189 ASSERT_EQ(i1
.offset
, i
);
190 ASSERT_EQ(i1
.length
, _2m
);
192 ASSERT_EQ(0u, al1
.debug_get_free());
193 i2
= al1
.allocate_l1_cont(_2m
, _2m
, 0, num_l1_entries
);
194 ASSERT_EQ(i2
.length
, 0u);
195 ASSERT_EQ(0u, al1
.debug_get_free());
198 i2
= al1
.allocate_l1_cont(_2m
, _2m
, 0, num_l1_entries
);
201 i2
= al1
.allocate_l1_cont(_1m
, _1m
, 0, num_l1_entries
);
202 ASSERT_EQ(i2
.offset
, i1
.offset
);
203 ASSERT_EQ(i2
.length
, _1m
);
205 i3
= al1
.allocate_l1_cont(_2m
, _2m
, 0, num_l1_entries
);
206 ASSERT_EQ(i3
.length
, 0u);
208 i3
= al1
.allocate_l1_cont(_2m
, _1m
, 0, num_l1_entries
);
209 ASSERT_EQ(i3
.length
, _1m
);
211 i4
= al1
.allocate_l1_cont(_2m
, _1m
, 0, num_l1_entries
);
212 ASSERT_EQ(i4
.length
, 0u);
215 i2
= al1
.allocate_l1_cont(_2m
, _2m
, 0, num_l1_entries
);
216 ASSERT_EQ(i2
.length
, 0u);
218 i2
= al1
.allocate_l1_cont(_2m
, 0x1000, 0, num_l1_entries
);
219 ASSERT_EQ(i2
.length
, _1m
);
223 ASSERT_EQ(_2m
, al1
.debug_get_free());
225 i1
= al1
.allocate_l1_cont(_2m
- 3 * 0x1000, 0x1000, 0, num_l1_entries
);
226 i2
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
227 i3
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
228 i4
= al1
.allocate_l1_cont(0x1000, 0x1000, 0, num_l1_entries
);
229 ASSERT_EQ(0u, al1
.debug_get_free());
234 i2
= al1
.allocate_l1_cont(0x4000, 0x2000, 0, num_l1_entries
);
235 ASSERT_EQ(i2
.length
, 0u);
236 i2
= al1
.allocate_l1_cont(0x4000, 0x1000, 0, num_l1_entries
);
237 ASSERT_EQ(i2
.length
, 0x1000u
);
240 i3
= al1
.allocate_l1_cont(0x6000, 0x3000, 0, num_l1_entries
);
241 ASSERT_EQ(i3
.length
, 0u);
242 i3
= al1
.allocate_l1_cont(0x6000, 0x1000, 0, num_l1_entries
);
243 ASSERT_EQ(i3
.length
, 0x2000u
);
244 ASSERT_EQ(0u, al1
.debug_get_free());
246 std::cout
<< "Done L1" << std::endl
;
249 TEST(TestAllocatorLevel01
, test_l2
)
251 TestAllocatorLevel02 al2
;
252 uint64_t num_l2_entries
= 64;// *512;
253 uint64_t capacity
= num_l2_entries
* 256 * 512 * 4096;
254 al2
.init(capacity
, 0x1000);
255 std::cout
<< "Init L2" << std::endl
;
257 uint64_t allocated1
= 0;
258 interval_vector_t a1
;
259 al2
.allocate_l2(0x2000, 0x2000, &allocated1
, &a1
);
260 ASSERT_EQ(allocated1
, 0x2000u
);
261 ASSERT_EQ(a1
[0].offset
, 0u);
262 ASSERT_EQ(a1
[0].length
, 0x2000u
);
264 // limit query range in debug_get_free for the sake of performance
265 ASSERT_EQ(0x2000u
, al2
.debug_get_allocated(0, 1));
266 ASSERT_EQ(0u, al2
.debug_get_allocated(1, 2));
268 uint64_t allocated2
= 0;
269 interval_vector_t a2
;
270 al2
.allocate_l2(0x2000, 0x2000, &allocated2
, &a2
);
271 ASSERT_EQ(allocated2
, 0x2000u
);
272 ASSERT_EQ(a2
[0].offset
, 0x2000u
);
273 ASSERT_EQ(a2
[0].length
, 0x2000u
);
274 // limit query range in debug_get_free for the sake of performance
275 ASSERT_EQ(0x4000u
, al2
.debug_get_allocated(0, 1));
276 ASSERT_EQ(0u, al2
.debug_get_allocated(1, 2));
282 al2
.allocate_l2(0x1000, 0x1000, &allocated2
, &a2
);
283 ASSERT_EQ(allocated2
, 0x1000u
);
284 ASSERT_EQ(a2
[0].offset
, 0x0000u
);
285 ASSERT_EQ(a2
[0].length
, 0x1000u
);
286 // limit query range in debug_get_free for the sake of performance
287 ASSERT_EQ(0x3000u
, al2
.debug_get_allocated(0, 1));
288 ASSERT_EQ(0u, al2
.debug_get_allocated(1, 2));
290 uint64_t allocated3
= 0;
291 interval_vector_t a3
;
292 al2
.allocate_l2(0x2000, 0x1000, &allocated3
, &a3
);
293 ASSERT_EQ(allocated3
, 0x2000u
);
294 ASSERT_EQ(a3
.size(), 2u);
295 ASSERT_EQ(a3
[0].offset
, 0x1000u
);
296 ASSERT_EQ(a3
[0].length
, 0x1000u
);
297 ASSERT_EQ(a3
[1].offset
, 0x4000u
);
298 ASSERT_EQ(a3
[1].length
, 0x1000u
);
299 // limit query range in debug_get_free for the sake of performance
300 ASSERT_EQ(0x5000u
, al2
.debug_get_allocated(0, 1));
301 ASSERT_EQ(0u, al2
.debug_get_allocated(1, 2));
304 r
.emplace_back(0x0, 0x5000);
310 al2
.allocate_l2(_1m
, _1m
, &allocated3
, &a3
);
311 ASSERT_EQ(a3
.size(), 1u);
312 ASSERT_EQ(a3
[0].offset
, 0u);
313 ASSERT_EQ(a3
[0].length
, _1m
);
319 al2
.allocate_l2(4 * _1m
, _1m
, &allocated3
, &a3
);
320 ASSERT_EQ(a3
.size(), 1u);
321 ASSERT_EQ(a3
[0].offset
, 0u);
322 ASSERT_EQ(a3
[0].length
, 4 * _1m
);
327 for (uint64_t i
= 0; i
< capacity
; i
+= 0x1000) {
328 uint64_t allocated4
= 0;
329 interval_vector_t a4
;
330 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
331 ASSERT_EQ(a4
.size(), 1u);
332 ASSERT_EQ(a4
[0].offset
, i
);
333 ASSERT_EQ(a4
[0].length
, 0x1000u
);
334 if (0 == (i
% (1 * 1024 * _1m
))) {
335 std::cout
<< "alloc1 " << i
/ 1024 / 1024 << " mb of "
336 << capacity
/ 1024 / 1024 << std::endl
;
340 for (uint64_t i
= 0; i
< capacity
; i
+= _2m
) {
341 uint64_t allocated4
= 0;
342 interval_vector_t a4
;
343 al2
.allocate_l2(_2m
, _2m
, &allocated4
, &a4
);
344 ASSERT_EQ(a4
.size(), 1);
345 ASSERT_EQ(a4
[0].offset
, i
);
346 ASSERT_EQ(a4
[0].length
, _2m
);
347 if (0 == (i
% (1 * 1024 * _1m
))) {
348 std::cout
<< "alloc1 " << i
/ 1024 / 1024 << " mb of "
349 << capacity
/ 1024 / 1024 << std::endl
;
354 ASSERT_EQ(0u, al2
.debug_get_free());
355 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
) {
357 r
.emplace_back(i
, _1m
);
359 if (0 == (i
% (1 * 1024 * _1m
))) {
360 std::cout
<< "free1 " << i
/ 1024 / 1024 << " mb of "
361 << capacity
/ 1024 / 1024 << std::endl
;
364 ASSERT_EQ(capacity
, al2
.debug_get_free());
366 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
) {
367 uint64_t allocated4
= 0;
368 interval_vector_t a4
;
369 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
370 ASSERT_EQ(a4
.size(), 1u);
371 ASSERT_EQ(allocated4
, _1m
);
372 ASSERT_EQ(a4
[0].offset
, i
);
373 ASSERT_EQ(a4
[0].length
, _1m
);
374 if (0 == (i
% (1 * 1024 * _1m
))) {
375 std::cout
<< "alloc2 " << i
/ 1024 / 1024 << " mb of "
376 << capacity
/ 1024 / 1024 << std::endl
;
379 ASSERT_EQ(0u, al2
.debug_get_free());
380 uint64_t allocated4
= 0;
381 interval_vector_t a4
;
382 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
383 ASSERT_EQ(a4
.size(), 0u);
384 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
385 ASSERT_EQ(a4
.size(), 0u);
387 for (uint64_t i
= 0; i
< capacity
; i
+= 0x2000) {
389 r
.emplace_back(i
, 0x1000);
391 if (0 == (i
% (1 * 1024 * _1m
))) {
392 std::cout
<< "free2 " << i
/ 1024 / 1024 << " mb of "
393 << capacity
/ 1024 / 1024 << std::endl
;
396 ASSERT_EQ(capacity
/ 2, al2
.debug_get_free());
398 // unable to allocate due to fragmentation
399 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
400 ASSERT_EQ(a4
.size(), 0u);
402 for (uint64_t i
= 0; i
< capacity
; i
+= 2 * _1m
) {
405 al2
.allocate_l2(_1m
, 0x1000, &allocated4
, &a4
);
406 ASSERT_EQ(a4
.size(), _1m
/ 0x1000);
407 ASSERT_EQ(allocated4
, _1m
);
408 ASSERT_EQ(a4
[0].offset
, i
);
409 ASSERT_EQ(a4
[0].length
, 0x1000u
);
410 if (0 == (i
% (1 * 1024 * _1m
))) {
411 std::cout
<< "alloc3 " << i
/ 1024 / 1024 << " mb of "
412 << capacity
/ 1024 / 1024 << std::endl
;
415 ASSERT_EQ(0u, al2
.debug_get_free());
417 std::cout
<< "Done L2" << std::endl
;
420 TEST(TestAllocatorLevel01
, test_l2_huge
)
422 TestAllocatorLevel02 al2
;
423 uint64_t num_l2_entries
= 4 * 512;
424 uint64_t capacity
= num_l2_entries
* 256 * 512 * 4096; // 1 TB
425 al2
.init(capacity
, 0x1000);
426 std::cout
<< "Init L2 Huge" << std::endl
;
428 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
) {
429 uint64_t allocated4
= 0;
430 interval_vector_t a4
;
431 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
432 ASSERT_EQ(a4
.size(), 1u);
433 ASSERT_EQ(allocated4
, 0x1000u
);
434 ASSERT_EQ(a4
[0].offset
, i
);
435 ASSERT_EQ(a4
[0].length
, 0x1000u
);
439 al2
.allocate_l2(_1m
- 0x1000, 0x1000, &allocated4
, &a4
);
440 ASSERT_EQ(a4
.size(), 1u);
441 ASSERT_EQ(allocated4
, _1m
- 0x1000);
442 ASSERT_EQ(a4
[0].offset
, i
+ 0x1000);
443 ASSERT_EQ(a4
[0].length
, _1m
- 0x1000);
444 if (0 == (i
% (1 * 1024 * _1m
))) {
445 std::cout
<< "allocH " << i
/ 1024 / 1024 << " mb of "
446 << capacity
/ 1024 / 1024 << std::endl
;
449 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
) {
450 interval_vector_t a4
;
451 a4
.emplace_back(i
, 0x1000);
453 if (0 == (i
% (1 * 1024 * _1m
))) {
454 std::cout
<< "freeH1 " << i
/ 1024 / 1024 << " mb of "
455 << capacity
/ 1024 / 1024 << std::endl
;
459 std::cout
<< "Try" << std::endl
;
460 time_t t
= time(NULL
);
461 for (int i
= 0; i
< 10; ++i
) {
462 uint64_t allocated
= 0;
464 al2
.allocate_l2(0x2000, 0x2000, &allocated
, &a
);
465 ASSERT_EQ(a
.size(), 0u);
467 std::cout
<< "End try in " << time(NULL
) - t
<< " seconds" << std::endl
;
470 std::cout
<< "Try" << std::endl
;
471 time_t t
= time(NULL
);
472 for (int i
= 0; i
< 10; ++i
) {
473 uint64_t allocated
= 0;
475 al2
.allocate_l2(_2m
, _2m
, &allocated
, &a
);
476 ASSERT_EQ(a
.size(), 0u);
478 std::cout
<< "End try in " << time(NULL
) - t
<< " seconds" << std::endl
;
481 ASSERT_EQ((capacity
/ _1m
) * 0x1000, al2
.debug_get_free());
483 std::cout
<< "Done L2 Huge" << std::endl
;
486 TEST(TestAllocatorLevel01
, test_l2_unaligned
)
489 TestAllocatorLevel02 al2
;
490 uint64_t num_l2_entries
= 3;
491 uint64_t capacity
= num_l2_entries
* 256 * 512 * 4096; // 3x512 MB
492 al2
.init(capacity
, 0x1000);
493 std::cout
<< "Init L2 Unaligned" << std::endl
;
495 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
/ 2) {
496 uint64_t allocated4
= 0;
497 interval_vector_t a4
;
498 al2
.allocate_l2(_1m
/ 2, _1m
/ 2, &allocated4
, &a4
);
499 ASSERT_EQ(a4
.size(), 1u);
500 ASSERT_EQ(allocated4
, _1m
/ 2);
501 ASSERT_EQ(a4
[0].offset
, i
);
502 ASSERT_EQ(a4
[0].length
, _1m
/ 2);
503 if (0 == (i
% (1 * 1024 * _1m
))) {
504 std::cout
<< "allocU " << i
/ 1024 / 1024 << " mb of "
505 << capacity
/ 1024 / 1024 << std::endl
;
508 ASSERT_EQ(0u, al2
.debug_get_free());
510 // no space to allocate
511 uint64_t allocated4
= 0;
512 interval_vector_t a4
;
513 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
514 ASSERT_EQ(a4
.size(), 0u);
518 TestAllocatorLevel02 al2
;
519 uint64_t capacity
= 500 * 512 * 4096; // 500x2 MB
520 al2
.init(capacity
, 0x1000);
521 std::cout
<< ("Init L2 Unaligned2\n");
522 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
/ 2) {
523 uint64_t allocated4
= 0;
524 interval_vector_t a4
;
525 al2
.allocate_l2(_1m
/ 2, _1m
/ 2, &allocated4
, &a4
);
526 ASSERT_EQ(a4
.size(), 1u);
527 ASSERT_EQ(allocated4
, _1m
/ 2);
528 ASSERT_EQ(a4
[0].offset
, i
);
529 ASSERT_EQ(a4
[0].length
, _1m
/ 2);
530 if (0 == (i
% (1 * 1024 * _1m
))) {
531 std::cout
<< "allocU2 " << i
/ 1024 / 1024 << " mb of "
532 << capacity
/ 1024 / 1024 << std::endl
;
535 ASSERT_EQ(0u, al2
.debug_get_free());
537 // no space to allocate
538 uint64_t allocated4
= 0;
539 interval_vector_t a4
;
540 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
541 ASSERT_EQ(a4
.size(), 0u);
546 TestAllocatorLevel02 al2
;
547 uint64_t capacity
= 100 * 512 * 4096 + 127 * 4096;
548 al2
.init(capacity
, 0x1000);
549 std::cout
<< "Init L2 Unaligned2" << std::endl
;
550 for (uint64_t i
= 0; i
< capacity
; i
+= 0x1000) {
551 uint64_t allocated4
= 0;
552 interval_vector_t a4
;
553 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
554 ASSERT_EQ(a4
.size(), 1u);
555 ASSERT_EQ(allocated4
, 0x1000u
);
556 ASSERT_EQ(a4
[0].offset
, i
);
557 ASSERT_EQ(a4
[0].length
, 0x1000u
);
559 ASSERT_EQ(0u, al2
.debug_get_free());
561 // no space to allocate
562 uint64_t allocated4
= 0;
563 interval_vector_t a4
;
564 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
565 ASSERT_EQ(a4
.size(), 0u);
569 TestAllocatorLevel02 al2
;
570 uint64_t capacity
= 3 * 4096;
571 al2
.init(capacity
, 0x1000);
572 std::cout
<< "Init L2 Unaligned2" << std::endl
;
573 for (uint64_t i
= 0; i
< capacity
; i
+= 0x1000) {
574 uint64_t allocated4
= 0;
575 interval_vector_t a4
;
576 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
577 ASSERT_EQ(a4
.size(), 1u);
578 ASSERT_EQ(allocated4
, 0x1000u
);
579 ASSERT_EQ(a4
[0].offset
, i
);
580 ASSERT_EQ(a4
[0].length
, 0x1000u
);
582 ASSERT_EQ(0u, al2
.debug_get_free());
584 // no space to allocate
585 uint64_t allocated4
= 0;
586 interval_vector_t a4
;
587 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
588 ASSERT_EQ(a4
.size(), 0u);
592 std::cout
<< "Done L2 Unaligned" << std::endl
;
595 TEST(TestAllocatorLevel01
, test_l2_contiguous_alignment
)
598 TestAllocatorLevel02 al2
;
599 uint64_t num_l2_entries
= 3;
600 uint64_t capacity
= num_l2_entries
* 256 * 512 * 4096; // 3x512 MB
601 uint64_t num_chunks
= capacity
/ 4096;
602 al2
.init(capacity
, 4096);
603 std::cout
<< "Init L2 cont aligned" << std::endl
;
605 std::map
<size_t, size_t> bins_overall
;
606 al2
.collect_stats(bins_overall
);
607 ASSERT_EQ(bins_overall
.size(), 1u);
608 // std::cout<<bins_overall.begin()->first << std::endl;
609 ASSERT_EQ(bins_overall
[cbits(num_chunks
) - 1], 1u);
611 for (uint64_t i
= 0; i
< capacity
/ 2; i
+= _1m
) {
612 uint64_t allocated4
= 0;
613 interval_vector_t a4
;
614 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
615 ASSERT_EQ(a4
.size(), 1u);
616 ASSERT_EQ(allocated4
, _1m
);
617 ASSERT_EQ(a4
[0].offset
, i
);
618 ASSERT_EQ(a4
[0].length
, _1m
);
620 ASSERT_EQ(capacity
/ 2, al2
.debug_get_free());
622 bins_overall
.clear();
623 al2
.collect_stats(bins_overall
);
624 ASSERT_EQ(bins_overall
.size(), 1u);
625 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
628 size_t to_release
= 2 * _1m
+ 0x1000;
629 // release 2M + 4K at the beginning
631 r
.emplace_back(0, to_release
);
633 bins_overall
.clear();
634 al2
.collect_stats(bins_overall
);
635 ASSERT_EQ(bins_overall
.size(), 2u);
636 ASSERT_EQ(bins_overall
[cbits(to_release
/ 0x1000) - 1], 1u);
637 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
640 // allocate 4K within the deallocated range
641 uint64_t allocated4
= 0;
642 interval_vector_t a4
;
643 al2
.allocate_l2(0x1000, 0x1000, &allocated4
, &a4
);
644 ASSERT_EQ(a4
.size(), 1u);
645 ASSERT_EQ(allocated4
, 0x1000u
);
646 ASSERT_EQ(a4
[0].offset
, 0u);
647 ASSERT_EQ(a4
[0].length
, 0x1000u
);
648 bins_overall
.clear();
649 al2
.collect_stats(bins_overall
);
650 ASSERT_EQ(bins_overall
.size(), 2u);
651 ASSERT_EQ(bins_overall
[cbits(2 * _1m
/ 0x1000) - 1], 1u);
652 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
655 // allocate 1M - should go to the second 1M chunk
656 uint64_t allocated4
= 0;
657 interval_vector_t a4
;
658 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
659 ASSERT_EQ(a4
.size(), 1u);
660 ASSERT_EQ(allocated4
, _1m
);
661 ASSERT_EQ(a4
[0].offset
, _1m
);
662 ASSERT_EQ(a4
[0].length
, _1m
);
663 bins_overall
.clear();
664 al2
.collect_stats(bins_overall
);
665 ASSERT_EQ(bins_overall
.size(), 3u);
666 ASSERT_EQ(bins_overall
[0], 1u);
667 ASSERT_EQ(bins_overall
[cbits((_1m
- 0x1000) / 0x1000) - 1], 1u);
668 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
671 // and allocate yet another 8K within the deallocated range
672 uint64_t allocated4
= 0;
673 interval_vector_t a4
;
674 al2
.allocate_l2(0x2000, 0x1000, &allocated4
, &a4
);
675 ASSERT_EQ(a4
.size(), 1u);
676 ASSERT_EQ(allocated4
, 0x2000u
);
677 ASSERT_EQ(a4
[0].offset
, 0x1000u
);
678 ASSERT_EQ(a4
[0].length
, 0x2000u
);
679 bins_overall
.clear();
680 al2
.collect_stats(bins_overall
);
681 ASSERT_EQ(bins_overall
[0], 1u);
682 ASSERT_EQ(bins_overall
[cbits((_1m
- 0x3000) / 0x1000) - 1], 1u);
683 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
686 // release just allocated 1M
688 r
.emplace_back(_1m
, _1m
);
690 bins_overall
.clear();
691 al2
.collect_stats(bins_overall
);
692 ASSERT_EQ(bins_overall
.size(), 2u);
693 ASSERT_EQ(bins_overall
[cbits((2 * _1m
- 0x3000) / 0x1000) - 1], 1u);
694 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
697 // allocate 3M - should go to the second 1M chunk and @capacity/2
698 uint64_t allocated4
= 0;
699 interval_vector_t a4
;
700 al2
.allocate_l2(3 * _1m
, _1m
, &allocated4
, &a4
);
701 ASSERT_EQ(a4
.size(), 2u);
702 ASSERT_EQ(allocated4
, 3 * _1m
);
703 ASSERT_EQ(a4
[0].offset
, _1m
);
704 ASSERT_EQ(a4
[0].length
, _1m
);
705 ASSERT_EQ(a4
[1].offset
, capacity
/ 2);
706 ASSERT_EQ(a4
[1].length
, 2 * _1m
);
707 bins_overall
.clear();
708 al2
.collect_stats(bins_overall
);
709 ASSERT_EQ(bins_overall
.size(), 3u);
710 ASSERT_EQ(bins_overall
[0], 1u);
711 ASSERT_EQ(bins_overall
[cbits((_1m
- 0x3000) / 0x1000) - 1], 1u);
712 ASSERT_EQ(bins_overall
[cbits((num_chunks
- 512) / 2) - 1], 1u);
715 // release allocated 1M in the second meg chunk except
716 // the first 4K chunk
718 r
.emplace_back(_1m
+ 0x1000, _1m
);
720 bins_overall
.clear();
721 al2
.collect_stats(bins_overall
);
722 ASSERT_EQ(bins_overall
.size(), 3u);
723 ASSERT_EQ(bins_overall
[cbits(_1m
/ 0x1000) - 1], 1u);
724 ASSERT_EQ(bins_overall
[cbits((_1m
- 0x3000) / 0x1000) - 1], 1u);
725 ASSERT_EQ(bins_overall
[cbits((num_chunks
- 512) / 2) - 1], 1u);
728 // release 2M @(capacity / 2)
730 r
.emplace_back(capacity
/ 2, 2 * _1m
);
732 bins_overall
.clear();
733 al2
.collect_stats(bins_overall
);
734 ASSERT_EQ(bins_overall
.size(), 3u);
735 ASSERT_EQ(bins_overall
[cbits(_1m
/ 0x1000) - 1], 1u);
736 ASSERT_EQ(bins_overall
[cbits((_1m
- 0x3000) / 0x1000) - 1], 1u);
737 ASSERT_EQ(bins_overall
[cbits((num_chunks
) / 2) - 1], 1u);
740 // allocate 4x512K - should go to the second halves of
741 // the first and second 1M chunks and @(capacity / 2)
742 uint64_t allocated4
= 0;
743 interval_vector_t a4
;
744 al2
.allocate_l2(2 * _1m
, _1m
/ 2, &allocated4
, &a4
);
745 ASSERT_EQ(a4
.size(), 3u);
746 ASSERT_EQ(allocated4
, 2 * _1m
);
747 ASSERT_EQ(a4
[0].offset
, _1m
/ 2);
748 ASSERT_EQ(a4
[0].length
, _1m
/ 2);
749 ASSERT_EQ(a4
[1].offset
, _1m
+ _1m
/ 2);
750 ASSERT_EQ(a4
[1].length
, _1m
/ 2);
751 ASSERT_EQ(a4
[2].offset
, capacity
/ 2);
752 ASSERT_EQ(a4
[2].length
, _1m
);
754 bins_overall
.clear();
755 al2
.collect_stats(bins_overall
);
756 ASSERT_EQ(bins_overall
.size(), 3u);
757 ASSERT_EQ(bins_overall
[0], 1u);
758 // below we have 512K - 4K & 512K - 12K chunks which both fit into
760 ASSERT_EQ(bins_overall
[6], 2u);
761 ASSERT_EQ(bins_overall
[cbits((num_chunks
- 256) / 2) - 1], 1u);
765 // cleanup first 2M except except the last 4K chunk
767 r
.emplace_back(0, 2 * _1m
- 0x1000);
769 bins_overall
.clear();
770 al2
.collect_stats(bins_overall
);
772 ASSERT_EQ(bins_overall
.size(), 3u);
773 ASSERT_EQ(bins_overall
[0], 1u);
774 ASSERT_EQ(bins_overall
[cbits((_2m
- 0x1000) / 0x1000) - 1], 1u);
775 ASSERT_EQ(bins_overall
[cbits((num_chunks
- 256) / 2) - 1], 1u);
778 // release 2M @(capacity / 2)
780 r
.emplace_back(capacity
/ 2, 2 * _1m
);
782 bins_overall
.clear();
783 al2
.collect_stats(bins_overall
);
785 ASSERT_EQ(bins_overall
.size(), 3u);
786 ASSERT_EQ(bins_overall
[0], 1u);
787 ASSERT_EQ(bins_overall
[cbits((_2m
- 0x1000) / 0x1000) - 1], 1u);
788 ASSERT_EQ(bins_overall
[cbits(num_chunks
/ 2) - 1], 1u);
791 // allocate 132M using 4M granularity should go to (capacity / 2)
792 uint64_t allocated4
= 0;
793 interval_vector_t a4
;
794 al2
.allocate_l2(132 * _1m
, 4 * _1m
, &allocated4
, &a4
);
795 ASSERT_EQ(a4
.size(), 1u);
796 ASSERT_EQ(a4
[0].offset
, capacity
/ 2);
797 ASSERT_EQ(a4
[0].length
, 132 * _1m
);
799 bins_overall
.clear();
800 al2
.collect_stats(bins_overall
);
801 ASSERT_EQ(bins_overall
.size(), 3u);
804 // cleanup left 4K chunk in the first 2M
806 r
.emplace_back(2 * _1m
- 0x1000, 0x1000);
808 bins_overall
.clear();
809 al2
.collect_stats(bins_overall
);
811 ASSERT_EQ(bins_overall
.size(), 2u);
814 // release 132M @(capacity / 2)
816 r
.emplace_back(capacity
/ 2, 132 * _1m
);
820 // allocate 132M using 2M granularity should go to the first chunk and to
822 uint64_t allocated4
= 0;
823 interval_vector_t a4
;
824 al2
.allocate_l2(132 * _1m
, 2 * _1m
, &allocated4
, &a4
);
825 ASSERT_EQ(a4
.size(), 2u);
826 ASSERT_EQ(a4
[0].offset
, 0u);
827 ASSERT_EQ(a4
[0].length
, 2 * _1m
);
828 ASSERT_EQ(a4
[1].offset
, capacity
/ 2);
829 ASSERT_EQ(a4
[1].length
, 130 * _1m
);
832 // release 130M @(capacity / 2)
834 r
.emplace_back(capacity
/ 2, 132 * _1m
);
842 r
.emplace_back(0x1000, 0x4000);
843 r
.emplace_back(0x7000, 0x8000);
844 r
.emplace_back(0x11000, 0x6000);
848 // allocate 32K using 16K granularity - should bypass the first
849 // unaligned extent, use the second free extent partially given
850 // the 16K alignment and then fallback to capacity / 2
851 uint64_t allocated4
= 0;
852 interval_vector_t a4
;
853 al2
.allocate_l2(0x8000, 0x4000, &allocated4
, &a4
);
854 ASSERT_EQ(a4
.size(), 2u);
855 ASSERT_EQ(a4
[0].offset
, 0x8000u
);
856 ASSERT_EQ(a4
[0].length
, 0x4000u
);
857 ASSERT_EQ(a4
[1].offset
, capacity
/ 2);
858 ASSERT_EQ(a4
[1].length
, 0x4000u
);
862 std::cout
<< "Done L2 cont aligned" << std::endl
;
865 TEST(TestAllocatorLevel01
, test_4G_alloc_bug
)
868 TestAllocatorLevel02 al2
;
869 uint64_t capacity
= 0x8000 * _1m
; // = 32GB
870 al2
.init(capacity
, 0x10000);
871 std::cout
<< "Init L2 cont aligned" << std::endl
;
873 uint64_t allocated4
= 0;
874 interval_vector_t a4
;
875 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
876 ASSERT_EQ(a4
.size(), 1u); // the bug caused no allocations here
877 ASSERT_EQ(allocated4
, _1m
);
878 ASSERT_EQ(a4
[0].offset
, 0u);
879 ASSERT_EQ(a4
[0].length
, _1m
);
883 TEST(TestAllocatorLevel01
, test_4G_alloc_bug2
)
886 TestAllocatorLevel02 al2
;
887 uint64_t capacity
= 0x8000 * _1m
; // = 32GB
888 al2
.init(capacity
, 0x10000);
890 for (uint64_t i
= 0; i
< capacity
; i
+= _1m
) {
891 uint64_t allocated4
= 0;
892 interval_vector_t a4
;
893 al2
.allocate_l2(_1m
, _1m
, &allocated4
, &a4
);
894 ASSERT_EQ(a4
.size(), 1u);
895 ASSERT_EQ(allocated4
, _1m
);
896 ASSERT_EQ(a4
[0].offset
, i
);
897 ASSERT_EQ(a4
[0].length
, _1m
);
899 ASSERT_EQ(0u , al2
.debug_get_free());
902 r
.emplace_back(0x5fec30000, 0x13d0000);
903 r
.emplace_back(0x628000000, 0x80000000);
904 r
.emplace_back(0x6a8000000, 0x80000000);
905 r
.emplace_back(0x728100000, 0x70000);
908 std::map
<size_t, size_t> bins_overall
;
909 al2
.collect_stats(bins_overall
);
911 uint64_t allocated4
= 0;
912 interval_vector_t a4
;
913 al2
.allocate_l2(0x3e000000, _1m
, &allocated4
, &a4
);
914 ASSERT_EQ(a4
.size(), 2u);
915 ASSERT_EQ(allocated4
, 0x3e000000u
);
916 ASSERT_EQ(a4
[0].offset
, 0x5fed00000u
);
917 ASSERT_EQ(a4
[0].length
, 0x1300000u
);
918 ASSERT_EQ(a4
[1].offset
, 0x628000000u
);
919 ASSERT_EQ(a4
[1].length
, 0x3cd00000u
);
923 TEST(TestAllocatorLevel01
, test_4G_alloc_bug3
)
926 TestAllocatorLevel02 al2
;
927 uint64_t capacity
= 0x8000 * _1m
; // = 32GB
928 al2
.init(capacity
, 0x10000);
929 std::cout
<< "Init L2 cont aligned" << std::endl
;
931 uint64_t allocated4
= 0;
932 interval_vector_t a4
;
933 al2
.allocate_l2(4096ull * _1m
, _1m
, &allocated4
, &a4
);
934 ASSERT_EQ(a4
.size(), 2u); // allocator has to split into 2 allocations
935 ASSERT_EQ(allocated4
, 4096ull * _1m
);
936 ASSERT_EQ(a4
[0].offset
, 0u);
937 ASSERT_EQ(a4
[0].length
, 2048ull * _1m
);
938 ASSERT_EQ(a4
[1].offset
, 2048ull * _1m
);
939 ASSERT_EQ(a4
[1].length
, 2048ull * _1m
);
943 TEST(TestAllocatorLevel01
, test_claim_free_l2
)
945 TestAllocatorLevel02 al2
;
946 uint64_t num_l2_entries
= 64;// *512;
947 uint64_t capacity
= num_l2_entries
* 256 * 512 * 4096;
948 al2
.init(capacity
, 0x1000);
949 std::cout
<< "Init L2" << std::endl
;
951 uint64_t max_available
= 0x20000;
952 al2
.mark_allocated(max_available
, capacity
- max_available
);
954 uint64_t allocated1
= 0;
955 interval_vector_t a1
;
956 al2
.allocate_l2(0x2000, 0x2000, &allocated1
, &a1
);
957 ASSERT_EQ(allocated1
, 0x2000u
);
958 ASSERT_EQ(a1
[0].offset
, 0u);
959 ASSERT_EQ(a1
[0].length
, 0x2000u
);
961 uint64_t allocated2
= 0;
962 interval_vector_t a2
;
963 al2
.allocate_l2(0x2000, 0x2000, &allocated2
, &a2
);
964 ASSERT_EQ(allocated2
, 0x2000u
);
965 ASSERT_EQ(a2
[0].offset
, 0x2000u
);
966 ASSERT_EQ(a2
[0].length
, 0x2000u
);
968 uint64_t allocated3
= 0;
969 interval_vector_t a3
;
970 al2
.allocate_l2(0x3000, 0x3000, &allocated3
, &a3
);
971 ASSERT_EQ(allocated3
, 0x3000u
);
972 ASSERT_EQ(a3
[0].offset
, 0x4000u
);
973 ASSERT_EQ(a3
[0].length
, 0x3000u
);
977 ASSERT_EQ(max_available
- 0x2000, al2
.debug_get_free());
979 auto claimed
= al2
.claim_free_to_right(0x4000);
980 ASSERT_EQ(max_available
- 0x4000u
, claimed
);
981 ASSERT_EQ(0x2000, al2
.debug_get_free());
983 claimed
= al2
.claim_free_to_right(0x4000);
984 ASSERT_EQ(0, claimed
);
985 ASSERT_EQ(0x2000, al2
.debug_get_free());
987 claimed
= al2
.claim_free_to_left(0x2000);
988 ASSERT_EQ(0x2000u
, claimed
);
989 ASSERT_EQ(0, al2
.debug_get_free());
991 claimed
= al2
.claim_free_to_left(0x2000);
992 ASSERT_EQ(0, claimed
);
993 ASSERT_EQ(0, al2
.debug_get_free());
996 al2
.mark_free(0x3000, 0x4000);
997 ASSERT_EQ(0x4000, al2
.debug_get_free());
999 claimed
= al2
.claim_free_to_right(0x7000);
1000 ASSERT_EQ(0, claimed
);
1001 ASSERT_EQ(0x4000, al2
.debug_get_free());
1003 claimed
= al2
.claim_free_to_right(0x6000);
1004 ASSERT_EQ(0x1000, claimed
);
1005 ASSERT_EQ(0x3000, al2
.debug_get_free());
1007 claimed
= al2
.claim_free_to_right(0x6000);
1008 ASSERT_EQ(0, claimed
);
1009 ASSERT_EQ(0x3000, al2
.debug_get_free());
1011 claimed
= al2
.claim_free_to_left(0x3000);
1012 ASSERT_EQ(0u, claimed
);
1013 ASSERT_EQ(0x3000, al2
.debug_get_free());
1015 claimed
= al2
.claim_free_to_left(0x4000);
1016 ASSERT_EQ(0x1000, claimed
);
1017 ASSERT_EQ(0x2000, al2
.debug_get_free());
1019 // extend allocator space up to 64M
1020 auto max_available2
= 64 * 1024 * 1024;
1021 al2
.mark_free(max_available
, max_available2
- max_available
);
1022 ASSERT_EQ(max_available2
- max_available
+ 0x2000, al2
.debug_get_free());
1024 // pin some allocations
1025 al2
.mark_allocated(0x400000 + 0x2000, 1000);
1026 al2
.mark_allocated(0x400000 + 0x5000, 1000);
1027 al2
.mark_allocated(0x400000 + 0x20000, 1000);
1028 ASSERT_EQ(max_available2
- max_available
- 0x1000, al2
.debug_get_free());
1030 claimed
= al2
.claim_free_to_left(0x403000);
1031 ASSERT_EQ(0x0, claimed
);
1033 claimed
= al2
.claim_free_to_left(0x404000);
1034 ASSERT_EQ(0x1000, claimed
);
1035 ASSERT_EQ(max_available2
- max_available
- 0x2000, al2
.debug_get_free());
1037 claimed
= al2
.claim_free_to_left(max_available
);
1038 ASSERT_EQ(0, claimed
);
1040 claimed
= al2
.claim_free_to_left(0x400000);
1041 ASSERT_EQ(0x3e0000, claimed
);
1042 ASSERT_EQ(max_available2
- max_available
- 0x3e2000, al2
.get_available());
1043 ASSERT_EQ(max_available2
- max_available
- 0x3e2000, al2
.debug_get_free());
1045 claimed
= al2
.claim_free_to_right(0x407000);
1046 ASSERT_EQ(0x19000, claimed
);
1047 ASSERT_EQ(max_available2
- max_available
- 0x3e2000 - 0x19000,
1048 al2
.get_available());
1049 ASSERT_EQ(max_available2
- max_available
- 0x3e2000 - 0x19000,
1050 al2
.debug_get_free());
1052 claimed
= al2
.claim_free_to_right(0x407000);
1053 ASSERT_EQ(0, claimed
);
1055 claimed
= al2
.claim_free_to_right(0x430000);
1056 ASSERT_EQ(max_available2
- 0x430000, claimed
);
1058 al2
.get_available());
1060 al2
.debug_get_free());