[lib/memory] Add mallinfo support
2006-02-15 Paul Jakma <paul.jakma@sun.com>
* configure.ac: Check for mallinfo, being careful to link test
so we can detect things like umem being used (which doesn't
provide a mallinfo).
* lib/memory.c: (mtype_memstr) new helper function to
return human friendly string for a byte count.
(mtype_stats_alloc) new function, for users to retrieve
number of objects allocated.
(show_memory_mallinfo) New function, show mallinfo statistics
if available.
(show_memory_all_cmd) Call show_memory_mallinfo, if mallinfo
is available.
* lib/memory.h: Export mtype_memstr and mtype_stats_alloc.
Provide a define for a reasonable buffer size for
mtype_memstr.
diff --git a/ChangeLog b/ChangeLog
index 33d1a02..98a0a8e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2006-02-15 Paul Jakma <paul.jakma@sun.com>
+
+ * configure.ac: Check for mallinfo, being careful to link test
+ so we can detect things like umem being used (which doesn't
+ provide a mallinfo).
+
2006-01-31 Paul Jakma <paul.jakma@sun.com>
* configure.ac: Cleanup the hideous {net,ucd}-snmp section
diff --git a/configure.ac b/configure.ac
index 8727e5d..841786f 100755
--- a/configure.ac
+++ b/configure.ac
@@ -5,7 +5,7 @@
## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
## Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st>
##
-## $Id: configure.ac,v 1.118 2006/01/31 10:09:27 paul Exp $
+## $Id: configure.ac,v 1.119 2006/03/30 13:53:59 paul Exp $
AC_PREREQ(2.53)
AC_INIT(Quagga, 0.99.3, [http://bugzilla.quagga.net])
@@ -1236,6 +1236,24 @@
)
fi
+dnl -----------------------------------------
+dnl check for malloc mallinfo struct and call
+dnl this must try and link using LIBS, in
+dnl order to check no alternative allocator
+dnl has been specified, which might not provide
+dnl mallinfo, e.g. such as Umem on Solaris.
+dnl -----------------------------------------
+AC_CHECK_HEADERS(malloc.h,
+ [AC_MSG_CHECKING(whether mallinfo is available)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
+ [[struct mallinfo ac_x; ac_x = mallinfo ();]])],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MALLINFO,,mallinfo)],
+ AC_MSG_RESULT(no)
+ )
+ ]
+)
+
dnl ----------
dnl configure date
dnl ----------
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 8794d69..de0f352 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,17 @@
+2006-03-15 Paul Jakma <paul.jakma@sun.com>
+
+ * memory.c: (mtype_memstr) new helper function to
+ return human friendly string for a byte count.
+ (mtype_stats_alloc) new function, for users to retrieve
+ number of objects allocated.
+ (show_memory_mallinfo) New function, show mallinfo statistics
+ if available.
+ (show_memory_all_cmd) Call show_memory_mallinfo, if mallinfo
+ is available.
+ * memory.h: Export mtype_memstr and mtype_stats_alloc.
+ Provide a define for a reasonable buffer size for
+ mtype_memstr.
+
2006-03-14 Paul Jakma <paul.jakma@sun.com>
* privs.c: (zprivs_caps_init) Change user IDs before lowering
diff --git a/lib/memory.c b/lib/memory.c
index dae2b9a..802c07f 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -21,6 +21,7 @@
*/
#include <zebra.h>
+#include <malloc.h>
#include "log.h"
#include "memory.h"
@@ -278,6 +279,47 @@
return needsep;
}
+#ifdef HAVE_MALLINFO
+static int
+show_memory_mallinfo (struct vty *vty)
+{
+ struct mallinfo minfo = mallinfo();
+ char buf[MTYPE_MEMSTR_LEN];
+
+ vty_out (vty, "System allocator statistics:%s", VTY_NEWLINE);
+ vty_out (vty, " Total heap allocated: %s%s",
+ mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.arena),
+ VTY_NEWLINE);
+ vty_out (vty, " Holding block headers: %s%s",
+ mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.hblkhd),
+ VTY_NEWLINE);
+ vty_out (vty, " Used small blocks: %s%s",
+ mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.usmblks),
+ VTY_NEWLINE);
+ vty_out (vty, " Used ordinary blocks: %s%s",
+ mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.uordblks),
+ VTY_NEWLINE);
+ vty_out (vty, " Free small blocks: %s%s",
+ mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fsmblks),
+ VTY_NEWLINE);
+ vty_out (vty, " Free ordinary blocks: %s%s",
+ mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fordblks),
+ VTY_NEWLINE);
+ vty_out (vty, " Ordinary blocks: %ld%s",
+ (unsigned long)minfo.ordblks,
+ VTY_NEWLINE);
+ vty_out (vty, " Small blocks: %ld%s",
+ (unsigned long)minfo.smblks,
+ VTY_NEWLINE);
+ vty_out (vty, " Holding blocks: %ld%s",
+ (unsigned long)minfo.hblks,
+ VTY_NEWLINE);
+ vty_out (vty, "(see system documentation for 'mallinfo' for meaning)%s",
+ VTY_NEWLINE);
+ return 1;
+}
+#endif /* HAVE_MALLINFO */
+
DEFUN (show_memory_all,
show_memory_all_cmd,
"show memory all",
@@ -287,7 +329,11 @@
{
struct mlist *ml;
int needsep = 0;
-
+
+#ifdef HAVE_MALLINFO
+ needsep = show_memory_mallinfo (vty);
+#endif /* HAVE_MALLINFO */
+
for (ml = mlists; ml->list; ml++)
{
if (needsep)
@@ -416,3 +462,72 @@
install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
install_element (ENABLE_NODE, &show_memory_isis_cmd);
}
+
+/* Stats querying from users */
+/* Return a pointer to a human friendly string describing
+ * the byte count passed in. E.g:
+ * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
+ * Up to 4 significant figures will be given.
+ * The pointer returned may be NULL (indicating an error)
+ * or point to the given buffer, or point to static storage.
+ */
+const char *
+mtype_memstr (char *buf, size_t len, unsigned long bytes)
+{
+ unsigned int t, g, m, k;
+
+ /* easy cases */
+ if (!bytes)
+ return "0 bytes";
+ if (bytes == 1)
+ return "1 byte";
+
+ if (sizeof (unsigned long) >= 8)
+ /* Hacked to make it not warn on ILP32 machines
+ * Shift will always be 40 at runtime. See below too */
+ t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0);
+ else
+ t = 0;
+ g = bytes >> 30;
+ m = bytes >> 20;
+ k = bytes >> 10;
+
+ if (t > 10)
+ {
+ /* The shift will always be 39 at runtime.
+ * Just hacked to make it not warn on 'smaller' machines.
+ * Static compiler analysis should mean no extra code
+ */
+ if (bytes & (1 << (sizeof (unsigned long) >= 8 ? 39 : 0)))
+ t++;
+ snprintf (buf, len, "%4d TiB", t);
+ }
+ else if (g > 10)
+ {
+ if (bytes & (1 << 29))
+ g++;
+ snprintf (buf, len, "%d GiB", g);
+ }
+ else if (m > 10)
+ {
+ if (bytes & (1 << 19))
+ m++;
+ snprintf (buf, len, "%d MiB", m);
+ }
+ else if (k > 10)
+ {
+ if (bytes & (1 << 9))
+ k++;
+ snprintf (buf, len, "%d KiB", k);
+ }
+ else
+ snprintf (buf, len, "%ld bytes", bytes);
+
+ return buf;
+}
+
+unsigned long
+mtype_stats_alloc (int type)
+{
+ return mstat[type].alloc;
+}
diff --git a/lib/memory.h b/lib/memory.h
index ef20b8c..071f394 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -79,4 +79,10 @@
const char *str);
extern void memory_init (void);
+/* return number of allocations outstanding for the type */
+extern unsigned long mtype_stats_alloc (int);
+
+/* Human friendly string for given byte count */
+#define MTYPE_MEMSTR_LEN 20
+extern const char *mtype_memstr (char *, size_t, unsigned long);
#endif /* _ZEBRA_MEMORY_H */