tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Extend "struct malloc_type" for extended KMEMSTATS?



Hi,

it's time to pick up an old issue I discussed here earlier.

As described earlier, I'd like to extend vmstat to show the
number of allocations done per type and size, like so:

Memory statistics by type                                Type  Kern
           Type InUse  MemUse HighUse   Limit   Requests Limit Limit Size(s)
   kernfs mount     1      1K      1K  78644K          1     0     0 16:1
    ptyfs mount     1      1K      1K  78644K          1     0     0 16:1
     prop array     1      1K      1K  78644K          1     0     0 64:1
prop dictionary   145     19K     19K  78644K        145     0     0 128:145
    prop string   143      3K      3K  78644K        143     0     0 16:143
           acpi    30      1K      1K  78644K         31     0     0 
16:7,32:19,64:4
            USB    46      5K      5K  78644K         52     0     0 
16:6,32:6,64:19,128:9,256:6,1024:0
     USB device    18     19K     19K  78644K         18     0     0 
16:6,128:3,2048:9

These stats are only available under KMEMSTATS, but since struct
malloc_type is part of what vmstat uses, it would not be friendly
to require a new vmstat just because you turned on KMEMSTATS in
the kernel.  This means that this change will currently consume
around 5-6KB extra kernel memory.  All the counting in the kernel
is however done under KMEMSTATS ifdefs.

While it is apparently true that malloc(9) over time is being
replaced by kmem(9), there remains a large number of uses of
malloc(9) in the kernel, and they are unlikely to go away anytime
soon.

This change is the first stage of a two-stage set of changes
which would make it easier to spot and trace kernel memory leaks
in use of malloc(9), and was of much help finding the kernel
memory leak documented in PRs 39145 and 42661.

The new diff is attached below.  This time I've refrained from
the re-typing of the preexisting fields in "struct malloc_type",
to keep the change as small as possible.

It would appear that in addition to this change, a kernel
revision bump would be required.

Comments?

Regards,

- Håvard
Index: sys/sys/mallocvar.h
===================================================================
RCS file: /cvsroot/src/sys/sys/mallocvar.h,v
retrieving revision 1.7
diff -u -p -r1.7 mallocvar.h
--- sys/sys/mallocvar.h 7 Nov 2007 16:12:25 -0000       1.7
+++ sys/sys/mallocvar.h 31 Mar 2010 12:52:13 -0000
@@ -56,7 +56,7 @@ struct malloc_type {
        u_long  ks_maxused;     /* maximum number ever used */
        u_long  ks_limit;       /* most that are allowed to exist */
        u_long  ks_size;        /* sizes of this thing that are allocated */
-       u_long  ks_spare;
+       u_int   ks_active[32];  /* number of active allocations per size */
 };
 
 #ifdef _KERNEL
Index: sys/kern/kern_malloc.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_malloc.c,v
retrieving revision 1.128
diff -u -p -r1.128 kern_malloc.c
--- sys/kern/kern_malloc.c      22 Jan 2010 08:32:05 -0000      1.128
+++ sys/kern/kern_malloc.c      31 Mar 2010 12:52:13 -0000
@@ -371,6 +371,7 @@ kern_malloc(unsigned long size, struct m
                        &malloc_lock);
        }
        ksp->ks_size |= 1 << indx;
+       ksp->ks_active[indx]++;
 #endif
 #ifdef DIAGNOSTIC
        copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
@@ -604,6 +605,7 @@ kern_free(void *addr, struct malloc_type
 #ifdef KMEMSTATS
                size = kup->ku_pagecnt << PGSHIFT;
                ksp->ks_memuse -= size;
+               ksp->ks_active[kup->ku_indx]--;
                kup->ku_indx = 0;
                kup->ku_pagecnt = 0;
                if (ksp->ks_memuse + size >= ksp->ks_limit &&
@@ -660,6 +662,7 @@ kern_free(void *addr, struct malloc_type
        }
        kbp->kb_totalfree++;
        ksp->ks_memuse -= size;
+       ksp->ks_active[kup->ku_indx]--;
        if (ksp->ks_memuse + size >= ksp->ks_limit &&
            ksp->ks_memuse < ksp->ks_limit)
                wakeup((void *)ksp);
Index: usr.bin/vmstat/vmstat.c
===================================================================
RCS file: /cvsroot/src/usr.bin/vmstat/vmstat.c,v
retrieving revision 1.166
diff -u -p -r1.166 vmstat.c
--- usr.bin/vmstat/vmstat.c     21 Oct 2009 21:12:07 -0000      1.166
+++ usr.bin/vmstat/vmstat.c     31 Mar 2010 12:52:13 -0000
@@ -1172,7 +1172,10 @@ domem(void)
                    howmany(ks.ks_limit, KILO), ks.ks_calls,
                    ks.ks_limblocks, ks.ks_mapblocks);
                first = 1;
-               for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
+               for (j = 1 << MINBUCKET, i = MINBUCKET;
+                    j < 1 << (MINBUCKET + 16);
+                    j <<= 1, i++)
+               {
                        if ((ks.ks_size & j) == 0)
                                continue;
                        if (first)
@@ -1180,6 +1183,7 @@ domem(void)
                        else
                                (void)printf(",%d", j);
                        first = 0;
+                       (void)printf(":%u", ks.ks_active[i]);
                }
                (void)printf("\n");
                totuse += ks.ks_memuse;


Home | Main Index | Thread Index | Old Index