summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_malloc.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2005-07-14 11:52:06 +0000
committerrwatson <rwatson@FreeBSD.org>2005-07-14 11:52:06 +0000
commit7a35a61825dfa26f2d1c482870403373442d33d8 (patch)
tree6ed03904d67f30da9a9764ca831c20f01cf4821c /sys/kern/kern_malloc.c
parent0889b696347f30e85c820821cd9c5542eea4c71c (diff)
downloadFreeBSD-src-7a35a61825dfa26f2d1c482870403373442d33d8.zip
FreeBSD-src-7a35a61825dfa26f2d1c482870403373442d33d8.tar.gz
Introduce a new sysctl, kern.malloc_stats, which exports kernel malloc
statistics via a binary structure stream: - Add structure 'malloc_type_stream_header', which defines a stream version, definition of MAXCPUS used in the stream, and a number of malloc_type records in the stream. - Add structure 'malloc_type_header', which defines the name of the malloc type being reported on. - When the sysctl is queried, return a stream header, followed by a series of type descriptions, each consisting of a type header followed by a series of MAXCPUS malloc_type_stats structures holding per-CPU allocation information. Typical values of MAXCPUS will be 1 (UP compiled kernel) and 16 (SMP compiled kernel). This query mechanism allows user space monitoring tools to extract memory allocation statistics in a machine-readable form, and to do so at a per-CPU granularity, allowing monitoring of allocation patterns across CPUs in order to better understand the distribution of work and memory flow over multiple CPUs. While here: - Bump statistics width to uint64_t, and hard code using fixed-width type in order to be more sure about structure layout in the stream. We allocate and free a lot of memory. - Add kmemcount, a counter of the number of registered malloc types, in order to avoid excessive manual counting of types. Export via a new sysctl to allow user-space code to better size buffers. - De-XXX comment on no longer maintaining the high watermark in old sysctl monitoring code. A follow-up commit of libmemstat(3), a library to monitor kernel memory allocation, will occur in the next few days. Likewise, similar changes to UMA.
Diffstat (limited to 'sys/kern/kern_malloc.c')
-rw-r--r--sys/kern/kern_malloc.c98
1 files changed, 93 insertions, 5 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index 316feca..0b0b044 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -94,6 +94,7 @@ static MALLOC_DEFINE(M_FREE, "free", "should be on free list");
static struct malloc_type *kmemstatistics;
static char *kmembase;
static char *kmemlimit;
+static int kmemcount;
#define KMEM_ZSHIFT 4
#define KMEM_ZBASE 16
@@ -169,6 +170,7 @@ static int sysctl_kern_mprof(SYSCTL_HANDLER_ARGS);
#endif
static int sysctl_kern_malloc(SYSCTL_HANDLER_ARGS);
+static int sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS);
/* time_uptime of last malloc(9) failure */
static time_t t_malloc_fail;
@@ -593,6 +595,7 @@ malloc_init(void *data)
mtx_lock(&malloc_mtx);
mtp->ks_next = kmemstatistics;
kmemstatistics = mtp;
+ kmemcount++;
mtx_unlock(&malloc_mtx);
}
@@ -615,6 +618,7 @@ malloc_uninit(void *data)
}
} else
kmemstatistics = mtp->ks_next;
+ kmemcount--;
mtx_unlock(&malloc_mtx);
uma_zfree(mt_zone, mtip);
}
@@ -639,8 +643,7 @@ sysctl_kern_malloc(SYSCTL_HANDLER_ARGS)
/* Guess at how much room is needed. */
mtx_lock(&malloc_mtx);
- for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next)
- cnt++;
+ cnt = kmemcount;
mtx_unlock(&malloc_mtx);
bufsize = linesize * (cnt + 1);
@@ -686,10 +689,10 @@ sysctl_kern_malloc(SYSCTL_HANDLER_ARGS)
temp_bytes = 0;
/*
- * XXXRW: High-waterwark is no longer easily available, so
- * we just print '-' for that column.
+ * High-waterwark is no longer easily available, so we just
+ * print '-' for that column.
*/
- sbuf_printf(&sbuf, "%13s%6lu%6luK -%9lu",
+ sbuf_printf(&sbuf, "%13s%6lu%6luK -%9llu",
mtp->ks_shortdesc,
temp_allocs,
(temp_bytes + 1023) / 1024,
@@ -723,6 +726,91 @@ sysctl_kern_malloc(SYSCTL_HANDLER_ARGS)
SYSCTL_OID(_kern, OID_AUTO, malloc, CTLTYPE_STRING|CTLFLAG_RD,
NULL, 0, sysctl_kern_malloc, "A", "Malloc Stats");
+static int
+sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS)
+{
+ struct malloc_type_stream_header mtsh;
+ struct malloc_type_internal *mtip;
+ struct malloc_type_header mth;
+ struct malloc_type *mtp;
+ int buflen, count, error, i;
+ struct sbuf sbuf;
+ char *buffer;
+
+ mtx_lock(&malloc_mtx);
+restart:
+ mtx_assert(&malloc_mtx, MA_OWNED);
+ count = kmemcount;
+ mtx_unlock(&malloc_mtx);
+ buflen = sizeof(mtsh) + count * (sizeof(mth) +
+ sizeof(struct malloc_type_stats) * MAXCPU) + 1;
+ buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
+ mtx_lock(&malloc_mtx);
+ if (count < kmemcount) {
+ free(buffer, M_TEMP);
+ goto restart;
+ }
+
+ sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN);
+
+ /*
+ * Insert stream header.
+ */
+ bzero(&mtsh, sizeof(mtsh));
+ mtsh.mtsh_version = MALLOC_TYPE_STREAM_VERSION;
+ mtsh.mtsh_maxcpus = MAXCPU;
+ mtsh.mtsh_count = kmemcount;
+ if (sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)) < 0) {
+ mtx_unlock(&malloc_mtx);
+ error = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Insert alternating sequence of type headers and type statistics.
+ */
+ for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
+ mtip = (struct malloc_type_internal *)mtp->ks_handle;
+
+ /*
+ * Insert type header.
+ */
+ bzero(&mth, sizeof(mth));
+ strlcpy(mth.mth_name, mtp->ks_shortdesc, MALLOC_MAX_NAME);
+ if (sbuf_bcat(&sbuf, &mth, sizeof(mth)) < 0) {
+ mtx_unlock(&malloc_mtx);
+ error = ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Insert type statistics for each CPU.
+ */
+ for (i = 0; i < MAXCPU; i++) {
+ if (sbuf_bcat(&sbuf, &mtip->mti_stats[i],
+ sizeof(mtip->mti_stats[i])) < 0) {
+ mtx_unlock(&malloc_mtx);
+ error = ENOMEM;
+ goto out;
+ }
+ }
+ }
+ mtx_unlock(&malloc_mtx);
+ sbuf_finish(&sbuf);
+ error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf));
+out:
+ sbuf_delete(&sbuf);
+ free(buffer, M_TEMP);
+ return (error);
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, malloc_stats, CTLFLAG_RD|CTLTYPE_STRUCT,
+ 0, 0, sysctl_kern_malloc_stats, "s,malloc_type_ustats",
+ "Return malloc types");
+
+SYSCTL_INT(_kern, OID_AUTO, malloc_count, CTLFLAG_RD, &kmemcount, 0,
+ "Count of kernel malloc types");
+
#ifdef MALLOC_PROFILE
static int
OpenPOWER on IntegriCloud