]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
debug tool for mem stats.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 3 Sep 2007 13:40:17 +0000 (13:40 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 3 Sep 2007 13:40:17 +0000 (13:40 +0000)
git-svn-id: file:///svn/unbound/trunk@580 be551aaa-1e26-0410-a405-d3ace91eadb9

Makefile.in
doc/Changelog
testcode/memstats.c [new file with mode: 0644]

index 9e7fbb86684e1ee1104932bffec0708abe4b0590..3cf9dc8377cd4fa04f786031258cb1b61aed77c2 100644 (file)
@@ -73,8 +73,11 @@ PKTVIEW_SRC=testcode/pktview.c testcode/readhex.c $(COMMON_SRC)
 PKTVIEW_OBJ=$(addprefix $(BUILD),$(PKTVIEW_SRC:.c=.o)) $(COMPAT_OBJ)
 SIGNIT_SRC=testcode/signit.c $(COMMON_SRC)
 SIGNIT_OBJ=$(addprefix $(BUILD),$(SIGNIT_SRC:.c=.o)) $(COMPAT_OBJ)
+MEMSTATS_SRC=testcode/memstats.c $(COMMON_SRC)
+MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ)
 ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
-       $(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC)
+       $(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
+       $(MEMSTATS_SRC)
 ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.o) \
        $(addprefix compat/,$(LIBOBJS))) $(COMPAT_OBJ)
 
@@ -89,7 +92,7 @@ $(BUILD)%.o:    $(srcdir)/%.c
 
 .PHONY:        clean realclean doc lint all install uninstall
 
-all:   $(COMMON_OBJ) unbound unittest testbound lock-verify pktview signit
+all:   $(COMMON_OBJ) unbound unittest testbound lock-verify pktview signit memstats
 
 unbound:       $(DAEMON_OBJ)
        $(INFO) Link $@
@@ -115,6 +118,10 @@ signit:    $(SIGNIT_OBJ)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $^ $(LIBS)
 
+memstats:      $(MEMSTATS_OBJ)
+       $(INFO) Link $@
+       $Q$(LINK) -o $@ $^ $(LIBS)
+
 #testcode/ldns-testpkts.c:     $(ldnsdir)/examples/ldns-testpkts.c \
 #                      $(ldnsdir)/examples/ldns-testpkts.h
 #      cp $(ldnsdir)/examples/ldns-testpkts.c testcode/ldns-testpkts.c
index d608f848c2de7db34a442be1cafdcfe3d22cbf1b..e6707f5b997bf315623490a398a538c82471bb56 100644 (file)
@@ -8,6 +8,7 @@
          not show lame cache growth as a leakage growth.
        - config setting for lameness cache expressed in bytes, instead of
          number of entries.
+       - tool too summarize allocations per code line.
 
 31 August 2007: Wouter
        - can read bind trusted-keys { ... }; files, in a compatibility mode. 
diff --git a/testcode/memstats.c b/testcode/memstats.c
new file mode 100644 (file)
index 0000000..cf00a9a
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * testcode/memstats.c - debug tool to show memory allocation statistics.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This program reads a log file and prints the memory allocation summed
+ * up.
+ */
+#include "config.h"
+#include "util/log.h"
+#include "util/rbtree.h"
+#include <sys/stat.h>
+
+/**
+ * The allocation statistics block
+ */
+struct codeline {
+       /** rbtree node */
+       rbnode_t node;
+       /** the name of the file:linenumber */
+       char* codeline;
+       /** the name of the function */
+       char* func;
+       /** number of bytes allocated */
+       uint64_t alloc;
+       /** number of bytes freed */
+       uint64_t free;
+};
+
+/**
+ * Other allocation stats
+ */
+struct alloc_misc {
+       /** number of region allocs */
+       uint64_t region_alloc;
+};
+
+/** print usage and exit */
+static void
+usage()
+{
+       printf("usage:  memstats <logfile>\n");
+       printf("statistics are printed on stdout.\n");
+       exit(1);
+}
+
+/** compare two codeline structs for rbtree */
+static int
+codeline_cmp(const void* a, const void* b)
+{
+       return strcmp((const char*)a, (const char*)b);
+}
+
+/** match logfile line to see if it needs accounting processing */
+static int
+match(char* line)
+{
+       /* f.e.:
+        * [1187340064] unbound[24604:0] info: ul/rb.c:81 r_create malloc(12)
+        * 0123456789 123456789 123456789 123456789
+        */
+       if(strlen(line) < 36) /* up to 'info: ' */
+               return 0;
+       if(strncmp(line+30, "info: ", 6) != 0)
+               return 0;
+       if(strncmp(line+36, "stat ", 5) == 0)
+               return 0; /* skip the hex dumps */
+       if(strstr(line+36, "malloc("))
+               return 1;
+       else if(strstr(line+36, "calloc("))
+               return 1;
+       /* skip reallocs */
+       return 0;
+}
+
+/** read up the region stats */
+static void
+read_region_stat(char* line, struct alloc_misc* misc)
+{
+       long num = 0;
+       if(sscanf(line+50, "%ld", &num) != 1) {
+               printf("%s\n%s\n", line, line+50);
+               fatal_exit("unhandled region");
+       }
+       misc->region_alloc += num;
+}
+
+/** find or alloc codeline in tree */
+static struct codeline*
+get_codeline(rbtree_t* tree, char* key, char* func)
+{
+       struct codeline* cl = (struct codeline*)rbtree_search(tree, key);
+       if(!cl) {
+               cl = calloc(1, sizeof(*cl));
+               if(!cl) return 0;
+               cl->codeline = strdup(key);
+               if(!cl->codeline) return 0;
+               cl->func = strdup(func);
+               if(!cl->func) return 0;
+               cl->alloc = 0;
+               cl->node.key = cl->codeline;
+               rbtree_insert(tree, &cl->node);
+       }
+       return cl;
+}
+
+/** read up the malloc stats */
+static void
+read_malloc_stat(char* line, rbtree_t* tree)
+{
+       char codeline[10240];
+       char name[10240];
+       int skip = 0;
+       long num = 0;
+       struct codeline* cl = 0;
+       if(sscanf(line+36, "%s %s %n", codeline, name, &skip) != 2) {
+               printf("%s\n%s\n", line, line+36);
+               fatal_exit("unhandled malloc");
+       }
+       if(sscanf(line+36+skip+7, "%ld", &num) != 1) {
+               printf("%s\n%s\n", line, line+36+skip+7);
+               fatal_exit("unhandled malloc");
+       }
+       cl = get_codeline(tree, codeline, name);
+       if(!cl)
+               fatal_exit("alloc failure");
+       cl->alloc += num;
+}
+
+/** read up the calloc stats */
+static void
+read_calloc_stat(char* line, rbtree_t* tree)
+{
+       char codeline[10240];
+       char name[10240];
+       int skip = 0;
+       long num = 0, sz = 0;
+       struct codeline* cl = 0;
+       if(sscanf(line+36, "%s %s %n", codeline, name, &skip) != 2) {
+               printf("%s\n%s\n", line, line+36);
+               fatal_exit("unhandled calloc");
+       }
+       if(sscanf(line+36+skip+7, "%ld, %ld", &num, &sz) != 2) {
+               printf("%s\n%s\n", line, line+36+skip+7);
+               fatal_exit("unhandled calloc");
+       }
+
+       cl = get_codeline(tree, codeline, name);
+       if(!cl)
+               fatal_exit("alloc failure");
+       cl->alloc += num*sz;
+}
+
+/** get size of file */
+static off_t
+get_file_size(const char* fname)
+{
+       struct stat s;
+       if(stat(fname, &s) < 0) {
+               fatal_exit("could not stat %s: %s", fname, strerror(errno));
+       }
+       return s.st_size;
+}
+
+/** read the logfile */
+static void
+readfile(rbtree_t* tree, const char* fname, struct alloc_misc* misc)
+{
+       off_t total = get_file_size(fname);
+       off_t done = 0;
+       int report = 0;
+       FILE* in = fopen(fname, "r");
+       char buf[102400];
+       if(!in)
+               fatal_exit("could not open %s: %s", fname, strerror(errno));
+       printf("Reading %s of size %lld\n", fname, (uint64_t)total);
+       while(fgets(buf, 102400, in)) {
+               buf[102400-1] = 0;
+               done += strlen(buf);
+               /* progress count */
+               if((int)(((double)done / (double)total)*100.) > report) {
+                       report = (int)(((double)done / (double)total)*100.);
+                       fprintf(stderr, " %d%%", report);
+               }
+
+               if(!match(buf))
+                       continue;
+               if(strncmp(buf+36, "region ", 7) == 0)
+                       read_region_stat(buf, misc);
+               else if(strstr(buf+36, "malloc("))
+                       read_malloc_stat(buf, tree);
+               else if(strstr(buf+36, "calloc("))
+                       read_calloc_stat(buf, tree);
+               else {
+                       printf("%s\n", buf);
+                       fatal_exit("unhandled input");
+               }
+       }
+       fprintf(stderr, " done\n");
+       fclose(in);
+}
+
+/** print memory stats */
+static void
+printstats(rbtree_t* tree, struct alloc_misc* misc)
+{
+       struct codeline* cl;
+       uint64_t total = 0;
+       printf("%12lld in region alloc\n", misc->region_alloc);
+       total += misc->region_alloc;
+       RBTREE_FOR(cl, struct codeline*, tree) {
+               printf("%12lld in %s %s\n", cl->alloc, cl->codeline, cl->func);
+               total += cl->alloc;
+       }
+       printf("------------\n");
+       printf("%12lld total in %ld code lines\n", total, (long)tree->count);
+       printf("\n");
+}
+
+/** main program */
+int main(int argc, const char* argv[])
+{
+       rbtree_t* tree = 0;
+       struct alloc_misc misc;
+       if(argc != 2) {
+               usage();
+       }
+       tree = rbtree_create(codeline_cmp);
+       if(!tree)
+               fatal_exit("alloc failure");
+       memset(&misc, 0, sizeof(misc));
+       readfile(tree, argv[1], &misc);
+       printstats(tree, &misc);
+       return 0;
+}