summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2005-07-14 11:52:06 +0000
committerRobert Watson <rwatson@FreeBSD.org>2005-07-14 11:52:06 +0000
commitcd814b269240f3a2e13d89b95e482f23d69519df (patch)
tree6ed03904d67f30da9a9764ca831c20f01cf4821c
parent49bb6870cc71b5c0726b765bcb196b6ebed74156 (diff)
Notes
-rw-r--r--sys/kern/kern_malloc.c98
-rw-r--r--sys/sys/malloc.h36
2 files changed, 121 insertions, 13 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index 316fecac05bc..0b0b04416684 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
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index eab2cf2d2114..ef0aa17dfa6d 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -70,14 +70,14 @@
* monitoring app should take into account.
*/
struct malloc_type_stats {
- u_long mts_memalloced; /* Bytes allocated on CPU. */
- u_long mts_memfreed; /* Bytes freed on CPU. */
- u_long mts_numallocs; /* Number of allocates on CPU. */
- u_long mts_numfrees; /* number of frees on CPU. */
- u_long mts_size; /* Bitmask of sizes allocated on CPU. */
- u_long _mts_reserved1; /* Reserved field. */
- u_long _mts_reserved2; /* Reserved field. */
- u_long _mts_reserved3; /* Reserved field. */
+ uint64_t mts_memalloced; /* Bytes allocated on CPU. */
+ uint64_t mts_memfreed; /* Bytes freed on CPU. */
+ uint64_t mts_numallocs; /* Number of allocates on CPU. */
+ uint64_t mts_numfrees; /* number of frees on CPU. */
+ uint64_t mts_size; /* Bitmask of sizes allocated on CPU. */
+ uint64_t _mts_reserved1; /* Reserved field. */
+ uint64_t _mts_reserved2; /* Reserved field. */
+ uint64_t _mts_reserved3; /* Reserved field. */
};
struct malloc_type_internal {
@@ -116,6 +116,26 @@ struct malloc_type {
u_int _mtx_recurse;
};
+/*
+ * Statistics structure headers for user space. The kern.malloc sysctl
+ * exposes a structure stream consisting of a stream header, then a series of
+ * malloc type headers and statistics structures (quantity maxcpus). For
+ * convenience, the kernel will provide the current value of maxcpus at the
+ * head of the stream.
+ */
+#define MALLOC_TYPE_STREAM_VERSION 0x00000001
+struct malloc_type_stream_header {
+ uint32_t mtsh_version; /* Stream format version. */
+ uint32_t mtsh_maxcpus; /* Value of MAXCPU for stream. */
+ uint32_t mtsh_count; /* Number of records. */
+ uint32_t _mtsh_pad; /* Pad/reserved field. */
+};
+
+#define MALLOC_MAX_NAME 32
+struct malloc_type_header {
+ char mth_name[MALLOC_MAX_NAME];
+};
+
#ifdef _KERNEL
#define MALLOC_DEFINE(type, shortdesc, longdesc) \
struct malloc_type type[1] = { \