LCOV - code coverage report
Current view: top level - vppinfra - heap.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 221 372 59.4 %
Date: 2023-07-05 22:20:52 Functions: 17 23 73.9 %

          Line data    Source code
       1             : /*
       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             : 
      38             : #include <vppinfra/cache.h>       /* for CLIB_CACHE_LINE_BYTES */
      39             : #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             : 
      45             : always_inline heap_elt_t *
      46      425362 : elt_at (heap_header_t * h, uword i)
      47             : {
      48      425362 :   ASSERT (i < vec_len (h->elts));
      49      425362 :   return h->elts + i;
      50             : }
      51             : 
      52             : always_inline heap_elt_t *
      53      285376 : last (heap_header_t * h)
      54             : {
      55      285376 :   return elt_at (h, h->tail);
      56             : }
      57             : 
      58             : always_inline heap_elt_t *
      59           0 : first (heap_header_t * h)
      60             : {
      61           0 :   return elt_at (h, h->head);
      62             : }
      63             : 
      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. */
      72             : always_inline uword
      73      396900 : size_to_bin (uword size)
      74             : {
      75             :   uword bin;
      76             : 
      77      396900 :   ASSERT (size > 0);
      78             : 
      79      396900 :   if (size <= HEAP_SMALL_BINS)
      80             :     {
      81      370461 :       bin = size - 1;
      82      370461 :       if (size == 0)
      83           0 :         bin = 0;
      84             :     }
      85             :   else
      86             :     {
      87       26439 :       bin = HEAP_SMALL_BINS + max_log2 (size) - (HEAP_LOG2_SMALL_BINS + 1);
      88       26439 :       if (bin >= HEAP_N_BINS)
      89           0 :         bin = HEAP_N_BINS - 1;
      90             :     }
      91             : 
      92      396900 :   return bin;
      93             : }
      94             : 
      95             : /* Convert bin to size. */
      96             : always_inline __attribute__ ((unused))
      97             :      uword bin_to_size (uword bin)
      98             : {
      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             : 
     109             : static void
     110       16130 : elt_delete (heap_header_t * h, heap_elt_t * e)
     111             : {
     112       16130 :   heap_elt_t *l = vec_end (h->elts) - 1;
     113             : 
     114       16130 :   ASSERT (e >= h->elts && e <= l);
     115             : 
     116             :   /* Update doubly linked pointers. */
     117             :   {
     118       16130 :     heap_elt_t *p = heap_prev (e);
     119       16130 :     heap_elt_t *n = heap_next (e);
     120             : 
     121       16130 :     if (p == e)
     122             :       {
     123           0 :         n->prev = 0;
     124           0 :         h->head = n - h->elts;
     125             :       }
     126       16130 :     else if (n == e)
     127             :       {
     128        5426 :         p->next = 0;
     129        5426 :         h->tail = p - h->elts;
     130             :       }
     131             :     else
     132             :       {
     133       10704 :         p->next = n - p;
     134       10704 :         n->prev = p - n;
     135             :       }
     136             :   }
     137             : 
     138             :   /* Add to index free list or delete from end. */
     139       16130 :   if (e < l)
     140       11107 :     vec_add1 (h->free_elts, e - h->elts);
     141             :   else
     142        5023 :     vec_dec_len (h->elts, 1);
     143       16130 : }
     144             : 
     145             : /*
     146             :   Before: P ... E
     147             :   After : P ... NEW ... E
     148             : */
     149             : always_inline void
     150        7880 : elt_insert_before (heap_header_t * h, heap_elt_t * e, heap_elt_t * new)
     151             : {
     152        7880 :   heap_elt_t *p = heap_prev (e);
     153             : 
     154        7880 :   if (p == e)
     155             :     {
     156        3561 :       new->prev = 0;
     157        3561 :       new->next = e - new;
     158        3561 :       p->prev = new - p;
     159        3561 :       h->head = new - h->elts;
     160             :     }
     161             :   else
     162             :     {
     163        4319 :       new->prev = p - new;
     164        4319 :       new->next = e - new;
     165        4319 :       e->prev = new - e;
     166        4319 :       p->next = new - p;
     167             :     }
     168        7880 : }
     169             : 
     170             : /*
     171             :   Before: E ... N
     172             :   After : E ... NEW ... N
     173             : */
     174             : always_inline void
     175      292704 : elt_insert_after (heap_header_t * h, heap_elt_t * e, heap_elt_t * new)
     176             : {
     177      292704 :   heap_elt_t *n = heap_next (e);
     178             : 
     179      292704 :   if (n == e)
     180             :     {
     181      290354 :       new->next = 0;
     182      290354 :       new->prev = e - new;
     183      290354 :       e->next = new - e;
     184      290354 :       h->tail = new - h->elts;
     185             :     }
     186             :   else
     187             :     {
     188        2350 :       new->prev = e - new;
     189        2350 :       new->next = n - new;
     190        2350 :       e->next = new - e;
     191        2350 :       n->prev = new - n;
     192             :     }
     193      292704 : }
     194             : 
     195             : always_inline heap_elt_t *
     196      300584 : elt_new (heap_header_t * h)
     197             : {
     198             :   heap_elt_t *e;
     199             :   uword l;
     200      300584 :   if ((l = vec_len (h->free_elts)) > 0)
     201             :     {
     202        9441 :       e = elt_at (h, h->free_elts[l - 1]);
     203        9441 :       vec_dec_len (h->free_elts, 1);
     204             :     }
     205             :   else
     206      291143 :     vec_add2 (h->elts, e, 1);
     207      300584 :   return e;
     208             : }
     209             : 
     210             : /* Return pointer to object at given offset.
     211             :    Used to write free list index of free objects. */
     212             : always_inline u32 *
     213       85494 : elt_data (void *v, heap_elt_t * e)
     214             : {
     215       85494 :   heap_header_t *h = heap_header (v);
     216       85494 :   return v + heap_offset (e) * h->elt_bytes;
     217             : }
     218             : 
     219             : always_inline void
     220       54533 : set_free_elt (void *v, heap_elt_t * e, uword fi)
     221             : {
     222       54533 :   heap_header_t *h = heap_header (v);
     223             : 
     224       54533 :   e->offset |= HEAP_ELT_FREE_BIT;
     225       54533 :   if (h->elt_bytes >= sizeof (u32))
     226             :     {
     227       53817 :       *elt_data (v, e) = fi;
     228             :     }
     229             :   else
     230             :     {
     231             :       /* For elt_bytes < 4 we must store free index in separate
     232             :          vector. */
     233         716 :       uword elt_index = e - h->elts;
     234         716 :       vec_validate (h->small_free_elt_free_index, elt_index);
     235         716 :       h->small_free_elt_free_index[elt_index] = fi;
     236             :     }
     237       54533 : }
     238             : 
     239             : always_inline uword
     240       32269 : get_free_elt (void *v, heap_elt_t * e, uword * bin_result)
     241             : {
     242       32269 :   heap_header_t *h = heap_header (v);
     243             :   uword fb, fi;
     244             : 
     245       32269 :   ASSERT (heap_is_free (e));
     246       32269 :   fb = size_to_bin (heap_elt_size (v, e));
     247             : 
     248       32269 :   if (h->elt_bytes >= sizeof (u32))
     249             :     {
     250       31677 :       fi = *elt_data (v, e);
     251             :     }
     252             :   else
     253             :     {
     254         592 :       uword elt_index = e - h->elts;
     255         592 :       fi = vec_elt (h->small_free_elt_free_index, elt_index);
     256             :     }
     257             : 
     258       32269 :   *bin_result = fb;
     259       32269 :   return fi;
     260             : }
     261             : 
     262             : always_inline void
     263       49262 : remove_free_block (void *v, uword b, uword i)
     264             : {
     265       49262 :   heap_header_t *h = heap_header (v);
     266             :   uword l;
     267             : 
     268       49262 :   ASSERT (b < vec_len (h->free_lists));
     269       49262 :   ASSERT (i < vec_len (h->free_lists[b]));
     270             : 
     271       49262 :   l = vec_len (h->free_lists[b]);
     272             : 
     273       49262 :   if (i < l - 1)
     274             :     {
     275        2259 :       uword t = h->free_lists[b][l - 1];
     276        2259 :       h->free_lists[b][i] = t;
     277        2259 :       set_free_elt (v, elt_at (h, t), i);
     278             :     }
     279       49262 :   vec_set_len (h->free_lists[b], l - 1);
     280       49262 : }
     281             : 
     282             : static heap_elt_t *
     283      318508 : search_free_list (void *v, uword size)
     284             : {
     285      318508 :   heap_header_t *h = heap_header (v);
     286             :   heap_elt_t *f, *u;
     287             :   uword b, fb, f_size, f_index;
     288             :   word s, l;
     289             : 
     290      318508 :   if (!v)
     291        6151 :     return 0;
     292             : 
     293             :   /* Search free lists for bins >= given size. */
     294      352381 :   for (b = size_to_bin (size); b < vec_len (h->free_lists); b++)
     295       73156 :     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. */
     300       33132 :         u8 found = 0;
     301             :         do
     302             :           {
     303       33132 :             l--;
     304       33132 :             f_index = h->free_lists[b][l];
     305       33132 :             f = elt_at (h, f_index);
     306       33132 :             f_size = heap_elt_size (v, f);
     307       33132 :             if ((s = f_size - size) >= 0)
     308             :               {
     309       33132 :                 found = 1;
     310       33132 :                 break;
     311             :               }
     312             :           }
     313           0 :         while (l > 0);
     314             : 
     315             :         /* If we fail to find a large enough object, try the next larger size. */
     316       33132 :         if (found == 0)
     317           0 :           continue;
     318             : 
     319       33132 :         ASSERT (heap_is_free (f));
     320             : 
     321             :         /* Link in used object (u) after free object (f). */
     322       33132 :         if (s == 0)
     323             :           {
     324       25804 :             u = f;
     325       25804 :             fb = HEAP_N_BINS;
     326             :           }
     327             :         else
     328             :           {
     329        7328 :             u = elt_new (h);
     330        7328 :             f = elt_at (h, f_index);
     331        7328 :             elt_insert_after (h, f, u);
     332        7328 :             fb = size_to_bin (s);
     333             :           }
     334             : 
     335       33132 :         u->offset = heap_offset (f) + s;
     336             : 
     337       33132 :         if (fb != b)
     338             :           {
     339       33132 :             if (fb < HEAP_N_BINS)
     340             :               {
     341             :                 uword i;
     342        7328 :                 vec_validate (h->free_lists, fb);
     343        7328 :                 i = vec_len (h->free_lists[fb]);
     344        7328 :                 vec_add1 (h->free_lists[fb], f - h->elts);
     345        7328 :                 set_free_elt (v, f, i);
     346             :               }
     347             : 
     348       33132 :             remove_free_block (v, b, l);
     349             :           }
     350             : 
     351       33132 :         return u;
     352             :       }
     353             : 
     354      279225 :   return 0;
     355             : }
     356             : 
     357             : static void combine_free_blocks (void *v, heap_elt_t * e0, heap_elt_t * e1);
     358             : 
     359             : static inline void
     360       37057 : dealloc_elt (void *v, heap_elt_t * e)
     361             : {
     362       37057 :   heap_header_t *h = heap_header (v);
     363             :   uword b, l;
     364             :   heap_elt_t *n, *p;
     365             : 
     366       37057 :   b = size_to_bin (heap_elt_size (v, e));
     367       37057 :   vec_validate (h->free_lists, b);
     368       37057 :   l = vec_len (h->free_lists[b]);
     369       37057 :   vec_add1 (h->free_lists[b], e - h->elts);
     370       37057 :   set_free_elt (v, e, l);
     371             : 
     372             :   /* See if we can combine the block we just freed with neighboring free blocks. */
     373       37057 :   p = heap_prev (e);
     374       37057 :   if (!heap_is_free (p))
     375       23763 :     p = e;
     376             : 
     377       37057 :   n = heap_next (e);
     378       37057 :   if (!heap_is_free (n))
     379        7067 :     n = e;
     380             : 
     381       37057 :   if (p != n)
     382        7889 :     combine_free_blocks (v, p, n);
     383       37057 : }
     384             : 
     385             : __clib_export void *
     386      318508 : _heap_alloc (void *v,
     387             :              uword size,
     388             :              uword align,
     389             :              uword elt_bytes, uword * offset_return, uword * handle_return)
     390             : {
     391      318508 :   uword offset = 0, align_size;
     392             :   heap_header_t *h;
     393             :   heap_elt_t *e;
     394             : 
     395      318508 :   if (size == 0)
     396           0 :     goto error;
     397             : 
     398             :   /* Round up alignment to power of 2. */
     399      318508 :   if (align <= 1)
     400             :     {
     401      318508 :       align = 0;
     402      318508 :       align_size = size;
     403             :     }
     404             :   else
     405             :     {
     406           0 :       align = max_pow2 (align);
     407           0 :       align_size = size + align - 1;
     408             :     }
     409             : 
     410      318508 :   e = search_free_list (v, align_size);
     411             : 
     412             :   /* If nothing found on free list, allocate object from end of vector. */
     413      318508 :   if (!e)
     414             :     {
     415             :       uword max_len;
     416      285376 :       vec_attr_t va = { .elt_sz = elt_bytes,
     417             :                         .hdr_sz = sizeof (h[0]),
     418             :                         .align = HEAP_DATA_ALIGN };
     419             : 
     420      285376 :       offset = vec_len (v);
     421      285376 :       max_len = heap_get_max_len (v);
     422             : 
     423      285376 :       if (max_len && offset + align_size > max_len)
     424           0 :         goto error;
     425             : 
     426      285376 :       h = heap_header (v);
     427      285376 :       if (!v || !(h->flags & HEAP_IS_STATIC))
     428      285376 :         v = _vec_realloc_internal (v, offset + align_size, &va);
     429             :       else
     430           0 :         vec_inc_len (v, align_size);
     431             : 
     432      285376 :       if (offset == 0)
     433             :         {
     434        6151 :           h = heap_header (v);
     435        6151 :           h->elt_bytes = elt_bytes;
     436             :         }
     437             :     }
     438             : 
     439      318508 :   h = heap_header (v);
     440             : 
     441             :   /* Add new element to doubly linked chain of elements. */
     442      318508 :   if (!e)
     443             :     {
     444      285376 :       e = elt_new (h);
     445      285376 :       e->offset = offset;
     446      285376 :       elt_insert_after (h, last (h), e);
     447             :     }
     448             : 
     449      318508 :   if (align > 0)
     450             :     {
     451             :       uword e_index;
     452             :       uword new_offset, old_offset;
     453             : 
     454           0 :       old_offset = e->offset;
     455           0 :       new_offset = (old_offset + align - 1) & ~(align - 1);
     456           0 :       e->offset = new_offset;
     457           0 :       e_index = e - h->elts;
     458             : 
     459             :       /* Free fragments before and after aligned object. */
     460           0 :       if (new_offset > old_offset)
     461             :         {
     462           0 :           heap_elt_t *before_e = elt_new (h);
     463           0 :           before_e->offset = old_offset;
     464           0 :           elt_insert_before (h, h->elts + e_index, before_e);
     465           0 :           dealloc_elt (v, before_e);
     466             :         }
     467             : 
     468           0 :       if (new_offset + size < old_offset + align_size)
     469             :         {
     470           0 :           heap_elt_t *after_e = elt_new (h);
     471           0 :           after_e->offset = new_offset + size;
     472           0 :           elt_insert_after (h, h->elts + e_index, after_e);
     473           0 :           dealloc_elt (v, after_e);
     474             :         }
     475             : 
     476           0 :       e = h->elts + e_index;
     477             :     }
     478             : 
     479      318508 :   h->used_count++;
     480             : 
     481             :   /* Keep track of used elements when debugging.
     482             :      This allows deallocation to check that passed objects are valid. */
     483             :   if (CLIB_DEBUG > 0)
     484             :     {
     485      318508 :       uword handle = e - h->elts;
     486      318508 :       ASSERT (!clib_bitmap_get (h->used_elt_bitmap, handle));
     487      318508 :       h->used_elt_bitmap = clib_bitmap_ori (h->used_elt_bitmap, handle);
     488             :     }
     489             : 
     490      318508 :   *offset_return = e->offset;
     491      318508 :   *handle_return = e - h->elts;
     492      318508 :   return v;
     493             : 
     494           0 : error:
     495           0 :   *offset_return = *handle_return = ~0;
     496           0 :   return v;
     497             : }
     498             : 
     499             : __clib_export void
     500       37057 : heap_dealloc (void *v, uword handle)
     501             : {
     502       37057 :   heap_header_t *h = heap_header (v);
     503             :   heap_elt_t *e;
     504             : 
     505       37057 :   ASSERT (handle < vec_len (h->elts));
     506             : 
     507             :   /* For debugging we keep track of indices for valid objects.
     508             :      We make sure user is not trying to free object with an invalid index. */
     509             :   if (CLIB_DEBUG > 0)
     510             :     {
     511       37057 :       ASSERT (clib_bitmap_get (h->used_elt_bitmap, handle));
     512       37057 :       h->used_elt_bitmap = clib_bitmap_andnoti (h->used_elt_bitmap, handle);
     513             :     }
     514             : 
     515       37057 :   h->used_count--;
     516             : 
     517       37057 :   e = h->elts + handle;
     518       37057 :   ASSERT (!heap_is_free (e));
     519             : 
     520       37057 :   dealloc_elt (v, e);
     521       37057 : }
     522             : 
     523             : /* While freeing objects at INDEX we noticed free blocks i0 <= index and
     524             :    i1 >= index.  We combine these two or three blocks into one big free block. */
     525             : static void
     526        7889 : combine_free_blocks (void *v, heap_elt_t * e0, heap_elt_t * e1)
     527             : {
     528        7889 :   heap_header_t *h = heap_header (v);
     529             :   uword total_size, i, b, tb, ti, i_last, g_offset;
     530             :   heap_elt_t *e;
     531             : 
     532             :   struct
     533             :   {
     534             :     u32 index;
     535             :     u32 bin;
     536             :     u32 bin_index;
     537             :   } f[3], g;
     538             : 
     539             :   /* Compute total size of free objects i0 through i1. */
     540        7889 :   total_size = 0;
     541       16139 :   for (i = 0, e = e0; 1; e = heap_next (e), i++)
     542             :     {
     543       16139 :       ASSERT (i < ARRAY_LEN (f));
     544             : 
     545       16139 :       ti = get_free_elt (v, e, &tb);
     546             : 
     547       16139 :       ASSERT (tb < vec_len (h->free_lists));
     548       16139 :       ASSERT (ti < vec_len (h->free_lists[tb]));
     549             : 
     550       16139 :       f[i].index = h->free_lists[tb][ti];
     551       16139 :       f[i].bin = tb;
     552       16139 :       f[i].bin_index = ti;
     553             : 
     554       16139 :       total_size += heap_elt_size (v, elt_at (h, f[i].index));
     555             : 
     556       16139 :       if (e == e1)
     557             :         {
     558        7889 :           i_last = i;
     559        7889 :           break;
     560             :         }
     561             :     }
     562             : 
     563             :   /* Compute combined bin.  See if all objects can be
     564             :      combined into existing bin. */
     565        7889 :   b = size_to_bin (total_size);
     566        7889 :   g.index = g.bin_index = 0;
     567       24010 :   for (i = 0; i <= i_last; i++)
     568       16130 :     if (b == f[i].bin)
     569             :       {
     570           9 :         g = f[i];
     571           9 :         break;
     572             :       }
     573             : 
     574             :   /* Make sure we found a bin. */
     575        7889 :   if (i > i_last)
     576             :     {
     577        7880 :       g.index = elt_new (h) - h->elts;
     578        7880 :       vec_validate (h->free_lists, b);
     579        7880 :       g.bin_index = vec_len (h->free_lists[b]);
     580        7880 :       vec_add1 (h->free_lists[b], g.index);
     581        7880 :       elt_insert_before (h, elt_at (h, f[0].index), elt_at (h, g.index));
     582             :     }
     583             : 
     584        7889 :   g_offset = elt_at (h, f[0].index)->offset;
     585             : 
     586             :   /* Delete unused bins. */
     587       24028 :   for (i = 0; i <= i_last; i++)
     588       16139 :     if (g.index != f[i].index)
     589             :       {
     590       16130 :         ti = get_free_elt (v, elt_at (h, f[i].index), &tb);
     591       16130 :         remove_free_block (v, tb, ti);
     592       16130 :         elt_delete (h, elt_at (h, f[i].index));
     593             :       }
     594             : 
     595             :   /* Initialize new element. */
     596        7889 :   elt_at (h, g.index)->offset = g_offset;
     597        7889 :   set_free_elt (v, elt_at (h, g.index), g.bin_index);
     598        7889 : }
     599             : 
     600             : __clib_export uword
     601           0 : heap_len (void *v, word handle)
     602             : {
     603           0 :   heap_header_t *h = heap_header (v);
     604             : 
     605             :   if (CLIB_DEBUG > 0)
     606           0 :     ASSERT (clib_bitmap_get (h->used_elt_bitmap, handle));
     607           0 :   return heap_elt_size (v, elt_at (h, handle));
     608             : }
     609             : 
     610             : __clib_export void *
     611       12201 : _heap_free (void *v)
     612             : {
     613       12201 :   heap_header_t *h = heap_header (v);
     614             :   uword b;
     615             : 
     616       12201 :   if (!v)
     617       12201 :     return v;
     618             : 
     619           0 :   clib_bitmap_free (h->used_elt_bitmap);
     620           0 :   for (b = 0; b < vec_len (h->free_lists); b++)
     621           0 :     vec_free (h->free_lists[b]);
     622           0 :   vec_free (h->free_lists);
     623           0 :   vec_free (h->elts);
     624           0 :   vec_free (h->free_elts);
     625           0 :   vec_free (h->small_free_elt_free_index);
     626           0 :   if (!(h->flags & HEAP_IS_STATIC))
     627           0 :     vec_free (v);
     628           0 :   return v;
     629             : }
     630             : 
     631             : uword
     632           0 : heap_bytes (void *v)
     633             : {
     634           0 :   heap_header_t *h = heap_header (v);
     635             :   uword bytes, b;
     636             : 
     637           0 :   if (!v)
     638           0 :     return 0;
     639             : 
     640           0 :   bytes = sizeof (h[0]);
     641           0 :   bytes += vec_len (v) * sizeof (h->elt_bytes);
     642           0 :   for (b = 0; b < vec_len (h->free_lists); b++)
     643           0 :     bytes += vec_mem_size (h->free_lists[b]);
     644           0 :   bytes += vec_bytes (h->free_lists);
     645           0 :   bytes += vec_mem_size (h->elts);
     646           0 :   bytes += vec_mem_size (h->free_elts);
     647           0 :   bytes += vec_bytes (h->used_elt_bitmap);
     648             : 
     649           0 :   return bytes;
     650             : }
     651             : 
     652             : static u8 *
     653           0 : debug_elt (u8 * s, void *v, word i, word n)
     654             : {
     655             :   heap_elt_t *e, *e0, *e1;
     656           0 :   heap_header_t *h = heap_header (v);
     657             :   word j;
     658             : 
     659           0 :   if (vec_len (h->elts) == 0)
     660           0 :     return s;
     661             : 
     662           0 :   if (i < 0)
     663           0 :     e0 = first (h);
     664             :   else
     665             :     {
     666           0 :       e0 = h->elts + i;
     667           0 :       for (j = 0; j < n / 2; j++)
     668           0 :         e0 = heap_prev (e0);
     669             :     }
     670             : 
     671           0 :   if (n < 0)
     672           0 :     e1 = h->elts + h->tail;
     673             :   else
     674             :     {
     675           0 :       e1 = h->elts + i;
     676           0 :       for (j = 0; j < n / 2; j++)
     677           0 :         e1 = heap_next (e1);
     678             :     }
     679             : 
     680           0 :   i = -n / 2;
     681           0 :   for (e = e0; 1; e = heap_next (e))
     682             :     {
     683           0 :       if (heap_is_free (e))
     684           0 :         s = format (s, "index %4d, free\n", e - h->elts);
     685           0 :       else if (h->format_elt)
     686           0 :         s = format (s, "%U", h->format_elt, v, elt_data (v, e));
     687             :       else
     688           0 :         s = format (s, "index %4d, used\n", e - h->elts);
     689           0 :       i++;
     690           0 :       if (e == e1)
     691           0 :         break;
     692             :     }
     693             : 
     694           0 :   return s;
     695             : }
     696             : 
     697             : __clib_export u8 *
     698           0 : format_heap (u8 *s, va_list *va)
     699             : {
     700           0 :   void *v = va_arg (*va, void *);
     701           0 :   uword verbose = va_arg (*va, uword);
     702           0 :   heap_header_t *h = heap_header (v);
     703             :   heap_header_t zero;
     704             : 
     705           0 :   clib_memset (&zero, 0, sizeof (zero));
     706             : 
     707           0 :   if (!v)
     708           0 :     h = &zero;
     709             : 
     710             :   {
     711           0 :     f64 elt_bytes = vec_len (v) * h->elt_bytes;
     712           0 :     f64 overhead_bytes = heap_bytes (v);
     713             : 
     714           0 :     s = format (s, "heap %p, %6d objects, size %.1fk + overhead %.1fk\n",
     715             :                 v, h->used_count, elt_bytes / 1024,
     716           0 :                 (overhead_bytes - elt_bytes) / 1024);
     717             :   }
     718             : 
     719           0 :   if (v && verbose)
     720           0 :     s = debug_elt (s, v, -1, -1);
     721             : 
     722           0 :   return s;
     723             : }
     724             : 
     725             : __clib_export void
     726           0 : heap_validate (void *v)
     727             : {
     728           0 :   heap_header_t *h = heap_header (v);
     729             :   uword i, o, s;
     730             :   u8 *free_map;
     731             :   heap_elt_t *e, *n;
     732             : 
     733             :   uword used_count, total_size;
     734             :   uword free_count, free_size;
     735             : 
     736           0 :   ASSERT (h->used_count == clib_bitmap_count_set_bits (h->used_elt_bitmap));
     737             : 
     738           0 :   ASSERT (first (h)->prev == 0);
     739           0 :   ASSERT (last (h)->next == 0);
     740             : 
     741             :   /* Validate number of elements and size. */
     742           0 :   free_size = free_count = 0;
     743           0 :   for (i = 0; i < vec_len (h->free_lists); i++)
     744             :     {
     745           0 :       free_count += vec_len (h->free_lists[i]);
     746           0 :       for (o = 0; o < vec_len (h->free_lists[i]); o++)
     747             :         {
     748           0 :           e = h->elts + h->free_lists[i][o];
     749           0 :           s = heap_elt_size (v, e);
     750           0 :           ASSERT (size_to_bin (s) == i);
     751           0 :           ASSERT (heap_is_free (e));
     752           0 :           free_size += s;
     753             :         }
     754             :     }
     755             : 
     756             :   {
     757             :     uword elt_free_size, elt_free_count;
     758             : 
     759           0 :     used_count = total_size = elt_free_size = elt_free_count = 0;
     760           0 :     for (e = first (h); 1; e = n)
     761           0 :       {
     762           0 :         int is_free = heap_is_free (e);
     763           0 :         used_count++;
     764           0 :         s = heap_elt_size (v, e);
     765           0 :         total_size += s;
     766           0 :         ASSERT (is_free ==
     767             :                 !clib_bitmap_get (h->used_elt_bitmap, e - h->elts));
     768           0 :         if (is_free)
     769             :           {
     770           0 :             elt_free_count++;
     771           0 :             elt_free_size += s;
     772             :           }
     773           0 :         n = heap_next (e);
     774           0 :         if (e == n)
     775             :           {
     776           0 :             ASSERT (last (h) == n);
     777           0 :             break;
     778             :           }
     779             : 
     780             :         /* We should never have two free adjacent elements. */
     781           0 :         ASSERT (!(heap_is_free (e) && heap_is_free (n)));
     782             :       }
     783             : 
     784           0 :     ASSERT (free_count == elt_free_count);
     785           0 :     ASSERT (free_size == elt_free_size);
     786           0 :     ASSERT (used_count == h->used_count + free_count);
     787           0 :     ASSERT (total_size == vec_len (v));
     788             :   }
     789             : 
     790           0 :   free_map = vec_new (u8, used_count);
     791             : 
     792           0 :   e = first (h);
     793           0 :   for (i = o = 0; 1; i++)
     794             :     {
     795           0 :       ASSERT (heap_offset (e) == o);
     796           0 :       s = heap_elt_size (v, e);
     797             : 
     798           0 :       if (heap_is_free (e))
     799             :         {
     800             :           uword fb, fi;
     801             : 
     802           0 :           fi = get_free_elt (v, e, &fb);
     803             : 
     804           0 :           ASSERT (fb < vec_len (h->free_lists));
     805           0 :           ASSERT (fi < vec_len (h->free_lists[fb]));
     806           0 :           ASSERT (h->free_lists[fb][fi] == e - h->elts);
     807             : 
     808           0 :           ASSERT (!free_map[i]);
     809           0 :           free_map[i] = 1;
     810             :         }
     811             : 
     812           0 :       n = heap_next (e);
     813             : 
     814           0 :       if (e == n)
     815           0 :         break;
     816             : 
     817           0 :       ASSERT (heap_prev (n) == e);
     818             : 
     819           0 :       o += s;
     820           0 :       e = n;
     821             :     }
     822             : 
     823           0 :   vec_free (free_map);
     824           0 : }
     825             : 
     826             : /*
     827             :  * fd.io coding-style-patch-verification: ON
     828             :  *
     829             :  * Local Variables:
     830             :  * eval: (c-set-style "gnu")
     831             :  * End:
     832             :  */

Generated by: LCOV version 1.14