Annotation of embedaddon/quagga/lib/memory.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:  * Memory management routine
                      3:  * Copyright (C) 1998 Kunihiro Ishiguro
                      4:  *
                      5:  * This file is part of GNU Zebra.
                      6:  *
                      7:  * GNU Zebra is free software; you can redistribute it and/or modify it
                      8:  * under the terms of the GNU General Public License as published by the
                      9:  * Free Software Foundation; either version 2, or (at your option) any
                     10:  * later version.
                     11:  *
                     12:  * GNU Zebra is distributed in the hope that it will be useful, but
                     13:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     15:  * General Public License for more details.
                     16:  *
                     17:  * You should have received a copy of the GNU General Public License
                     18:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
                     19:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
                     20:  * 02111-1307, USA.  
                     21:  */
                     22: 
                     23: #include <zebra.h>
                     24: /* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */
                     25: #if !defined(HAVE_STDLIB_H) || (defined(GNU_LINUX) && defined(HAVE_MALLINFO))
                     26: #include <malloc.h>
                     27: #endif /* !HAVE_STDLIB_H || HAVE_MALLINFO */
                     28: 
                     29: #include "log.h"
                     30: #include "memory.h"
                     31: 
                     32: static void alloc_inc (int);
                     33: static void alloc_dec (int);
                     34: static void log_memstats(int log_priority);
1.1.1.3 ! misho      35: 
1.1       misho      36: static const struct message mstr [] =
                     37: {
                     38:   { MTYPE_THREAD, "thread" },
                     39:   { MTYPE_THREAD_MASTER, "thread_master" },
                     40:   { MTYPE_VECTOR, "vector" },
                     41:   { MTYPE_VECTOR_INDEX, "vector_index" },
                     42:   { MTYPE_IF, "interface" },
                     43:   { 0, NULL },
                     44: };
1.1.1.3 ! misho      45: 
1.1       misho      46: /* Fatal memory allocation error occured. */
                     47: static void __attribute__ ((noreturn))
                     48: zerror (const char *fname, int type, size_t size)
                     49: {
                     50:   zlog_err ("%s : can't allocate memory for `%s' size %d: %s\n", 
                     51:            fname, lookup (mstr, type), (int) size, safe_strerror(errno));
                     52:   log_memstats(LOG_WARNING);
                     53:   /* N.B. It might be preferable to call zlog_backtrace_sigsafe here, since
                     54:      that function should definitely be safe in an OOM condition.  But
                     55:      unfortunately zlog_backtrace_sigsafe does not support syslog logging at
                     56:      this time... */
                     57:   zlog_backtrace(LOG_WARNING);
                     58:   abort();
                     59: }
                     60: 
                     61: /*
                     62:  * Allocate memory of a given size, to be tracked by a given type.
                     63:  * Effects: Returns a pointer to usable memory.  If memory cannot
                     64:  * be allocated, aborts execution.
                     65:  */
                     66: void *
                     67: zmalloc (int type, size_t size)
                     68: {
                     69:   void *memory;
                     70: 
                     71:   memory = malloc (size);
                     72: 
                     73:   if (memory == NULL)
                     74:     zerror ("malloc", type, size);
                     75: 
                     76:   alloc_inc (type);
                     77: 
                     78:   return memory;
                     79: }
                     80: 
                     81: /*
                     82:  * Allocate memory as in zmalloc, and also clear the memory.
                     83:  */
                     84: void *
                     85: zcalloc (int type, size_t size)
                     86: {
                     87:   void *memory;
                     88: 
                     89:   memory = calloc (1, size);
                     90: 
                     91:   if (memory == NULL)
                     92:     zerror ("calloc", type, size);
                     93: 
                     94:   alloc_inc (type);
                     95: 
                     96:   return memory;
                     97: }
                     98: 
                     99: /* 
                    100:  * Given a pointer returned by zmalloc or zcalloc, free it and
                    101:  * return a pointer to a new size, basically acting like realloc().
                    102:  * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
                    103:  * same type.
                    104:  * Effects: Returns a pointer to the new memory, or aborts.
                    105:  */
                    106: void *
                    107: zrealloc (int type, void *ptr, size_t size)
                    108: {
                    109:   void *memory;
                    110: 
1.1.1.3 ! misho     111:   if (ptr == NULL)              /* is really alloc */
        !           112:       return zcalloc(type, size);
        !           113: 
1.1       misho     114:   memory = realloc (ptr, size);
                    115:   if (memory == NULL)
                    116:     zerror ("realloc", type, size);
                    117:   if (ptr == NULL)
                    118:     alloc_inc (type);
                    119: 
                    120:   return memory;
                    121: }
                    122: 
                    123: /*
                    124:  * Free memory allocated by z*alloc or zstrdup.
                    125:  * Requires: ptr was returned by zmalloc, zcalloc, or zrealloc with the
                    126:  * same type.
                    127:  * Effects: The memory is freed and may no longer be referenced.
                    128:  */
                    129: void
                    130: zfree (int type, void *ptr)
                    131: {
                    132:   if (ptr != NULL)
                    133:     {
                    134:       alloc_dec (type);
                    135:       free (ptr);
                    136:     }
                    137: }
                    138: 
                    139: /*
                    140:  * Duplicate a string, counting memory usage by type.
                    141:  * Effects: The string is duplicated, and the return value must
                    142:  * eventually be passed to zfree with the same type.  The function will
                    143:  * succeed or abort.
                    144:  */
                    145: char *
                    146: zstrdup (int type, const char *str)
                    147: {
                    148:   void *dup;
                    149: 
                    150:   dup = strdup (str);
                    151:   if (dup == NULL)
                    152:     zerror ("strdup", type, strlen (str));
                    153:   alloc_inc (type);
                    154:   return dup;
                    155: }
1.1.1.3 ! misho     156: 
1.1       misho     157: #ifdef MEMORY_LOG
                    158: static struct 
                    159: {
                    160:   const char *name;
                    161:   long alloc;
                    162:   unsigned long t_malloc;
                    163:   unsigned long c_malloc;
                    164:   unsigned long t_calloc;
                    165:   unsigned long c_calloc;
                    166:   unsigned long t_realloc;
                    167:   unsigned long t_free;
                    168:   unsigned long c_strdup;
                    169: } mstat [MTYPE_MAX];
                    170: 
                    171: static void
                    172: mtype_log (char *func, void *memory, const char *file, int line, int type)
                    173: {
                    174:   zlog_debug ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line);
                    175: }
                    176: 
                    177: void *
                    178: mtype_zmalloc (const char *file, int line, int type, size_t size)
                    179: {
                    180:   void *memory;
                    181: 
                    182:   mstat[type].c_malloc++;
                    183:   mstat[type].t_malloc++;
                    184: 
                    185:   memory = zmalloc (type, size);
                    186:   mtype_log ("zmalloc", memory, file, line, type);
                    187: 
                    188:   return memory;
                    189: }
                    190: 
                    191: void *
                    192: mtype_zcalloc (const char *file, int line, int type, size_t size)
                    193: {
                    194:   void *memory;
                    195: 
                    196:   mstat[type].c_calloc++;
                    197:   mstat[type].t_calloc++;
                    198: 
                    199:   memory = zcalloc (type, size);
                    200:   mtype_log ("xcalloc", memory, file, line, type);
                    201: 
                    202:   return memory;
                    203: }
                    204: 
                    205: void *
                    206: mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
                    207: {
                    208:   void *memory;
                    209: 
                    210:   /* Realloc need before allocated pointer. */
                    211:   mstat[type].t_realloc++;
                    212: 
                    213:   memory = zrealloc (type, ptr, size);
                    214: 
                    215:   mtype_log ("xrealloc", memory, file, line, type);
                    216: 
                    217:   return memory;
                    218: }
                    219: 
                    220: /* Important function. */
                    221: void 
                    222: mtype_zfree (const char *file, int line, int type, void *ptr)
                    223: {
                    224:   mstat[type].t_free++;
                    225: 
                    226:   mtype_log ("xfree", ptr, file, line, type);
                    227: 
                    228:   zfree (type, ptr);
                    229: }
                    230: 
                    231: char *
                    232: mtype_zstrdup (const char *file, int line, int type, const char *str)
                    233: {
                    234:   char *memory;
                    235: 
                    236:   mstat[type].c_strdup++;
                    237: 
                    238:   memory = zstrdup (type, str);
                    239:   
                    240:   mtype_log ("xstrdup", memory, file, line, type);
                    241: 
                    242:   return memory;
                    243: }
                    244: #else
                    245: static struct 
                    246: {
                    247:   char *name;
                    248:   long alloc;
                    249: } mstat [MTYPE_MAX];
                    250: #endif /* MEMORY_LOG */
                    251: 
                    252: /* Increment allocation counter. */
                    253: static void
                    254: alloc_inc (int type)
                    255: {
                    256:   mstat[type].alloc++;
                    257: }
                    258: 
                    259: /* Decrement allocation counter. */
                    260: static void
                    261: alloc_dec (int type)
                    262: {
                    263:   mstat[type].alloc--;
                    264: }
1.1.1.3 ! misho     265: 
1.1       misho     266: /* Looking up memory status from vty interface. */
                    267: #include "vector.h"
                    268: #include "vty.h"
                    269: #include "command.h"
                    270: 
                    271: static void
                    272: log_memstats(int pri)
                    273: {
                    274:   struct mlist *ml;
                    275: 
                    276:   for (ml = mlists; ml->list; ml++)
                    277:     {
                    278:       struct memory_list *m;
                    279: 
                    280:       zlog (NULL, pri, "Memory utilization in module %s:", ml->name);
                    281:       for (m = ml->list; m->index >= 0; m++)
                    282:        if (m->index && mstat[m->index].alloc)
                    283:          zlog (NULL, pri, "  %-30s: %10ld", m->format, mstat[m->index].alloc);
                    284:     }
                    285: }
                    286: 
                    287: void
                    288: log_memstats_stderr (const char *prefix)
                    289: {
                    290:   struct mlist *ml;
                    291:   struct memory_list *m;
                    292:   int i;
                    293:   int j = 0;
                    294: 
                    295:   for (ml = mlists; ml->list; ml++)
                    296:     {
                    297:       i = 0;
                    298: 
                    299:       for (m = ml->list; m->index >= 0; m++)
                    300:         if (m->index && mstat[m->index].alloc)
                    301:           {
                    302:             if (!i)
                    303:               fprintf (stderr,
                    304:                        "%s: memstats: Current memory utilization in module %s:\n",
                    305:                        prefix,
                    306:                        ml->name);
                    307:             fprintf (stderr,
                    308:                      "%s: memstats:  %-30s: %10ld%s\n",
                    309:                      prefix,
                    310:                      m->format,
                    311:                      mstat[m->index].alloc,
                    312:                      mstat[m->index].alloc < 0 ? " (REPORT THIS BUG!)" : "");
                    313:             i = j = 1;
                    314:           }
                    315:     }
                    316: 
                    317:   if (j)
                    318:     fprintf (stderr,
                    319:              "%s: memstats: NOTE: If configuration exists, utilization may be "
                    320:              "expected.\n",
                    321:              prefix);
                    322:   else
                    323:     fprintf (stderr,
                    324:              "%s: memstats: No remaining tracked memory utilization.\n",
                    325:              prefix);
                    326: }
                    327: 
                    328: static void
                    329: show_separator(struct vty *vty)
                    330: {
                    331:   vty_out (vty, "-----------------------------\r\n");
                    332: }
                    333: 
                    334: static int
                    335: show_memory_vty (struct vty *vty, struct memory_list *list)
                    336: {
                    337:   struct memory_list *m;
                    338:   int needsep = 0;
                    339: 
                    340:   for (m = list; m->index >= 0; m++)
                    341:     if (m->index == 0)
                    342:       {
                    343:        if (needsep)
                    344:          {
                    345:            show_separator (vty);
                    346:            needsep = 0;
                    347:          }
                    348:       }
                    349:     else if (mstat[m->index].alloc)
                    350:       {
                    351:        vty_out (vty, "%-30s: %10ld\r\n", m->format, mstat[m->index].alloc);
                    352:        needsep = 1;
                    353:       }
                    354:   return needsep;
                    355: }
                    356: 
                    357: #ifdef HAVE_MALLINFO
                    358: static int
                    359: show_memory_mallinfo (struct vty *vty)
                    360: {
                    361:   struct mallinfo minfo = mallinfo();
                    362:   char buf[MTYPE_MEMSTR_LEN];
                    363:   
                    364:   vty_out (vty, "System allocator statistics:%s", VTY_NEWLINE);
                    365:   vty_out (vty, "  Total heap allocated:  %s%s",
                    366:            mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.arena),
                    367:            VTY_NEWLINE);
                    368:   vty_out (vty, "  Holding block headers: %s%s",
                    369:            mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.hblkhd),
                    370:            VTY_NEWLINE);
                    371:   vty_out (vty, "  Used small blocks:     %s%s",
                    372:            mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.usmblks),
                    373:            VTY_NEWLINE);
                    374:   vty_out (vty, "  Used ordinary blocks:  %s%s",
                    375:            mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.uordblks),
                    376:            VTY_NEWLINE);
                    377:   vty_out (vty, "  Free small blocks:     %s%s",
                    378:            mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fsmblks),
                    379:            VTY_NEWLINE);
                    380:   vty_out (vty, "  Free ordinary blocks:  %s%s",
                    381:            mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fordblks),
                    382:            VTY_NEWLINE);
                    383:   vty_out (vty, "  Ordinary blocks:       %ld%s",
                    384:            (unsigned long)minfo.ordblks,
                    385:            VTY_NEWLINE);
                    386:   vty_out (vty, "  Small blocks:          %ld%s",
                    387:            (unsigned long)minfo.smblks,
                    388:            VTY_NEWLINE);
                    389:   vty_out (vty, "  Holding blocks:        %ld%s",
                    390:            (unsigned long)minfo.hblks,
                    391:            VTY_NEWLINE);
                    392:   vty_out (vty, "(see system documentation for 'mallinfo' for meaning)%s",
                    393:            VTY_NEWLINE);
                    394:   return 1;
                    395: }
                    396: #endif /* HAVE_MALLINFO */
                    397: 
1.1.1.3 ! misho     398: DEFUN (show_memory,
        !           399:        show_memory_cmd,
        !           400:        "show memory",
1.1       misho     401:        "Show running system information\n"
1.1.1.3 ! misho     402:        "Memory statistics\n")
1.1       misho     403: {
                    404:   struct mlist *ml;
                    405:   int needsep = 0;
                    406:   
                    407: #ifdef HAVE_MALLINFO
                    408:   needsep = show_memory_mallinfo (vty);
                    409: #endif /* HAVE_MALLINFO */
                    410:   
                    411:   for (ml = mlists; ml->list; ml++)
                    412:     {
                    413:       if (needsep)
                    414:        show_separator (vty);
                    415:       needsep = show_memory_vty (vty, ml->list);
                    416:     }
                    417: 
                    418:   return CMD_SUCCESS;
                    419: }
                    420: 
                    421: 
                    422: void
                    423: memory_init (void)
                    424: {
                    425:   install_element (RESTRICTED_NODE, &show_memory_cmd);
                    426: 
                    427:   install_element (VIEW_NODE, &show_memory_cmd);
                    428: 
                    429:   install_element (ENABLE_NODE, &show_memory_cmd);
                    430: }
1.1.1.3 ! misho     431: 
1.1       misho     432: /* Stats querying from users */
                    433: /* Return a pointer to a human friendly string describing
                    434:  * the byte count passed in. E.g:
                    435:  * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
                    436:  * Up to 4 significant figures will be given.
                    437:  * The pointer returned may be NULL (indicating an error)
                    438:  * or point to the given buffer, or point to static storage.
                    439:  */
                    440: const char *
                    441: mtype_memstr (char *buf, size_t len, unsigned long bytes)
                    442: {
1.1.1.3 ! misho     443:   unsigned int m, k;
        !           444: 
1.1       misho     445:   /* easy cases */
                    446:   if (!bytes)
                    447:     return "0 bytes";
                    448:   if (bytes == 1)
                    449:     return "1 byte";
1.1.1.3 ! misho     450: 
        !           451:   /*
        !           452:    * When we pass the 2gb barrier mallinfo() can no longer report
        !           453:    * correct data so it just does something odd...
        !           454:    * Reporting like Terrabytes of data.  Which makes users...
        !           455:    * edgy.. yes edgy that's the term for it.
        !           456:    * So let's just give up gracefully
        !           457:    */
        !           458:   if (bytes > 0x7fffffff)
        !           459:     return "> 2GB";
        !           460: 
1.1       misho     461:   m = bytes >> 20;
                    462:   k = bytes >> 10;
1.1.1.3 ! misho     463: 
        !           464:  if (m > 10)
1.1       misho     465:     {
                    466:       if (bytes & (1 << 19))
                    467:         m++;
                    468:       snprintf (buf, len, "%d MiB", m);
                    469:     }
                    470:   else if (k > 10)
                    471:     {
                    472:       if (bytes & (1 << 9))
                    473:         k++;
                    474:       snprintf (buf, len, "%d KiB", k);
                    475:     }
                    476:   else
                    477:     snprintf (buf, len, "%ld bytes", bytes);
                    478:   
                    479:   return buf;
                    480: }
                    481: 
                    482: unsigned long
                    483: mtype_stats_alloc (int type)
                    484: {
                    485:   return mstat[type].alloc;
                    486: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>