diff --git a/sys/kern/kern_slaballoc.c b/sys/kern/kern_slaballoc.c index 747ecc3..5266938 100644 --- a/sys/kern/kern_slaballoc.c +++ b/sys/kern/kern_slaballoc.c @@ -160,6 +160,7 @@ static int32_t weirdary[16]; static void *kmem_slab_alloc(vm_size_t bytes, vm_offset_t align, int flags); static void kmem_slab_free(void *ptr, vm_size_t bytes); +static int sysctl_kern_memstats(SYSCTL_HANDLER_ARGS); #if defined(INVARIANTS) static void chunk_mark_allocated(SLZone *z, void *chunk); @@ -222,11 +223,55 @@ SYSCTL_INT(_debug, OID_AUTO, use_malloc_pattern, CTLFLAG_RW, "Initialize memory to -1 if M_ZERO not specified"); #endif +SYSCTL_OID(_kern, OID_AUTO, memstats, CTLTYPE_STRING|CTLFLAG_RD, \ + NULL, 0, sysctl_kern_memstats, "A", "Malloc types info"); + static int ZoneRelsThresh = ZONE_RELS_THRESH; SYSCTL_INT(_kern, OID_AUTO, zone_big_alloc, CTLFLAG_RD, &ZoneBigAlloc, 0, ""); SYSCTL_INT(_kern, OID_AUTO, zone_gen_alloc, CTLFLAG_RD, &ZoneGenAlloc, 0, ""); SYSCTL_INT(_kern, OID_AUTO, zone_cache, CTLFLAG_RW, &ZoneRelsThresh, 0, ""); +static int +sysctl_kern_memstats(SYSCTL_HANDLER_ARGS) +{ + struct malloc_type *cur; + char tmpbuf[128]; + size_t allocs; + size_t meminuse; + size_t calls; + int error; + int cpu; + + meminuse = 0; + allocs = 0; + calls = 0; + + ksnprintf(tmpbuf, sizeof(tmpbuf), + "\n Type InUse MemUse HighUse Limit Requests\n"); + error = SYSCTL_OUT(req, tmpbuf, strlen(tmpbuf)); + if (error) + return (error); + + for (cur = kmemstatistics; cur != NULL; cur = cur->ks_next) { + for (cpu = allocs = meminuse = 0; cpu < SMP_MAXCPU; cpu++) { + allocs += cur->ks_inuse[cpu]; + meminuse += cur->ks_memuse[cpu]; + calls += cur->ks_calls[cpu]; + } + + ksnprintf(tmpbuf, sizeof(tmpbuf), "%19s %6ld %7ldK %9ldK %9zdK %9jd\n", + cur->ks_shortdesc, allocs, (meminuse + 1023) / 1024, + (cur->ks_maxused + 1023) / 1024, + (cur->ks_limit + 1023) / 1024, (intmax_t)calls); + + error = SYSCTL_OUT(req, tmpbuf, strlen(tmpbuf)); + if (error) + return (error); + } + + return 0; +} + /* * Returns the kernel memory size limit for the purposes of initializing * various subsystem caches. The smaller of available memory and the KVM @@ -544,7 +589,7 @@ kmalloc(unsigned long size, struct malloc_type *type, int flags) malloc_init(type); crit_exit(); } - ++type->ks_calls; + ++type->ks_calls[gd->gd_cpuid]; /* * Handle the case where the limit is reached. Panic if we can't return diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index 4a4895c..46a8597 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -109,16 +109,13 @@ struct malloc_type { struct malloc_type *ks_next; /* next in list */ size_t ks_memuse[SMP_MAXCPU]; /* total memory held in bytes */ size_t ks_loosememuse; /* (inaccurate) aggregate memuse */ - size_t ks_limit; /* most that are allowed to exist */ - long ks_size; /* sizes of this thing that are allocated */ - size_t ks_inuse[SMP_MAXCPU]; /* # of allocs currently in use */ - __int64_t ks_calls; /* total packets of this type ever allocated */ - long ks_maxused; /* maximum number ever used */ - __uint32_t ks_magic; /* if it's not magic, don't touch it */ + size_t ks_limit; /* most that are allowed to exist */ + long ks_size; /* sizes of this thing that are allocated */ + size_t ks_inuse[SMP_MAXCPU]; /* # of allocs currently in use */ + __int64_t ks_calls[SMP_MAXCPU]; /* per-cpu total packets of this type ever allocated */ + long ks_maxused; /* maximum number ever used */ + __uint32_t ks_magic; /* if it's not magic, don't touch it */ const char *ks_shortdesc; /* short description */ - __uint16_t ks_limblocks; /* number of times blocked for hitting limit */ - __uint16_t ks_mapblocks; /* number of times blocked for kernel map */ - long ks_reserved[4]; /* future use (module compatibility) */ }; typedef struct malloc_type *malloc_type_t; @@ -127,7 +124,7 @@ typedef struct malloc_type *malloc_type_t; #define MALLOC_DEFINE(type, shortdesc, longdesc) \ struct malloc_type type[1] = { \ - { NULL, { 0 }, 0, 0, 0, { 0 }, 0, 0, M_MAGIC, shortdesc, 0, 0, { 0 } } \ + { NULL, { 0 }, 0, 0, 0, { 0 }, { 0 }, 0, M_MAGIC, shortdesc } \ }; \ SYSINIT(type##_init, SI_BOOT1_KMALLOC, SI_ORDER_ANY, malloc_init, type); \ SYSUNINIT(type##_uninit, SI_BOOT1_KMALLOC, SI_ORDER_ANY, malloc_uninit, type) @@ -136,7 +133,7 @@ typedef struct malloc_type *malloc_type_t; #define MALLOC_DEFINE(type, shortdesc, longdesc) \ struct malloc_type type[1] = { \ - { NULL, { 0 }, 0, 0, 0, { 0 }, 0, 0, M_MAGIC, shortdesc, 0, 0 } \ + { NULL, { 0 }, 0, 0, 0, { 0 }, { 0 }, 0, M_MAGIC, shortdesc } \ }; #endif diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index bae5d1d..c31ba60 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -780,77 +780,31 @@ dointr(void) #define MAX_KMSTATS 1024 -static long -cpuagg(size_t *ary) -{ - int i; - long ttl; - - for (i = ttl = 0; i < SMP_MAXCPU; ++i) - ttl += ary[i]; - return(ttl); -} - static void domem(void) { - struct malloc_type *ks; - int i, j; - int first, nkms; - long totuse = 0, totfree = 0, totreq = 0; - struct malloc_type kmemstats[MAX_KMSTATS], *kmsp; - char buf[1024]; - - kread(X_KMEMSTATISTICS, &kmsp, sizeof(kmsp)); - for (nkms = 0; nkms < MAX_KMSTATS && kmsp != NULL; nkms++) { - if (sizeof(kmemstats[0]) != kvm_read(kd, (u_long)kmsp, - &kmemstats[nkms], sizeof(kmemstats[0]))) - err(1, "kvm_read(%p)", (void *)kmsp); - if (sizeof(buf) != kvm_read(kd, - (u_long)kmemstats[nkms].ks_shortdesc, buf, sizeof(buf))) - err(1, "kvm_read(%p)", - kmemstats[nkms].ks_shortdesc); - buf[sizeof(buf) - 1] = '\0'; - kmemstats[nkms].ks_shortdesc = strdup(buf); - kmsp = kmemstats[nkms].ks_next; - } - if (kmsp != NULL) - warnx("truncated to the first %d memory types", nkms); + char *buf; + size_t bufsize; - printf( - "\nMemory statistics by type Type Kern\n"); - printf( -" Type InUse MemUse HighUse Limit Requests Limit Limit\n"); - for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) { - if (ks->ks_calls == 0) - continue; - printf("%19s%7ld%7ldK%7ldK%11zdK%10jd%5u%6u", - ks->ks_shortdesc, - cpuagg(ks->ks_inuse), (cpuagg(ks->ks_memuse) + 1023) / 1024, - (ks->ks_maxused + 1023) / 1024, - (ks->ks_limit + 1023) / 1024, (intmax_t)ks->ks_calls, - ks->ks_limblocks, ks->ks_mapblocks); - first = 1; - for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) { - if ((ks->ks_size & j) == 0) - continue; - if (first) - printf(" "); - else - printf(","); - if(j<1024) - printf("%d",j); - else - printf("%dK",j>>10); - first = 0; - } - printf("\n"); - totuse += cpuagg(ks->ks_memuse); - totreq += ks->ks_calls; + buf = NULL; + bufsize = 1024; + for (;;) { + if ((buf = realloc(buf, bufsize)) == NULL) + err(1, "realloc()"); + if (sysctlbyname("kern.memstats", buf, &bufsize, NULL, 0) == 0) + break; + if (errno != ENOMEM) + err(1, "sysctl()"); + bufsize *= 2; } - printf("\nMemory Totals: In Use Free Requests\n"); - printf(" %7ldK %6ldK %8ld\n", - (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); + buf[bufsize] = '\0'; /* play it safe */ + printf("%s\n\n", buf); + free(buf); + +// printf("\nMemory Totals: In Use Free Requests\n"); +// printf(" %7ldK %6ldK %8ld\n", +// +// (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); } static void