blob: 2a5fb5c8d8ed247e4e4fa3f78b5cab006a2dd4b7 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
Dave Barachc3799992016-08-15 11:12:27 -040038#include <vppinfra/cache.h> /* for CLIB_CACHE_LINE_BYTES */
Ed Warnickecb9cada2015-12-08 15:45:58 -070039#include <vppinfra/mem.h>
40#include <vppinfra/hash.h>
41#include <vppinfra/vec.h>
42#include <vppinfra/heap.h>
43#include <vppinfra/error.h>
44
Dave Barachc3799992016-08-15 11:12:27 -040045always_inline heap_elt_t *
46elt_at (heap_header_t * h, uword i)
Ed Warnickecb9cada2015-12-08 15:45:58 -070047{
48 ASSERT (i < vec_len (h->elts));
49 return h->elts + i;
50}
51
Dave Barachc3799992016-08-15 11:12:27 -040052always_inline heap_elt_t *
53last (heap_header_t * h)
54{
55 return elt_at (h, h->tail);
56}
Ed Warnickecb9cada2015-12-08 15:45:58 -070057
Dave Barachc3799992016-08-15 11:12:27 -040058always_inline heap_elt_t *
59first (heap_header_t * h)
60{
61 return elt_at (h, h->head);
62}
Ed Warnickecb9cada2015-12-08 15:45:58 -070063
64/* Objects sizes are binned into N_BINS bins.
65 Objects with size <= SMALL_BINS have their own bins.
66 Larger objects are grouped together in power or 2 sized
67 bins.
68
69 Sizes are in units of elt_bytes bytes. */
70
71/* Convert size to bin. */
Dave Barachc3799992016-08-15 11:12:27 -040072always_inline uword
73size_to_bin (uword size)
Ed Warnickecb9cada2015-12-08 15:45:58 -070074{
75 uword bin;
76
77 ASSERT (size > 0);
78
79 if (size <= HEAP_SMALL_BINS)
80 {
81 bin = size - 1;
82 if (size == 0)
83 bin = 0;
84 }
85 else
86 {
87 bin = HEAP_SMALL_BINS + max_log2 (size) - (HEAP_LOG2_SMALL_BINS + 1);
88 if (bin >= HEAP_N_BINS)
89 bin = HEAP_N_BINS - 1;
90 }
91
92 return bin;
93}
94
95/* Convert bin to size. */
Dave Barachc3799992016-08-15 11:12:27 -040096always_inline __attribute__ ((unused))
97 uword bin_to_size (uword bin)
Ed Warnickecb9cada2015-12-08 15:45:58 -070098{
99 uword size;
100
101 if (bin <= HEAP_SMALL_BINS - 1)
102 size = bin + 1;
103 else
104 size = (uword) 1 << ((bin - HEAP_SMALL_BINS) + HEAP_LOG2_SMALL_BINS + 1);
105
106 return size;
107}
108
Dave Barachc3799992016-08-15 11:12:27 -0400109static void
110elt_delete (heap_header_t * h, heap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111{
Dave Barachc3799992016-08-15 11:12:27 -0400112 heap_elt_t *l = vec_end (h->elts) - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113
114 ASSERT (e >= h->elts && e <= l);
115
116 /* Update doubly linked pointers. */
117 {
Dave Barachc3799992016-08-15 11:12:27 -0400118 heap_elt_t *p = heap_prev (e);
119 heap_elt_t *n = heap_next (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
121 if (p == e)
122 {
123 n->prev = 0;
124 h->head = n - h->elts;
125 }
126 else if (n == e)
127 {
128 p->next = 0;
129 h->tail = p - h->elts;
130 }
131 else
132 {
133 p->next = n - p;
134 n->prev = p - n;
135 }
136 }
137
138 /* Add to index free list or delete from end. */
139 if (e < l)
140 vec_add1 (h->free_elts, e - h->elts);
141 else
142 _vec_len (h->elts)--;
143}
144
145/*
146 Before: P ... E
147 After : P ... NEW ... E
148*/
Dave Barachc3799992016-08-15 11:12:27 -0400149always_inline void
150elt_insert_before (heap_header_t * h, heap_elt_t * e, heap_elt_t * new)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151{
Dave Barachc3799992016-08-15 11:12:27 -0400152 heap_elt_t *p = heap_prev (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153
154 if (p == e)
155 {
156 new->prev = 0;
157 new->next = e - new;
158 p->prev = new - p;
159 h->head = new - h->elts;
160 }
161 else
162 {
163 new->prev = p - new;
164 new->next = e - new;
165 e->prev = new - e;
166 p->next = new - p;
167 }
168}
169
170/*
171 Before: E ... N
172 After : E ... NEW ... N
173*/
Dave Barachc3799992016-08-15 11:12:27 -0400174always_inline void
175elt_insert_after (heap_header_t * h, heap_elt_t * e, heap_elt_t * new)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176{
Dave Barachc3799992016-08-15 11:12:27 -0400177 heap_elt_t *n = heap_next (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178
179 if (n == e)
180 {
181 new->next = 0;
182 new->prev = e - new;
183 e->next = new - e;
184 h->tail = new - h->elts;
185 }
186 else
187 {
188 new->prev = e - new;
189 new->next = n - new;
190 e->next = new - e;
191 n->prev = new - n;
192 }
193}
194
Dave Barachc3799992016-08-15 11:12:27 -0400195always_inline heap_elt_t *
196elt_new (heap_header_t * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197{
Dave Barachc3799992016-08-15 11:12:27 -0400198 heap_elt_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 uword l;
200 if ((l = vec_len (h->free_elts)) > 0)
201 {
Dave Barachc3799992016-08-15 11:12:27 -0400202 e = elt_at (h, h->free_elts[l - 1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 _vec_len (h->free_elts) -= 1;
204 }
205 else
206 vec_add2 (h->elts, e, 1);
207 return e;
208}
209
210/* Return pointer to object at given offset.
211 Used to write free list index of free objects. */
Dave Barachc3799992016-08-15 11:12:27 -0400212always_inline u32 *
213elt_data (void *v, heap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214{
Dave Barachc3799992016-08-15 11:12:27 -0400215 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 return v + heap_offset (e) * h->elt_bytes;
217}
218
219always_inline void
Dave Barachc3799992016-08-15 11:12:27 -0400220set_free_elt (void *v, heap_elt_t * e, uword fi)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221{
Dave Barachc3799992016-08-15 11:12:27 -0400222 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223
224 e->offset |= HEAP_ELT_FREE_BIT;
225 if (h->elt_bytes >= sizeof (u32))
226 {
227 *elt_data (v, e) = fi;
228 }
229 else
230 {
231 /* For elt_bytes < 4 we must store free index in separate
Dave Barachc3799992016-08-15 11:12:27 -0400232 vector. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 uword elt_index = e - h->elts;
234 vec_validate (h->small_free_elt_free_index, elt_index);
235 h->small_free_elt_free_index[elt_index] = fi;
236 }
237}
238
239always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400240get_free_elt (void *v, heap_elt_t * e, uword * bin_result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241{
Dave Barachc3799992016-08-15 11:12:27 -0400242 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 uword fb, fi;
244
245 ASSERT (heap_is_free (e));
246 fb = size_to_bin (heap_elt_size (v, e));
247
248 if (h->elt_bytes >= sizeof (u32))
249 {
250 fi = *elt_data (v, e);
251 }
252 else
253 {
254 uword elt_index = e - h->elts;
255 fi = vec_elt (h->small_free_elt_free_index, elt_index);
256 }
257
258 *bin_result = fb;
259 return fi;
260}
261
Dave Barachc3799992016-08-15 11:12:27 -0400262always_inline void
263remove_free_block (void *v, uword b, uword i)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264{
Dave Barachc3799992016-08-15 11:12:27 -0400265 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266 uword l;
267
268 ASSERT (b < vec_len (h->free_lists));
269 ASSERT (i < vec_len (h->free_lists[b]));
270
271 l = vec_len (h->free_lists[b]);
272
273 if (i < l - 1)
274 {
275 uword t = h->free_lists[b][l - 1];
276 h->free_lists[b][i] = t;
277 set_free_elt (v, elt_at (h, t), i);
278 }
279 _vec_len (h->free_lists[b]) = l - 1;
280}
281
Dave Barachc3799992016-08-15 11:12:27 -0400282static heap_elt_t *
283search_free_list (void *v, uword size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284{
Dave Barachc3799992016-08-15 11:12:27 -0400285 heap_header_t *h = heap_header (v);
286 heap_elt_t *f, *u;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287 uword b, fb, f_size, f_index;
288 word s, l;
289
Dave Barachc3799992016-08-15 11:12:27 -0400290 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 return 0;
292
293 /* Search free lists for bins >= given size. */
294 for (b = size_to_bin (size); b < vec_len (h->free_lists); b++)
295 if ((l = vec_len (h->free_lists[b])) > 0)
296 {
297 /* Find an object that is large enough.
298 Search list in reverse so that more recently freed objects will be
299 allocated again sooner. */
Dave Barachc3799992016-08-15 11:12:27 -0400300 do
301 {
302 l--;
303 f_index = h->free_lists[b][l];
304 f = elt_at (h, f_index);
305 f_size = heap_elt_size (v, f);
306 if ((s = f_size - size) >= 0)
307 break;
308 }
309 while (l >= 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310
311 /* If we fail to find a large enough object, try the next larger size. */
312 if (l < 0)
313 continue;
314
315 ASSERT (heap_is_free (f));
316
317 /* Link in used object (u) after free object (f). */
318 if (s == 0)
319 {
320 u = f;
321 fb = HEAP_N_BINS;
322 }
323 else
324 {
325 u = elt_new (h);
326 f = elt_at (h, f_index);
327 elt_insert_after (h, f, u);
328 fb = size_to_bin (s);
329 }
330
331 u->offset = heap_offset (f) + s;
332
333 if (fb != b)
334 {
335 if (fb < HEAP_N_BINS)
336 {
337 uword i;
338 vec_validate (h->free_lists, fb);
339 i = vec_len (h->free_lists[fb]);
340 vec_add1 (h->free_lists[fb], f - h->elts);
341 set_free_elt (v, f, i);
342 }
343
344 remove_free_block (v, b, l);
345 }
346
347 return u;
348 }
349
350 return 0;
351}
352
Dave Barachc3799992016-08-15 11:12:27 -0400353static void combine_free_blocks (void *v, heap_elt_t * e0, heap_elt_t * e1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354
Dave Barachc3799992016-08-15 11:12:27 -0400355static inline void
356dealloc_elt (void *v, heap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357{
Dave Barachc3799992016-08-15 11:12:27 -0400358 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 uword b, l;
Dave Barachc3799992016-08-15 11:12:27 -0400360 heap_elt_t *n, *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
362 b = size_to_bin (heap_elt_size (v, e));
363 vec_validate (h->free_lists, b);
364 l = vec_len (h->free_lists[b]);
365 vec_add1 (h->free_lists[b], e - h->elts);
366 set_free_elt (v, e, l);
367
368 /* See if we can combine the block we just freed with neighboring free blocks. */
369 p = heap_prev (e);
Dave Barachc3799992016-08-15 11:12:27 -0400370 if (!heap_is_free (p))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371 p = e;
372
373 n = heap_next (e);
Dave Barachc3799992016-08-15 11:12:27 -0400374 if (!heap_is_free (n))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375 n = e;
376
377 if (p != n)
378 combine_free_blocks (v, p, n);
379}
380
Dave Barachc3799992016-08-15 11:12:27 -0400381void *
382_heap_alloc (void *v,
383 uword size,
384 uword align,
385 uword elt_bytes, uword * offset_return, uword * handle_return)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386{
387 uword offset = 0, align_size;
Dave Barachc3799992016-08-15 11:12:27 -0400388 heap_header_t *h;
389 heap_elt_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390
391 if (size == 0)
392 goto error;
393
394 /* Round up alignment to power of 2. */
395 if (align <= 1)
396 {
397 align = 0;
398 align_size = size;
399 }
400 else
401 {
402 align = max_pow2 (align);
403 align_size = size + align - 1;
404 }
405
406 e = search_free_list (v, align_size);
407
408 /* If nothing found on free list, allocate object from end of vector. */
Dave Barachc3799992016-08-15 11:12:27 -0400409 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700410 {
411 uword max_len;
412
413 offset = vec_len (v);
414 max_len = heap_get_max_len (v);
415
416 if (max_len && offset + align_size > max_len)
417 goto error;
418
419 h = heap_header (v);
Dave Barachc3799992016-08-15 11:12:27 -0400420 if (!v || !(h->flags & HEAP_IS_STATIC))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 v = _vec_resize (v,
422 align_size,
423 (offset + align_size) * elt_bytes,
Dave Barachc3799992016-08-15 11:12:27 -0400424 sizeof (h[0]), HEAP_DATA_ALIGN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425 else
426 _vec_len (v) += align_size;
427
428 if (offset == 0)
429 {
430 h = heap_header (v);
431 h->elt_bytes = elt_bytes;
432 }
433 }
434
435 h = heap_header (v);
436
437 /* Add new element to doubly linked chain of elements. */
Dave Barachc3799992016-08-15 11:12:27 -0400438 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439 {
440 e = elt_new (h);
441 e->offset = offset;
442 elt_insert_after (h, last (h), e);
443 }
444
445 if (align > 0)
446 {
447 uword e_index;
448 uword new_offset, old_offset;
449
450 old_offset = e->offset;
Dave Barachc3799992016-08-15 11:12:27 -0400451 new_offset = (old_offset + align - 1) & ~(align - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452 e->offset = new_offset;
453 e_index = e - h->elts;
454
455 /* Free fragments before and after aligned object. */
456 if (new_offset > old_offset)
457 {
Dave Barachc3799992016-08-15 11:12:27 -0400458 heap_elt_t *before_e = elt_new (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459 before_e->offset = old_offset;
460 elt_insert_before (h, h->elts + e_index, before_e);
461 dealloc_elt (v, before_e);
462 }
463
464 if (new_offset + size < old_offset + align_size)
465 {
Dave Barachc3799992016-08-15 11:12:27 -0400466 heap_elt_t *after_e = elt_new (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467 after_e->offset = new_offset + size;
468 elt_insert_after (h, h->elts + e_index, after_e);
469 dealloc_elt (v, after_e);
470 }
Dave Barachc3799992016-08-15 11:12:27 -0400471
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472 e = h->elts + e_index;
473 }
474
475 h->used_count++;
476
477 /* Keep track of used elements when debugging.
478 This allows deallocation to check that passed objects are valid. */
479 if (CLIB_DEBUG > 0)
480 {
481 uword handle = e - h->elts;
Dave Barachc3799992016-08-15 11:12:27 -0400482 ASSERT (!clib_bitmap_get (h->used_elt_bitmap, handle));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483 h->used_elt_bitmap = clib_bitmap_ori (h->used_elt_bitmap, handle);
484 }
485
486 *offset_return = e->offset;
Dave Barachc3799992016-08-15 11:12:27 -0400487 *handle_return = e - h->elts;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488 return v;
489
Dave Barachc3799992016-08-15 11:12:27 -0400490error:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 *offset_return = *handle_return = ~0;
492 return v;
493}
494
Dave Barachc3799992016-08-15 11:12:27 -0400495void
496heap_dealloc (void *v, uword handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497{
Dave Barachc3799992016-08-15 11:12:27 -0400498 heap_header_t *h = heap_header (v);
499 heap_elt_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500
501 ASSERT (handle < vec_len (h->elts));
502
503 /* For debugging we keep track of indices for valid objects.
504 We make sure user is not trying to free object with an invalid index. */
505 if (CLIB_DEBUG > 0)
506 {
507 ASSERT (clib_bitmap_get (h->used_elt_bitmap, handle));
508 h->used_elt_bitmap = clib_bitmap_andnoti (h->used_elt_bitmap, handle);
509 }
510
511 h->used_count--;
512
513 e = h->elts + handle;
Dave Barachc3799992016-08-15 11:12:27 -0400514 ASSERT (!heap_is_free (e));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516 dealloc_elt (v, e);
517}
518
519/* While freeing objects at INDEX we noticed free blocks i0 <= index and
520 i1 >= index. We combine these two or three blocks into one big free block. */
Dave Barachc3799992016-08-15 11:12:27 -0400521static void
522combine_free_blocks (void *v, heap_elt_t * e0, heap_elt_t * e1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523{
Dave Barachc3799992016-08-15 11:12:27 -0400524 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525 uword total_size, i, b, tb, ti, i_last, g_offset;
Dave Barachc3799992016-08-15 11:12:27 -0400526 heap_elt_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527
Dave Barachc3799992016-08-15 11:12:27 -0400528 struct
529 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 u32 index;
531 u32 bin;
532 u32 bin_index;
533 } f[3], g;
534
535 /* Compute total size of free objects i0 through i1. */
536 total_size = 0;
537 for (i = 0, e = e0; 1; e = heap_next (e), i++)
538 {
539 ASSERT (i < ARRAY_LEN (f));
540
541 ti = get_free_elt (v, e, &tb);
542
543 ASSERT (tb < vec_len (h->free_lists));
544 ASSERT (ti < vec_len (h->free_lists[tb]));
545
546 f[i].index = h->free_lists[tb][ti];
547 f[i].bin = tb;
548 f[i].bin_index = ti;
549
550 total_size += heap_elt_size (v, elt_at (h, f[i].index));
551
552 if (e == e1)
553 {
554 i_last = i;
555 break;
556 }
557 }
558
559 /* Compute combined bin. See if all objects can be
560 combined into existing bin. */
561 b = size_to_bin (total_size);
562 g.index = g.bin_index = 0;
563 for (i = 0; i <= i_last; i++)
564 if (b == f[i].bin)
565 {
566 g = f[i];
567 break;
568 }
569
570 /* Make sure we found a bin. */
571 if (i > i_last)
572 {
573 g.index = elt_new (h) - h->elts;
574 vec_validate (h->free_lists, b);
575 g.bin_index = vec_len (h->free_lists[b]);
576 vec_add1 (h->free_lists[b], g.index);
577 elt_insert_before (h, elt_at (h, f[0].index), elt_at (h, g.index));
578 }
579
580 g_offset = elt_at (h, f[0].index)->offset;
581
582 /* Delete unused bins. */
583 for (i = 0; i <= i_last; i++)
584 if (g.index != f[i].index)
585 {
586 ti = get_free_elt (v, elt_at (h, f[i].index), &tb);
587 remove_free_block (v, tb, ti);
588 elt_delete (h, elt_at (h, f[i].index));
589 }
590
591 /* Initialize new element. */
592 elt_at (h, g.index)->offset = g_offset;
593 set_free_elt (v, elt_at (h, g.index), g.bin_index);
594}
595
Dave Barachc3799992016-08-15 11:12:27 -0400596uword
597heap_len (void *v, word handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598{
Dave Barachc3799992016-08-15 11:12:27 -0400599 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700600
601 if (CLIB_DEBUG > 0)
602 ASSERT (clib_bitmap_get (h->used_elt_bitmap, handle));
603 return heap_elt_size (v, elt_at (h, handle));
604}
605
Dave Barachc3799992016-08-15 11:12:27 -0400606void *
607_heap_free (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608{
Dave Barachc3799992016-08-15 11:12:27 -0400609 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610 uword b;
611
Dave Barachc3799992016-08-15 11:12:27 -0400612 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700613 return v;
614
615 clib_bitmap_free (h->used_elt_bitmap);
616 for (b = 0; b < vec_len (h->free_lists); b++)
617 vec_free (h->free_lists[b]);
618 vec_free (h->free_lists);
619 vec_free (h->elts);
620 vec_free (h->free_elts);
621 vec_free (h->small_free_elt_free_index);
Dave Barachc3799992016-08-15 11:12:27 -0400622 if (!(h->flags & HEAP_IS_STATIC))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623 vec_free_h (v, sizeof (h[0]));
624 return v;
625}
626
Dave Barachc3799992016-08-15 11:12:27 -0400627uword
628heap_bytes (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629{
Dave Barachc3799992016-08-15 11:12:27 -0400630 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 uword bytes, b;
632
Dave Barachc3799992016-08-15 11:12:27 -0400633 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634 return 0;
635
636 bytes = sizeof (h[0]);
637 bytes += vec_len (v) * sizeof (h->elt_bytes);
638 for (b = 0; b < vec_len (h->free_lists); b++)
639 bytes += vec_capacity (h->free_lists[b], 0);
640 bytes += vec_bytes (h->free_lists);
641 bytes += vec_capacity (h->elts, 0);
642 bytes += vec_capacity (h->free_elts, 0);
643 bytes += vec_bytes (h->used_elt_bitmap);
644
645 return bytes;
646}
647
Dave Barachc3799992016-08-15 11:12:27 -0400648static u8 *
649debug_elt (u8 * s, void *v, word i, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700650{
Dave Barachc3799992016-08-15 11:12:27 -0400651 heap_elt_t *e, *e0, *e1;
652 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653 word j;
654
655 if (vec_len (h->elts) == 0)
656 return s;
657
658 if (i < 0)
659 e0 = first (h);
660 else
661 {
662 e0 = h->elts + i;
Dave Barachc3799992016-08-15 11:12:27 -0400663 for (j = 0; j < n / 2; j++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664 e0 = heap_prev (e0);
665 }
666
667 if (n < 0)
668 e1 = h->elts + h->tail;
669 else
670 {
671 e1 = h->elts + i;
Dave Barachc3799992016-08-15 11:12:27 -0400672 for (j = 0; j < n / 2; j++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 e1 = heap_next (e1);
674 }
675
Dave Barachc3799992016-08-15 11:12:27 -0400676 i = -n / 2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677 for (e = e0; 1; e = heap_next (e))
678 {
679 if (heap_is_free (e))
680 s = format (s, "index %4d, free\n", e - h->elts);
681 else if (h->format_elt)
682 s = format (s, "%U", h->format_elt, v, elt_data (v, e));
683 else
684 s = format (s, "index %4d, used\n", e - h->elts);
685 i++;
686 if (e == e1)
687 break;
688 }
689
690 return s;
691}
692
Dave Barachc3799992016-08-15 11:12:27 -0400693u8 *
694format_heap (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695{
Dave Barachc3799992016-08-15 11:12:27 -0400696 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697 uword verbose = va_arg (*va, uword);
Dave Barachc3799992016-08-15 11:12:27 -0400698 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699 heap_header_t zero;
700
701 memset (&zero, 0, sizeof (zero));
702
Dave Barachc3799992016-08-15 11:12:27 -0400703 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704 h = &zero;
705
706 {
707 f64 elt_bytes = vec_len (v) * h->elt_bytes;
708 f64 overhead_bytes = heap_bytes (v);
Dave Barachc3799992016-08-15 11:12:27 -0400709
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710 s = format (s, "heap %p, %6d objects, size %.1fk + overhead %.1fk\n",
Dave Barachc3799992016-08-15 11:12:27 -0400711 v, h->used_count, elt_bytes / 1024,
712 (overhead_bytes - elt_bytes) / 1024);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713 }
714
715 if (v && verbose)
716 s = debug_elt (s, v, -1, -1);
717
718 return s;
719}
720
Dave Barachc3799992016-08-15 11:12:27 -0400721void
722heap_validate (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723{
Dave Barachc3799992016-08-15 11:12:27 -0400724 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725 uword i, o, s;
Dave Barachc3799992016-08-15 11:12:27 -0400726 u8 *free_map;
727 heap_elt_t *e, *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700728
729 uword used_count, total_size;
730 uword free_count, free_size;
731
732 ASSERT (h->used_count == clib_bitmap_count_set_bits (h->used_elt_bitmap));
733
Dave Barachc3799992016-08-15 11:12:27 -0400734 ASSERT (first (h)->prev == 0);
735 ASSERT (last (h)->next == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
737 /* Validate number of elements and size. */
738 free_size = free_count = 0;
739 for (i = 0; i < vec_len (h->free_lists); i++)
740 {
741 free_count += vec_len (h->free_lists[i]);
742 for (o = 0; o < vec_len (h->free_lists[i]); o++)
743 {
744 e = h->elts + h->free_lists[i][o];
745 s = heap_elt_size (v, e);
746 ASSERT (size_to_bin (s) == i);
747 ASSERT (heap_is_free (e));
748 free_size += s;
749 }
750 }
751
752 {
753 uword elt_free_size, elt_free_count;
754
755 used_count = total_size = elt_free_size = elt_free_count = 0;
756 for (e = first (h); 1; e = n)
757 {
758 int is_free = heap_is_free (e);
759 used_count++;
760 s = heap_elt_size (v, e);
761 total_size += s;
Dave Barachc3799992016-08-15 11:12:27 -0400762 ASSERT (is_free ==
763 !clib_bitmap_get (h->used_elt_bitmap, e - h->elts));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700764 if (is_free)
765 {
766 elt_free_count++;
767 elt_free_size += s;
768 }
769 n = heap_next (e);
770 if (e == n)
771 {
772 ASSERT (last (h) == n);
773 break;
774 }
775
776 /* We should never have two free adjacent elements. */
Dave Barachc3799992016-08-15 11:12:27 -0400777 ASSERT (!(heap_is_free (e) && heap_is_free (n)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778 }
779
780 ASSERT (free_count == elt_free_count);
781 ASSERT (free_size == elt_free_size);
782 ASSERT (used_count == h->used_count + free_count);
783 ASSERT (total_size == vec_len (v));
784 }
785
786 free_map = vec_new (u8, used_count);
787
788 e = first (h);
789 for (i = o = 0; 1; i++)
790 {
791 ASSERT (heap_offset (e) == o);
792 s = heap_elt_size (v, e);
793
794 if (heap_is_free (e))
795 {
796 uword fb, fi;
797
798 fi = get_free_elt (v, e, &fb);
799
800 ASSERT (fb < vec_len (h->free_lists));
801 ASSERT (fi < vec_len (h->free_lists[fb]));
802 ASSERT (h->free_lists[fb][fi] == e - h->elts);
803
Dave Barachc3799992016-08-15 11:12:27 -0400804 ASSERT (!free_map[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805 free_map[i] = 1;
806 }
807
808 n = heap_next (e);
809
810 if (e == n)
811 break;
812
813 ASSERT (heap_prev (n) == e);
814
815 o += s;
816 e = n;
817 }
818
819 vec_free (free_map);
820}
Dave Barachc3799992016-08-15 11:12:27 -0400821
822/*
823 * fd.io coding-style-patch-verification: ON
824 *
825 * Local Variables:
826 * eval: (c-set-style "gnu")
827 * End:
828 */