From 80093b1fc86c422dcaaa59505d07a2f7ac1245d4 Mon Sep 17 00:00:00 2001 From: Antonio Huete Jimenez Date: Wed, 23 Nov 2011 01:20:00 +0100 Subject: [PATCH] kern - Add kern.memstats sysctl. This sysctl now lists all malloc types in a similar way like vmstat -m did. This is pretty much the only thing left so that we can drop vmstat's dependency on kvm(3) thus removing also the need of the suid bit. Some more changes were done: - In struct malloc_type, nuke some meaningless fields and reserved fields. Also make memory ks_calls and ks_maxused per-cpu so that they can be updated on the fly. - Remove "Limit" columns corresponding to fields ks_limblocks and ks_mapblocks, they were always zeroes, they weren't being tracked. - Fix HighUse column, previously ks_maxused was not being tracked either, so add the necessary code for it. - In totals, "Free" was always zero. It's not possible to show the Free size left (something like KvaSize - meminuse) because there are other users and it would not be accurate. Reviewed-by: vsrinivas --- sys/kern/kern_slaballoc.c | 70 ++++++++++++++++++++++++++++++++++++++++++++- sys/sys/malloc.h | 19 +++++------- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/sys/kern/kern_slaballoc.c b/sys/kern/kern_slaballoc.c index 747ecc3..77d1b27 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,74 @@ 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[256]; + size_t allocs; + size_t totuse; + int64_t totreq; + size_t meminuse; + size_t maxused; + size_t calls; + int error; + int cpu; + + totuse = 0; + totreq = 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) { + + /* Per-cpu values must be aggregated */ + meminuse = 0; + maxused = 0; + allocs = 0; + calls = 0; + for (cpu = allocs = meminuse = 0; cpu < ncpus; cpu++) { + allocs += cur->ks_inuse[cpu]; + meminuse += cur->ks_memuse[cpu]; + maxused += cur->ks_maxused[cpu]; + calls += cur->ks_calls[cpu]; + } + totuse += meminuse; + totreq += calls; + + ksnprintf(tmpbuf, sizeof(tmpbuf), "%19s %6zd %7zdK %9zdK %9zdK %9zd\n", + cur->ks_shortdesc, allocs, (meminuse + 1023) / 1024, + (maxused + 1023) / 1024, + (cur->ks_limit + 1023) / 1024, (intmax_t)calls); + + error = SYSCTL_OUT(req, tmpbuf, strlen(tmpbuf)); + if (error) + return (error); + + } + + ksnprintf(tmpbuf, sizeof(tmpbuf), "\nMemory Totals: In Use Requests\n" + " %7zdK %8jd\n", (totuse + 1023) / 1024, (intmax_t)totreq); + + 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 +608,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 @@ -846,6 +910,10 @@ kmalloc(unsigned long size, struct malloc_type *type, int flags) done: ++type->ks_inuse[gd->gd_cpuid]; type->ks_memuse[gd->gd_cpuid] += size; + + if (type->ks_memuse[gd->gd_cpuid] > type->ks_maxused[gd->gd_cpuid]) + type->ks_maxused[gd->gd_cpuid] = type->ks_memuse[gd->gd_cpuid]; + type->ks_loosememuse += size; /* not MP synchronized */ crit_exit(); diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index 4a4895c..091dc8c 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 */ + size_t ks_maxused[SMP_MAXCPU]; /* per-cpu 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 -- 1.7.6.3