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
