back to topotato report
topotato coverage report
Current view: top level - lib - memory.c (source / functions) Hit Total Coverage
Test: test_pim_bfd.py::PIMBFDTest Lines: 82 90 91.1 %
Date: 2023-02-24 18:39:40 Functions: 17 18 94.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015-16  David Lamparter, for NetDEF, Inc.
       3             :  *
       4             :  * Permission to use, copy, modify, and distribute this software for any
       5             :  * purpose with or without fee is hereby granted, provided that the above
       6             :  * copyright notice and this permission notice appear in all copies.
       7             :  *
       8             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       9             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      10             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      11             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      12             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      13             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      14             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      15             :  */
      16             : 
      17             : #include <zebra.h>
      18             : 
      19             : #include <stdlib.h>
      20             : #ifdef HAVE_MALLOC_H
      21             : #include <malloc.h>
      22             : #endif
      23             : #ifdef HAVE_MALLOC_NP_H
      24             : #include <malloc_np.h>
      25             : #endif
      26             : #ifdef HAVE_MALLOC_MALLOC_H
      27             : #include <malloc/malloc.h>
      28             : #endif
      29             : 
      30             : #include "memory.h"
      31             : #include "log.h"
      32             : #include "libfrr_trace.h"
      33             : 
      34             : static struct memgroup *mg_first = NULL;
      35             : struct memgroup **mg_insert = &mg_first;
      36             : 
      37          36 : DEFINE_MGROUP(LIB, "libfrr");
      38          36 : DEFINE_MTYPE(LIB, TMP, "Temporary memory");
      39          36 : DEFINE_MTYPE(LIB, BITFIELD, "Bitfield memory");
      40             : 
      41      661839 : static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
      42             : {
      43      661839 :         size_t current;
      44      661839 :         size_t oldsize;
      45             : 
      46      661839 :         current = 1 + atomic_fetch_add_explicit(&mt->n_alloc, 1,
      47             :                                                 memory_order_relaxed);
      48             : 
      49      661839 :         oldsize = atomic_load_explicit(&mt->n_max, memory_order_relaxed);
      50      661839 :         if (current > oldsize)
      51             :                 /* note that this may fail, but approximation is sufficient */
      52      374675 :                 atomic_compare_exchange_weak_explicit(&mt->n_max, &oldsize,
      53             :                                                       current,
      54             :                                                       memory_order_relaxed,
      55             :                                                       memory_order_relaxed);
      56             : 
      57      661839 :         oldsize = atomic_load_explicit(&mt->size, memory_order_relaxed);
      58      661839 :         if (oldsize == 0)
      59         738 :                 oldsize = atomic_exchange_explicit(&mt->size, size,
      60             :                                                    memory_order_relaxed);
      61      661839 :         if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
      62         205 :                 atomic_store_explicit(&mt->size, SIZE_VAR,
      63             :                                       memory_order_relaxed);
      64             : 
      65             : #ifdef HAVE_MALLOC_USABLE_SIZE
      66      661839 :         size_t mallocsz = malloc_usable_size(ptr);
      67             : 
      68      661838 :         current = mallocsz + atomic_fetch_add_explicit(&mt->total, mallocsz,
      69             :                                                        memory_order_relaxed);
      70      661838 :         oldsize = atomic_load_explicit(&mt->max_size, memory_order_relaxed);
      71      661838 :         if (current > oldsize)
      72             :                 /* note that this may fail, but approximation is sufficient */
      73      377650 :                 atomic_compare_exchange_weak_explicit(&mt->max_size, &oldsize,
      74             :                                                       current,
      75             :                                                       memory_order_relaxed,
      76             :                                                       memory_order_relaxed);
      77             : #endif
      78      661837 : }
      79             : 
      80      665953 : static inline void mt_count_free(struct memtype *mt, void *ptr)
      81             : {
      82      665953 :         frrtrace(2, frr_libfrr, memfree, mt, ptr);
      83             : 
      84      665953 :         assert(mt->n_alloc);
      85      665953 :         atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
      86             : 
      87             : #ifdef HAVE_MALLOC_USABLE_SIZE
      88      665953 :         size_t mallocsz = malloc_usable_size(ptr);
      89             : 
      90      665954 :         atomic_fetch_sub_explicit(&mt->total, mallocsz, memory_order_relaxed);
      91             : #endif
      92      665954 : }
      93             : 
      94      661839 : static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
      95             : {
      96      661839 :         frrtrace(3, frr_libfrr, memalloc, mt, ptr, size);
      97             : 
      98      661839 :         if (__builtin_expect(ptr == NULL, 0)) {
      99           0 :                 if (size) {
     100             :                         /* malloc(0) is allowed to return NULL */
     101           0 :                         memory_oom(size, mt->name);
     102             :                 }
     103             :                 return NULL;
     104             :         }
     105      661839 :         mt_count_alloc(mt, size, ptr);
     106      661839 :         return ptr;
     107             : }
     108             : 
     109       11987 : void *qmalloc(struct memtype *mt, size_t size)
     110             : {
     111       11987 :         return mt_checkalloc(mt, malloc(size), size);
     112             : }
     113             : 
     114      473050 : void *qcalloc(struct memtype *mt, size_t size)
     115             : {
     116      473050 :         return mt_checkalloc(mt, calloc(size, 1), size);
     117             : }
     118             : 
     119       48044 : void *qrealloc(struct memtype *mt, void *ptr, size_t size)
     120             : {
     121       48044 :         if (ptr)
     122       47977 :                 mt_count_free(mt, ptr);
     123       48044 :         return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
     124             : }
     125             : 
     126      128759 : void *qstrdup(struct memtype *mt, const char *str)
     127             : {
     128      128759 :         return str ? mt_checkalloc(mt, strdup(str), strlen(str) + 1) : NULL;
     129             : }
     130             : 
     131           0 : void qcountfree(struct memtype *mt, void *ptr)
     132             : {
     133           0 :         if (ptr)
     134           0 :                 mt_count_free(mt, ptr);
     135           0 : }
     136             : 
     137      823807 : void qfree(struct memtype *mt, void *ptr)
     138             : {
     139      823807 :         if (ptr)
     140      617976 :                 mt_count_free(mt, ptr);
     141      823808 :         free(ptr);
     142      823808 : }
     143             : 
     144          20 : int qmem_walk(qmem_walk_fn *func, void *arg)
     145             : {
     146          20 :         struct memgroup *mg;
     147          20 :         struct memtype *mt;
     148          20 :         int rv;
     149             : 
     150         104 :         for (mg = mg_first; mg; mg = mg->next) {
     151          84 :                 if ((rv = func(arg, mg, NULL)))
     152           0 :                         return rv;
     153        3556 :                 for (mt = mg->types; mt; mt = mt->next)
     154        3472 :                         if ((rv = func(arg, mg, mt)))
     155           0 :                                 return rv;
     156             :         }
     157             :         return 0;
     158             : }
     159             : 
     160             : struct exit_dump_args {
     161             :         FILE *fp;
     162             :         const char *prefix;
     163             :         int error;
     164             :         struct memgroup *mg_printed;
     165             : };
     166             : 
     167        3556 : static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
     168             : {
     169        3556 :         struct exit_dump_args *eda = arg;
     170        3556 :         char size[32];
     171             : 
     172        3556 :         if (!mt || !mt->n_alloc)
     173        3400 :                 return 0;
     174         156 :         if (!mg->active_at_exit)
     175          96 :                 eda->error++;
     176             : 
     177         156 :         if (eda->mg_printed != mg) {
     178          44 :                 if (eda->fp != stderr)
     179          20 :                         fprintf(eda->fp, "%s: showing active allocations in memory group %s",
     180             :                                 eda->prefix, mg->name);
     181          24 :                 else if (mg->active_at_exit)
     182          12 :                         zlog_debug("%s: showing active allocations in memory group %s",
     183             :                                 eda->prefix, mg->name);
     184             :                 else
     185          12 :                         zlog_warn("%s: showing active allocations in memory group %s",
     186             :                                 eda->prefix, mg->name);
     187          44 :                 eda->mg_printed = mg;
     188             :         }
     189             : 
     190         156 :         snprintf(size, sizeof(size), "%10zu", mt->size);
     191         156 :         if (eda->fp != stderr)
     192         144 :                 fprintf(eda->fp, "%s: memstats:  %-30s: %6zu * %s",
     193          72 :                                 eda->prefix, mt->name, mt->n_alloc,
     194          72 :                                 mt->size == SIZE_VAR ? "(variably sized)" : size);
     195          84 :         else if (mg->active_at_exit)
     196          36 :                 zlog_debug("%s: memstats:  %-30s: %6zu * %s",
     197             :                                 eda->prefix, mt->name, mt->n_alloc,
     198             :                                 mt->size == SIZE_VAR ? "(variably sized)" : size);
     199             :         else
     200          64 :                 zlog_warn("%s: memstats:  %-30s: %6zu * %s",
     201             :                                 eda->prefix, mt->name, mt->n_alloc,
     202             :                                 mt->size == SIZE_VAR ? "(variably sized)" : size);
     203             :         return 0;
     204             : }
     205             : 
     206          20 : int log_memstats(FILE *fp, const char *prefix)
     207             : {
     208          20 :         struct exit_dump_args eda = {.fp = fp, .prefix = prefix, .error = 0};
     209          20 :         qmem_walk(qmem_exit_walker, &eda);
     210          20 :         return eda.error;
     211             : }

Generated by: LCOV version v1.16-topotato