svn commit: r367274 - in head: lib/libmemstat share/man/man9 sys/kern usr.bin/vmstat
Mateusz Guzik
mjg at FreeBSD.org
Mon Nov 2 17:38:10 UTC 2020
Author: mjg
Date: Mon Nov 2 17:38:08 2020
New Revision: 367274
URL: https://svnweb.freebsd.org/changeset/base/367274
Log:
malloc: export kernel zones instead of relying on them being power-of-2
Reviewed by: markj (previous version)
Differential Revision: https://reviews.freebsd.org/D27026
Modified:
head/lib/libmemstat/memstat.h
head/lib/libmemstat/memstat_malloc.c
head/share/man/man9/malloc.9
head/sys/kern/kern_malloc.c
head/usr.bin/vmstat/vmstat.c
Modified: head/lib/libmemstat/memstat.h
==============================================================================
--- head/lib/libmemstat/memstat.h Mon Nov 2 15:01:37 2020 (r367273)
+++ head/lib/libmemstat/memstat.h Mon Nov 2 17:38:08 2020 (r367274)
@@ -118,6 +118,13 @@ int memstat_kvm_malloc(struct memory_type_list *list,
int memstat_kvm_uma(struct memory_type_list *list, void *kvm_handle);
/*
+ * General malloc routines.
+ */
+size_t memstat_malloc_zone_get_count(void);
+size_t memstat_malloc_zone_get_size(size_t n);
+int memstat_malloc_zone_used(const struct memory_type *mtp, size_t n);
+
+/*
* Accessor methods for struct memory_type.
*/
const char *memstat_get_name(const struct memory_type *mtp);
Modified: head/lib/libmemstat/memstat_malloc.c
==============================================================================
--- head/lib/libmemstat/memstat_malloc.c Mon Nov 2 15:01:37 2020 (r367273)
+++ head/lib/libmemstat/memstat_malloc.c Mon Nov 2 17:38:08 2020 (r367274)
@@ -44,10 +44,22 @@
#include "memstat.h"
#include "memstat_internal.h"
+static int memstat_malloc_zone_count;
+static int memstat_malloc_zone_sizes[32];
+
+static int memstat_malloc_zone_init(void);
+static int memstat_malloc_zone_init_kvm(kvm_t *kvm);
+
static struct nlist namelist[] = {
#define X_KMEMSTATISTICS 0
{ .n_name = "_kmemstatistics" },
-#define X_MP_MAXCPUS 1
+#define X_KMEMZONES 1
+ { .n_name = "_kmemzones" },
+#define X_NUMZONES 2
+ { .n_name = "_numzones" },
+#define X_VM_MALLOC_ZONE_COUNT 3
+ { .n_name = "_vm_malloc_zone_count" },
+#define X_MP_MAXCPUS 4
{ .n_name = "_mp_maxcpus" },
{ .n_name = "" },
};
@@ -111,6 +123,11 @@ retry:
return (-1);
}
+ if (memstat_malloc_zone_init() == -1) {
+ list->mtl_error = MEMSTAT_ERROR_VERSION;
+ return (-1);
+ }
+
size = sizeof(*mthp) + count * (sizeof(*mthp) + sizeof(*mtsp) *
maxcpus);
@@ -333,6 +350,12 @@ memstat_kvm_malloc(struct memory_type_list *list, void
return (-1);
}
+ ret = memstat_malloc_zone_init_kvm(kvm);
+ if (ret != 0) {
+ list->mtl_error = ret;
+ return (-1);
+ }
+
mp_ncpus = kvm_getncpus(kvm);
for (typep = kmemstatistics; typep != NULL; typep = type.ks_next) {
@@ -413,6 +436,112 @@ memstat_kvm_malloc(struct memory_type_list *list, void
mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
}
+
+ return (0);
+}
+
+static int
+memstat_malloc_zone_init(void)
+{
+ size_t size;
+
+ size = sizeof(memstat_malloc_zone_count);
+ if (sysctlbyname("vm.malloc.zone_count", &memstat_malloc_zone_count,
+ &size, NULL, 0) < 0) {
+ return (-1);
+ }
+
+ if (memstat_malloc_zone_count > (int)nitems(memstat_malloc_zone_sizes)) {
+ return (-1);
+ }
+
+ size = sizeof(memstat_malloc_zone_sizes);
+ if (sysctlbyname("vm.malloc.zone_sizes", &memstat_malloc_zone_sizes,
+ &size, NULL, 0) < 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Copied from kern_malloc.c
+ *
+ * kz_zone is an array sized at compilation time, the size is exported in
+ * "numzones". Below we need to iterate kz_size.
+ */
+struct memstat_kmemzone {
+ int kz_size;
+ const char *kz_name;
+ void *kz_zone[1];
+};
+
+static int
+memstat_malloc_zone_init_kvm(kvm_t *kvm)
+{
+ struct memstat_kmemzone *kmemzones, *kz;
+ int numzones, objsize, allocsize, ret;
+ int i;
+
+ ret = kread_symbol(kvm, X_VM_MALLOC_ZONE_COUNT,
+ &memstat_malloc_zone_count, sizeof(memstat_malloc_zone_count), 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ ret = kread_symbol(kvm, X_NUMZONES, &numzones, sizeof(numzones), 0);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ objsize = __offsetof(struct memstat_kmemzone, kz_zone) +
+ sizeof(void *) * numzones;
+
+ allocsize = objsize * memstat_malloc_zone_count;
+ kmemzones = malloc(allocsize);
+ if (kmemzones == NULL) {
+ return (MEMSTAT_ERROR_NOMEMORY);
+ }
+ ret = kread_symbol(kvm, X_KMEMZONES, kmemzones, allocsize, 0);
+ if (ret != 0) {
+ free(kmemzones);
+ return (ret);
+ }
+
+ kz = kmemzones;
+ for (i = 0; i < (int)nitems(memstat_malloc_zone_sizes); i++) {
+ memstat_malloc_zone_sizes[i] = kz->kz_size;
+ kz = (struct memstat_kmemzone *)((char *)kz + objsize);
+ }
+
+ free(kmemzones);
+ return (0);
+}
+
+size_t
+memstat_malloc_zone_get_count(void)
+{
+
+ return (memstat_malloc_zone_count);
+}
+
+size_t
+memstat_malloc_zone_get_size(size_t n)
+{
+
+ if (n >= nitems(memstat_malloc_zone_sizes)) {
+ return (-1);
+ }
+
+ return (memstat_malloc_zone_sizes[n]);
+}
+
+int
+memstat_malloc_zone_used(const struct memory_type *mtp, size_t n)
+{
+
+ if (memstat_get_sizemask(mtp) & (1 << n))
+ return (1);
return (0);
}
Modified: head/share/man/man9/malloc.9
==============================================================================
--- head/share/man/man9/malloc.9 Mon Nov 2 15:01:37 2020 (r367273)
+++ head/share/man/man9/malloc.9 Mon Nov 2 17:38:08 2020 (r367274)
@@ -29,7 +29,7 @@
.\" $NetBSD: malloc.9,v 1.3 1996/11/11 00:05:11 lukem Exp $
.\" $FreeBSD$
.\"
-.Dd August 28, 2020
+.Dd October 30, 2020
.Dt MALLOC 9
.Os
.Sh NAME
@@ -57,6 +57,8 @@
.Fn reallocf "void *addr" "size_t size" "struct malloc_type *type" "int flags"
.Ft size_t
.Fn malloc_usable_size "const void *addr"
+.Ft void *
+.Fn malloc_exec "size_t size" "struct malloc_type *type" "int flags"
.Fn MALLOC_DECLARE type
.In sys/param.h
.In sys/malloc.h
@@ -66,6 +68,8 @@
.In sys/domainset.h
.Ft void *
.Fn malloc_domainset "size_t size" "struct malloc_type *type" "struct domainset *ds" "int flags"
+.Ft void *
+.Fn malloc_domainset_exec "size_t size" "struct malloc_type *type" "struct domainset *ds" "int flags"
.Sh DESCRIPTION
The
.Fn malloc
@@ -82,6 +86,13 @@ See
.Xr domainset 9
for some example policies.
.Pp
+Both
+.Fn malloc_exec
+and
+.Fn malloc_domainset_exec
+can be used to return executable memory.
+Not all platforms enforce a distinction between executable and non-executable memory.
+.Pp
The
.Fn mallocarray
function allocates uninitialized memory in kernel address space for an
@@ -214,11 +225,6 @@ This option should only be used in combination with
.Dv M_NOWAIT
when an allocation failure cannot be tolerated by the caller without
catastrophic effects on the system.
-.It Dv M_EXEC
-Indicates that the system should allocate executable memory.
-If this flag is not set, the system will not allocate executable memory.
-Not all platforms enforce a distinction between executable and
-non-executable memory.
.El
.Pp
Exactly one of either
Modified: head/sys/kern/kern_malloc.c
==============================================================================
--- head/sys/kern/kern_malloc.c Mon Nov 2 15:01:37 2020 (r367273)
+++ head/sys/kern/kern_malloc.c Mon Nov 2 17:38:08 2020 (r367274)
@@ -147,6 +147,8 @@ static int numzones = MALLOC_DEBUG_MAXZONES;
* Small malloc(9) memory allocations are allocated from a set of UMA buckets
* of various sizes.
*
+ * Warning: the layout of the struct is duplicated in libmemstat for KVM support.
+ *
* XXX: The comment here used to read "These won't be powers of two for
* long." It's possible that a significant amount of wasted memory could be
* recovered by tuning the sizes of these buckets.
@@ -213,6 +215,19 @@ SYSCTL_PROC(_vm, OID_AUTO, kmem_map_free,
CTLFLAG_RD | CTLTYPE_ULONG | CTLFLAG_MPSAFE, NULL, 0,
sysctl_kmem_map_free, "LU", "Free space in kmem");
+static SYSCTL_NODE(_vm, OID_AUTO, malloc, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "Malloc information");
+
+static u_int vm_malloc_zone_count = nitems(kmemzones);
+SYSCTL_UINT(_vm_malloc, OID_AUTO, zone_count,
+ CTLFLAG_RD, &vm_malloc_zone_count, 0,
+ "Number of malloc zones");
+
+static int sysctl_vm_malloc_zone_sizes(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_vm_malloc, OID_AUTO, zone_sizes,
+ CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, NULL, 0,
+ sysctl_vm_malloc_zone_sizes, "S", "Zone sizes used by malloc");
+
/*
* The malloc_mtx protects the kmemstatistics linked list.
*/
@@ -272,6 +287,19 @@ sysctl_kmem_map_free(SYSCTL_HANDLER_ARGS)
else
size = limit - size;
return (sysctl_handle_long(oidp, &size, 0, req));
+}
+
+static int
+sysctl_vm_malloc_zone_sizes(SYSCTL_HANDLER_ARGS)
+{
+ int sizes[nitems(kmemzones)];
+ int i;
+
+ for (i = 0; i < nitems(kmemzones); i++) {
+ sizes[i] = kmemzones[i].kz_size;
+ }
+
+ return (SYSCTL_OUT(req, &sizes, sizeof(sizes)));
}
/*
Modified: head/usr.bin/vmstat/vmstat.c
==============================================================================
--- head/usr.bin/vmstat/vmstat.c Mon Nov 2 15:01:37 2020 (r367273)
+++ head/usr.bin/vmstat/vmstat.c Mon Nov 2 17:38:08 2020 (r367274)
@@ -1407,7 +1407,8 @@ domemstat_malloc(void)
{
struct memory_type_list *mtlp;
struct memory_type *mtp;
- int error, first, i;
+ size_t i, zones;
+ int error, first;
mtlp = memstat_mtl_alloc();
if (mtlp == NULL) {
@@ -1435,6 +1436,7 @@ domemstat_malloc(void)
xo_emit("{T:/%13s} {T:/%5s} {T:/%6s} {T:/%7s} {T:/%8s} {T:Size(s)}\n",
"Type", "InUse", "MemUse", "HighUse", "Requests");
xo_open_list("memory");
+ zones = memstat_malloc_zone_get_count();
for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
mtp = memstat_mtl_next(mtp)) {
if (memstat_get_numallocs(mtp) == 0 &&
@@ -1449,11 +1451,11 @@ domemstat_malloc(void)
(uintmax_t)memstat_get_numallocs(mtp));
first = 1;
xo_open_list("size");
- for (i = 0; i < 32; i++) {
- if (memstat_get_sizemask(mtp) & (1 << i)) {
+ for (i = 0; i < zones; i++) {
+ if (memstat_malloc_zone_used(mtp, i)) {
if (!first)
xo_emit(",");
- xo_emit("{l:size/%d}", 1 << (i + 4));
+ xo_emit("{l:size/%d}", memstat_malloc_zone_get_size(i));
first = 0;
}
}
More information about the svn-src-all
mailing list