11eaf0ac3Slogwang /*-
222ce4affSfengbojiang * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
322ce4affSfengbojiang *
41eaf0ac3Slogwang * Copyright (c) 2005 Robert N. M. Watson
51eaf0ac3Slogwang * All rights reserved.
61eaf0ac3Slogwang *
71eaf0ac3Slogwang * Redistribution and use in source and binary forms, with or without
81eaf0ac3Slogwang * modification, are permitted provided that the following conditions
91eaf0ac3Slogwang * are met:
101eaf0ac3Slogwang * 1. Redistributions of source code must retain the above copyright
111eaf0ac3Slogwang * notice, this list of conditions and the following disclaimer.
121eaf0ac3Slogwang * 2. Redistributions in binary form must reproduce the above copyright
131eaf0ac3Slogwang * notice, this list of conditions and the following disclaimer in the
141eaf0ac3Slogwang * documentation and/or other materials provided with the distribution.
151eaf0ac3Slogwang *
161eaf0ac3Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171eaf0ac3Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181eaf0ac3Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191eaf0ac3Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201eaf0ac3Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211eaf0ac3Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221eaf0ac3Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231eaf0ac3Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241eaf0ac3Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251eaf0ac3Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261eaf0ac3Slogwang * SUCH DAMAGE.
271eaf0ac3Slogwang *
281eaf0ac3Slogwang * $FreeBSD$
291eaf0ac3Slogwang */
301eaf0ac3Slogwang
31*d4a07e70Sfengbojiang #ifdef FSTACK
32*d4a07e70Sfengbojiang #include <stdint.h>
33*d4a07e70Sfengbojiang #endif
34*d4a07e70Sfengbojiang
351eaf0ac3Slogwang #include <sys/cdefs.h>
361eaf0ac3Slogwang #include <sys/param.h>
371eaf0ac3Slogwang #include <sys/malloc.h>
381eaf0ac3Slogwang #include <sys/sysctl.h>
391eaf0ac3Slogwang
401eaf0ac3Slogwang #include <err.h>
411eaf0ac3Slogwang #include <errno.h>
42*d4a07e70Sfengbojiang #ifndef FSTACK
431eaf0ac3Slogwang #include <kvm.h>
44*d4a07e70Sfengbojiang #endif
451eaf0ac3Slogwang #include <nlist.h>
461eaf0ac3Slogwang #include <stdio.h>
471eaf0ac3Slogwang #include <stdlib.h>
481eaf0ac3Slogwang #include <string.h>
491eaf0ac3Slogwang
501eaf0ac3Slogwang #include "memstat.h"
511eaf0ac3Slogwang #include "memstat_internal.h"
521eaf0ac3Slogwang
53*d4a07e70Sfengbojiang #ifndef FSTACK
5422ce4affSfengbojiang static int memstat_malloc_zone_count;
5522ce4affSfengbojiang static int memstat_malloc_zone_sizes[32];
5622ce4affSfengbojiang
5722ce4affSfengbojiang static int memstat_malloc_zone_init(void);
5822ce4affSfengbojiang static int memstat_malloc_zone_init_kvm(kvm_t *kvm);
5922ce4affSfengbojiang
601eaf0ac3Slogwang static struct nlist namelist[] = {
611eaf0ac3Slogwang #define X_KMEMSTATISTICS 0
621eaf0ac3Slogwang { .n_name = "_kmemstatistics" },
6322ce4affSfengbojiang #define X_KMEMZONES 1
6422ce4affSfengbojiang { .n_name = "_kmemzones" },
6522ce4affSfengbojiang #define X_NUMZONES 2
6622ce4affSfengbojiang { .n_name = "_numzones" },
6722ce4affSfengbojiang #define X_VM_MALLOC_ZONE_COUNT 3
6822ce4affSfengbojiang { .n_name = "_vm_malloc_zone_count" },
6922ce4affSfengbojiang #define X_MP_MAXCPUS 4
701eaf0ac3Slogwang { .n_name = "_mp_maxcpus" },
711eaf0ac3Slogwang { .n_name = "" },
721eaf0ac3Slogwang };
73*d4a07e70Sfengbojiang #endif
741eaf0ac3Slogwang
751eaf0ac3Slogwang /*
761eaf0ac3Slogwang * Extract malloc(9) statistics from the running kernel, and store all memory
771eaf0ac3Slogwang * type information in the passed list. For each type, check the list for an
781eaf0ac3Slogwang * existing entry with the right name/allocator -- if present, update that
791eaf0ac3Slogwang * entry. Otherwise, add a new entry. On error, the entire list will be
801eaf0ac3Slogwang * cleared, as entries will be in an inconsistent state.
811eaf0ac3Slogwang *
821eaf0ac3Slogwang * To reduce the level of work for a list that starts empty, we keep around a
831eaf0ac3Slogwang * hint as to whether it was empty when we began, so we can avoid searching
841eaf0ac3Slogwang * the list for entries to update. Updates are O(n^2) due to searching for
851eaf0ac3Slogwang * each entry before adding it.
861eaf0ac3Slogwang */
871eaf0ac3Slogwang int
memstat_sysctl_malloc(struct memory_type_list * list,int flags)881eaf0ac3Slogwang memstat_sysctl_malloc(struct memory_type_list *list, int flags)
891eaf0ac3Slogwang {
901eaf0ac3Slogwang struct malloc_type_stream_header *mtshp;
911eaf0ac3Slogwang struct malloc_type_header *mthp;
921eaf0ac3Slogwang struct malloc_type_stats *mtsp;
931eaf0ac3Slogwang struct memory_type *mtp;
941eaf0ac3Slogwang int count, hint_dontsearch, i, j, maxcpus;
951eaf0ac3Slogwang char *buffer, *p;
961eaf0ac3Slogwang size_t size;
971eaf0ac3Slogwang
981eaf0ac3Slogwang hint_dontsearch = LIST_EMPTY(&list->mtl_list);
991eaf0ac3Slogwang
1001eaf0ac3Slogwang /*
1011eaf0ac3Slogwang * Query the number of CPUs, number of malloc types so that we can
1021eaf0ac3Slogwang * guess an initial buffer size. We loop until we succeed or really
1031eaf0ac3Slogwang * fail. Note that the value of maxcpus we query using sysctl is not
1041eaf0ac3Slogwang * the version we use when processing the real data -- that is read
1051eaf0ac3Slogwang * from the header.
1061eaf0ac3Slogwang */
1071eaf0ac3Slogwang retry:
1081eaf0ac3Slogwang size = sizeof(maxcpus);
1091eaf0ac3Slogwang if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
1101eaf0ac3Slogwang if (errno == EACCES || errno == EPERM)
1111eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_PERMISSION;
1121eaf0ac3Slogwang else
1131eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_DATAERROR;
1141eaf0ac3Slogwang return (-1);
1151eaf0ac3Slogwang }
1161eaf0ac3Slogwang if (size != sizeof(maxcpus)) {
1171eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_DATAERROR;
1181eaf0ac3Slogwang return (-1);
1191eaf0ac3Slogwang }
1201eaf0ac3Slogwang
1211eaf0ac3Slogwang size = sizeof(count);
1221eaf0ac3Slogwang if (sysctlbyname("kern.malloc_count", &count, &size, NULL, 0) < 0) {
1231eaf0ac3Slogwang if (errno == EACCES || errno == EPERM)
1241eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_PERMISSION;
1251eaf0ac3Slogwang else
1261eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1271eaf0ac3Slogwang return (-1);
1281eaf0ac3Slogwang }
1291eaf0ac3Slogwang if (size != sizeof(count)) {
1301eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_DATAERROR;
1311eaf0ac3Slogwang return (-1);
1321eaf0ac3Slogwang }
1331eaf0ac3Slogwang
134*d4a07e70Sfengbojiang #ifndef FSTACK
13522ce4affSfengbojiang if (memstat_malloc_zone_init() == -1) {
13622ce4affSfengbojiang list->mtl_error = MEMSTAT_ERROR_VERSION;
13722ce4affSfengbojiang return (-1);
13822ce4affSfengbojiang }
139*d4a07e70Sfengbojiang #endif
14022ce4affSfengbojiang
1411eaf0ac3Slogwang size = sizeof(*mthp) + count * (sizeof(*mthp) + sizeof(*mtsp) *
1421eaf0ac3Slogwang maxcpus);
1431eaf0ac3Slogwang
1441eaf0ac3Slogwang buffer = malloc(size);
1451eaf0ac3Slogwang if (buffer == NULL) {
1461eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
1471eaf0ac3Slogwang return (-1);
1481eaf0ac3Slogwang }
1491eaf0ac3Slogwang
1501eaf0ac3Slogwang if (sysctlbyname("kern.malloc_stats", buffer, &size, NULL, 0) < 0) {
1511eaf0ac3Slogwang /*
1521eaf0ac3Slogwang * XXXRW: ENOMEM is an ambiguous return, we should bound the
1531eaf0ac3Slogwang * number of loops, perhaps.
1541eaf0ac3Slogwang */
1551eaf0ac3Slogwang if (errno == ENOMEM) {
1561eaf0ac3Slogwang free(buffer);
1571eaf0ac3Slogwang goto retry;
1581eaf0ac3Slogwang }
1591eaf0ac3Slogwang if (errno == EACCES || errno == EPERM)
1601eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_PERMISSION;
1611eaf0ac3Slogwang else
1621eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1631eaf0ac3Slogwang free(buffer);
1641eaf0ac3Slogwang return (-1);
1651eaf0ac3Slogwang }
1661eaf0ac3Slogwang
1671eaf0ac3Slogwang if (size == 0) {
1681eaf0ac3Slogwang free(buffer);
1691eaf0ac3Slogwang return (0);
1701eaf0ac3Slogwang }
1711eaf0ac3Slogwang
1721eaf0ac3Slogwang if (size < sizeof(*mtshp)) {
1731eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1741eaf0ac3Slogwang free(buffer);
1751eaf0ac3Slogwang return (-1);
1761eaf0ac3Slogwang }
1771eaf0ac3Slogwang p = buffer;
1781eaf0ac3Slogwang mtshp = (struct malloc_type_stream_header *)p;
1791eaf0ac3Slogwang p += sizeof(*mtshp);
1801eaf0ac3Slogwang
1811eaf0ac3Slogwang if (mtshp->mtsh_version != MALLOC_TYPE_STREAM_VERSION) {
1821eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1831eaf0ac3Slogwang free(buffer);
1841eaf0ac3Slogwang return (-1);
1851eaf0ac3Slogwang }
1861eaf0ac3Slogwang
1871eaf0ac3Slogwang /*
1881eaf0ac3Slogwang * For the remainder of this function, we are quite trusting about
1891eaf0ac3Slogwang * the layout of structures and sizes, since we've determined we have
1901eaf0ac3Slogwang * a matching version and acceptable CPU count.
1911eaf0ac3Slogwang */
1921eaf0ac3Slogwang maxcpus = mtshp->mtsh_maxcpus;
1931eaf0ac3Slogwang count = mtshp->mtsh_count;
1941eaf0ac3Slogwang for (i = 0; i < count; i++) {
1951eaf0ac3Slogwang mthp = (struct malloc_type_header *)p;
1961eaf0ac3Slogwang p += sizeof(*mthp);
1971eaf0ac3Slogwang
1981eaf0ac3Slogwang if (hint_dontsearch == 0) {
1991eaf0ac3Slogwang mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC,
2001eaf0ac3Slogwang mthp->mth_name);
2011eaf0ac3Slogwang } else
2021eaf0ac3Slogwang mtp = NULL;
2031eaf0ac3Slogwang if (mtp == NULL)
2041eaf0ac3Slogwang mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC,
2051eaf0ac3Slogwang mthp->mth_name, maxcpus);
2061eaf0ac3Slogwang if (mtp == NULL) {
2071eaf0ac3Slogwang _memstat_mtl_empty(list);
2081eaf0ac3Slogwang free(buffer);
2091eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
2101eaf0ac3Slogwang return (-1);
2111eaf0ac3Slogwang }
2121eaf0ac3Slogwang
2131eaf0ac3Slogwang /*
2141eaf0ac3Slogwang * Reset the statistics on a current node.
2151eaf0ac3Slogwang */
2161eaf0ac3Slogwang _memstat_mt_reset_stats(mtp, maxcpus);
2171eaf0ac3Slogwang
2181eaf0ac3Slogwang for (j = 0; j < maxcpus; j++) {
2191eaf0ac3Slogwang mtsp = (struct malloc_type_stats *)p;
2201eaf0ac3Slogwang p += sizeof(*mtsp);
2211eaf0ac3Slogwang
2221eaf0ac3Slogwang /*
2231eaf0ac3Slogwang * Sumarize raw statistics across CPUs into coalesced
2241eaf0ac3Slogwang * statistics.
2251eaf0ac3Slogwang */
2261eaf0ac3Slogwang mtp->mt_memalloced += mtsp->mts_memalloced;
2271eaf0ac3Slogwang mtp->mt_memfreed += mtsp->mts_memfreed;
2281eaf0ac3Slogwang mtp->mt_numallocs += mtsp->mts_numallocs;
2291eaf0ac3Slogwang mtp->mt_numfrees += mtsp->mts_numfrees;
2301eaf0ac3Slogwang mtp->mt_sizemask |= mtsp->mts_size;
2311eaf0ac3Slogwang
2321eaf0ac3Slogwang /*
2331eaf0ac3Slogwang * Copies of per-CPU statistics.
2341eaf0ac3Slogwang */
2351eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_memalloced =
2361eaf0ac3Slogwang mtsp->mts_memalloced;
2371eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_memfreed =
2381eaf0ac3Slogwang mtsp->mts_memfreed;
2391eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_numallocs =
2401eaf0ac3Slogwang mtsp->mts_numallocs;
2411eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_numfrees =
2421eaf0ac3Slogwang mtsp->mts_numfrees;
2431eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_sizemask =
2441eaf0ac3Slogwang mtsp->mts_size;
2451eaf0ac3Slogwang }
2461eaf0ac3Slogwang
2471eaf0ac3Slogwang /*
2481eaf0ac3Slogwang * Derived cross-CPU statistics.
2491eaf0ac3Slogwang */
2501eaf0ac3Slogwang mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
2511eaf0ac3Slogwang mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
2521eaf0ac3Slogwang }
2531eaf0ac3Slogwang
2541eaf0ac3Slogwang free(buffer);
2551eaf0ac3Slogwang
2561eaf0ac3Slogwang return (0);
2571eaf0ac3Slogwang }
2581eaf0ac3Slogwang
259*d4a07e70Sfengbojiang #ifndef FSTACK
2601eaf0ac3Slogwang static int
kread(kvm_t * kvm,void * kvm_pointer,void * address,size_t size,size_t offset)2611eaf0ac3Slogwang kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size,
2621eaf0ac3Slogwang size_t offset)
2631eaf0ac3Slogwang {
2641eaf0ac3Slogwang ssize_t ret;
2651eaf0ac3Slogwang
2661eaf0ac3Slogwang ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address,
2671eaf0ac3Slogwang size);
2681eaf0ac3Slogwang if (ret < 0)
2691eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM);
2701eaf0ac3Slogwang if ((size_t)ret != size)
2711eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM_SHORTREAD);
2721eaf0ac3Slogwang return (0);
2731eaf0ac3Slogwang }
2741eaf0ac3Slogwang
2751eaf0ac3Slogwang static int
kread_string(kvm_t * kvm,const void * kvm_pointer,char * buffer,int buflen)2761eaf0ac3Slogwang kread_string(kvm_t *kvm, const void *kvm_pointer, char *buffer, int buflen)
2771eaf0ac3Slogwang {
2781eaf0ac3Slogwang ssize_t ret;
2791eaf0ac3Slogwang int i;
2801eaf0ac3Slogwang
2811eaf0ac3Slogwang for (i = 0; i < buflen; i++) {
2821eaf0ac3Slogwang ret = kvm_read(kvm, __DECONST(unsigned long, kvm_pointer) +
2831eaf0ac3Slogwang i, &(buffer[i]), sizeof(char));
2841eaf0ac3Slogwang if (ret < 0)
2851eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM);
2861eaf0ac3Slogwang if ((size_t)ret != sizeof(char))
2871eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM_SHORTREAD);
2881eaf0ac3Slogwang if (buffer[i] == '\0')
2891eaf0ac3Slogwang return (0);
2901eaf0ac3Slogwang }
2911eaf0ac3Slogwang /* Truncate. */
2921eaf0ac3Slogwang buffer[i-1] = '\0';
2931eaf0ac3Slogwang return (0);
2941eaf0ac3Slogwang }
2951eaf0ac3Slogwang
2961eaf0ac3Slogwang static int
kread_symbol(kvm_t * kvm,int index,void * address,size_t size,size_t offset)2971eaf0ac3Slogwang kread_symbol(kvm_t *kvm, int index, void *address, size_t size,
2981eaf0ac3Slogwang size_t offset)
2991eaf0ac3Slogwang {
3001eaf0ac3Slogwang ssize_t ret;
3011eaf0ac3Slogwang
3021eaf0ac3Slogwang ret = kvm_read(kvm, namelist[index].n_value + offset, address, size);
3031eaf0ac3Slogwang if (ret < 0)
3041eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM);
3051eaf0ac3Slogwang if ((size_t)ret != size)
3061eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM_SHORTREAD);
3071eaf0ac3Slogwang return (0);
3081eaf0ac3Slogwang }
3091eaf0ac3Slogwang
31022ce4affSfengbojiang static int
kread_zpcpu(kvm_t * kvm,u_long base,void * buf,size_t size,int cpu)31122ce4affSfengbojiang kread_zpcpu(kvm_t *kvm, u_long base, void *buf, size_t size, int cpu)
31222ce4affSfengbojiang {
31322ce4affSfengbojiang ssize_t ret;
31422ce4affSfengbojiang
31522ce4affSfengbojiang ret = kvm_read_zpcpu(kvm, base, buf, size, cpu);
31622ce4affSfengbojiang if (ret < 0)
31722ce4affSfengbojiang return (MEMSTAT_ERROR_KVM);
31822ce4affSfengbojiang if ((size_t)ret != size)
31922ce4affSfengbojiang return (MEMSTAT_ERROR_KVM_SHORTREAD);
32022ce4affSfengbojiang return (0);
32122ce4affSfengbojiang }
32222ce4affSfengbojiang
3231eaf0ac3Slogwang int
memstat_kvm_malloc(struct memory_type_list * list,void * kvm_handle)3241eaf0ac3Slogwang memstat_kvm_malloc(struct memory_type_list *list, void *kvm_handle)
3251eaf0ac3Slogwang {
3261eaf0ac3Slogwang struct memory_type *mtp;
3271eaf0ac3Slogwang void *kmemstatistics;
32822ce4affSfengbojiang int hint_dontsearch, j, mp_maxcpus, mp_ncpus, ret;
3291eaf0ac3Slogwang char name[MEMTYPE_MAXNAME];
33022ce4affSfengbojiang struct malloc_type_stats mts;
3311eaf0ac3Slogwang struct malloc_type_internal *mtip;
3321eaf0ac3Slogwang struct malloc_type type, *typep;
3331eaf0ac3Slogwang kvm_t *kvm;
3341eaf0ac3Slogwang
3351eaf0ac3Slogwang kvm = (kvm_t *)kvm_handle;
3361eaf0ac3Slogwang
3371eaf0ac3Slogwang hint_dontsearch = LIST_EMPTY(&list->mtl_list);
3381eaf0ac3Slogwang
3391eaf0ac3Slogwang if (kvm_nlist(kvm, namelist) != 0) {
3401eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_KVM;
3411eaf0ac3Slogwang return (-1);
3421eaf0ac3Slogwang }
3431eaf0ac3Slogwang
3441eaf0ac3Slogwang if (namelist[X_KMEMSTATISTICS].n_type == 0 ||
3451eaf0ac3Slogwang namelist[X_KMEMSTATISTICS].n_value == 0) {
3461eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
3471eaf0ac3Slogwang return (-1);
3481eaf0ac3Slogwang }
3491eaf0ac3Slogwang
3501eaf0ac3Slogwang ret = kread_symbol(kvm, X_MP_MAXCPUS, &mp_maxcpus,
3511eaf0ac3Slogwang sizeof(mp_maxcpus), 0);
3521eaf0ac3Slogwang if (ret != 0) {
3531eaf0ac3Slogwang list->mtl_error = ret;
3541eaf0ac3Slogwang return (-1);
3551eaf0ac3Slogwang }
3561eaf0ac3Slogwang
3571eaf0ac3Slogwang ret = kread_symbol(kvm, X_KMEMSTATISTICS, &kmemstatistics,
3581eaf0ac3Slogwang sizeof(kmemstatistics), 0);
3591eaf0ac3Slogwang if (ret != 0) {
3601eaf0ac3Slogwang list->mtl_error = ret;
3611eaf0ac3Slogwang return (-1);
3621eaf0ac3Slogwang }
3631eaf0ac3Slogwang
36422ce4affSfengbojiang ret = memstat_malloc_zone_init_kvm(kvm);
36522ce4affSfengbojiang if (ret != 0) {
36622ce4affSfengbojiang list->mtl_error = ret;
3671eaf0ac3Slogwang return (-1);
3681eaf0ac3Slogwang }
3691eaf0ac3Slogwang
37022ce4affSfengbojiang mp_ncpus = kvm_getncpus(kvm);
37122ce4affSfengbojiang
3721eaf0ac3Slogwang for (typep = kmemstatistics; typep != NULL; typep = type.ks_next) {
3731eaf0ac3Slogwang ret = kread(kvm, typep, &type, sizeof(type), 0);
3741eaf0ac3Slogwang if (ret != 0) {
3751eaf0ac3Slogwang _memstat_mtl_empty(list);
3761eaf0ac3Slogwang list->mtl_error = ret;
3771eaf0ac3Slogwang return (-1);
3781eaf0ac3Slogwang }
3791eaf0ac3Slogwang ret = kread_string(kvm, (void *)type.ks_shortdesc, name,
3801eaf0ac3Slogwang MEMTYPE_MAXNAME);
3811eaf0ac3Slogwang if (ret != 0) {
3821eaf0ac3Slogwang _memstat_mtl_empty(list);
3831eaf0ac3Slogwang list->mtl_error = ret;
3841eaf0ac3Slogwang return (-1);
3851eaf0ac3Slogwang }
38622ce4affSfengbojiang if (type.ks_version != M_VERSION) {
38722ce4affSfengbojiang warnx("type %s with unsupported version %lu; skipped",
38822ce4affSfengbojiang name, type.ks_version);
38922ce4affSfengbojiang continue;
39022ce4affSfengbojiang }
3911eaf0ac3Slogwang
3921eaf0ac3Slogwang /*
3931eaf0ac3Slogwang * Since our compile-time value for MAXCPU may differ from the
3941eaf0ac3Slogwang * kernel's, we populate our own array.
3951eaf0ac3Slogwang */
39622ce4affSfengbojiang mtip = &type.ks_mti;
3971eaf0ac3Slogwang
3981eaf0ac3Slogwang if (hint_dontsearch == 0) {
3991eaf0ac3Slogwang mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC, name);
4001eaf0ac3Slogwang } else
4011eaf0ac3Slogwang mtp = NULL;
4021eaf0ac3Slogwang if (mtp == NULL)
4031eaf0ac3Slogwang mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC,
4041eaf0ac3Slogwang name, mp_maxcpus);
4051eaf0ac3Slogwang if (mtp == NULL) {
4061eaf0ac3Slogwang _memstat_mtl_empty(list);
4071eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
4081eaf0ac3Slogwang return (-1);
4091eaf0ac3Slogwang }
4101eaf0ac3Slogwang
4111eaf0ac3Slogwang /*
4121eaf0ac3Slogwang * This logic is replicated from kern_malloc.c, and should
4131eaf0ac3Slogwang * be kept in sync.
4141eaf0ac3Slogwang */
4151eaf0ac3Slogwang _memstat_mt_reset_stats(mtp, mp_maxcpus);
41622ce4affSfengbojiang for (j = 0; j < mp_ncpus; j++) {
41722ce4affSfengbojiang ret = kread_zpcpu(kvm, (u_long)mtip->mti_stats, &mts,
41822ce4affSfengbojiang sizeof(mts), j);
41922ce4affSfengbojiang if (ret != 0) {
42022ce4affSfengbojiang _memstat_mtl_empty(list);
42122ce4affSfengbojiang list->mtl_error = ret;
42222ce4affSfengbojiang return (-1);
42322ce4affSfengbojiang }
42422ce4affSfengbojiang mtp->mt_memalloced += mts.mts_memalloced;
42522ce4affSfengbojiang mtp->mt_memfreed += mts.mts_memfreed;
42622ce4affSfengbojiang mtp->mt_numallocs += mts.mts_numallocs;
42722ce4affSfengbojiang mtp->mt_numfrees += mts.mts_numfrees;
42822ce4affSfengbojiang mtp->mt_sizemask |= mts.mts_size;
4291eaf0ac3Slogwang
4301eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_memalloced =
43122ce4affSfengbojiang mts.mts_memalloced;
4321eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_memfreed =
43322ce4affSfengbojiang mts.mts_memfreed;
4341eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_numallocs =
43522ce4affSfengbojiang mts.mts_numallocs;
4361eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_numfrees =
43722ce4affSfengbojiang mts.mts_numfrees;
4381eaf0ac3Slogwang mtp->mt_percpu_alloc[j].mtp_sizemask =
43922ce4affSfengbojiang mts.mts_size;
44022ce4affSfengbojiang }
44122ce4affSfengbojiang for (; j < mp_maxcpus; j++) {
44222ce4affSfengbojiang bzero(&mtp->mt_percpu_alloc[j],
44322ce4affSfengbojiang sizeof(mtp->mt_percpu_alloc[0]));
4441eaf0ac3Slogwang }
4451eaf0ac3Slogwang
4461eaf0ac3Slogwang mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
4471eaf0ac3Slogwang mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
4481eaf0ac3Slogwang }
4491eaf0ac3Slogwang
4501eaf0ac3Slogwang return (0);
4511eaf0ac3Slogwang }
4521eaf0ac3Slogwang
45322ce4affSfengbojiang static int
memstat_malloc_zone_init(void)45422ce4affSfengbojiang memstat_malloc_zone_init(void)
45522ce4affSfengbojiang {
45622ce4affSfengbojiang size_t size;
45722ce4affSfengbojiang
45822ce4affSfengbojiang size = sizeof(memstat_malloc_zone_count);
45922ce4affSfengbojiang if (sysctlbyname("vm.malloc.zone_count", &memstat_malloc_zone_count,
46022ce4affSfengbojiang &size, NULL, 0) < 0) {
46122ce4affSfengbojiang return (-1);
46222ce4affSfengbojiang }
46322ce4affSfengbojiang
46422ce4affSfengbojiang if (memstat_malloc_zone_count > (int)nitems(memstat_malloc_zone_sizes)) {
46522ce4affSfengbojiang return (-1);
46622ce4affSfengbojiang }
46722ce4affSfengbojiang
46822ce4affSfengbojiang size = sizeof(memstat_malloc_zone_sizes);
46922ce4affSfengbojiang if (sysctlbyname("vm.malloc.zone_sizes", &memstat_malloc_zone_sizes,
47022ce4affSfengbojiang &size, NULL, 0) < 0) {
47122ce4affSfengbojiang return (-1);
47222ce4affSfengbojiang }
47322ce4affSfengbojiang
47422ce4affSfengbojiang return (0);
47522ce4affSfengbojiang }
47622ce4affSfengbojiang
47722ce4affSfengbojiang /*
47822ce4affSfengbojiang * Copied from kern_malloc.c
47922ce4affSfengbojiang *
48022ce4affSfengbojiang * kz_zone is an array sized at compilation time, the size is exported in
48122ce4affSfengbojiang * "numzones". Below we need to iterate kz_size.
48222ce4affSfengbojiang */
48322ce4affSfengbojiang struct memstat_kmemzone {
48422ce4affSfengbojiang int kz_size;
48522ce4affSfengbojiang const char *kz_name;
48622ce4affSfengbojiang void *kz_zone[1];
48722ce4affSfengbojiang };
48822ce4affSfengbojiang
48922ce4affSfengbojiang static int
memstat_malloc_zone_init_kvm(kvm_t * kvm)49022ce4affSfengbojiang memstat_malloc_zone_init_kvm(kvm_t *kvm)
49122ce4affSfengbojiang {
49222ce4affSfengbojiang struct memstat_kmemzone *kmemzones, *kz;
49322ce4affSfengbojiang int numzones, objsize, allocsize, ret;
49422ce4affSfengbojiang int i;
49522ce4affSfengbojiang
49622ce4affSfengbojiang ret = kread_symbol(kvm, X_VM_MALLOC_ZONE_COUNT,
49722ce4affSfengbojiang &memstat_malloc_zone_count, sizeof(memstat_malloc_zone_count), 0);
49822ce4affSfengbojiang if (ret != 0) {
49922ce4affSfengbojiang return (ret);
50022ce4affSfengbojiang }
50122ce4affSfengbojiang
50222ce4affSfengbojiang ret = kread_symbol(kvm, X_NUMZONES, &numzones, sizeof(numzones), 0);
50322ce4affSfengbojiang if (ret != 0) {
50422ce4affSfengbojiang return (ret);
50522ce4affSfengbojiang }
50622ce4affSfengbojiang
50722ce4affSfengbojiang objsize = __offsetof(struct memstat_kmemzone, kz_zone) +
50822ce4affSfengbojiang sizeof(void *) * numzones;
50922ce4affSfengbojiang
51022ce4affSfengbojiang allocsize = objsize * memstat_malloc_zone_count;
51122ce4affSfengbojiang kmemzones = malloc(allocsize);
51222ce4affSfengbojiang if (kmemzones == NULL) {
51322ce4affSfengbojiang return (MEMSTAT_ERROR_NOMEMORY);
51422ce4affSfengbojiang }
51522ce4affSfengbojiang ret = kread_symbol(kvm, X_KMEMZONES, kmemzones, allocsize, 0);
51622ce4affSfengbojiang if (ret != 0) {
51722ce4affSfengbojiang free(kmemzones);
51822ce4affSfengbojiang return (ret);
51922ce4affSfengbojiang }
52022ce4affSfengbojiang
52122ce4affSfengbojiang kz = kmemzones;
52222ce4affSfengbojiang for (i = 0; i < (int)nitems(memstat_malloc_zone_sizes); i++) {
52322ce4affSfengbojiang memstat_malloc_zone_sizes[i] = kz->kz_size;
52422ce4affSfengbojiang kz = (struct memstat_kmemzone *)((char *)kz + objsize);
52522ce4affSfengbojiang }
52622ce4affSfengbojiang
52722ce4affSfengbojiang free(kmemzones);
52822ce4affSfengbojiang return (0);
52922ce4affSfengbojiang }
53022ce4affSfengbojiang
53122ce4affSfengbojiang size_t
memstat_malloc_zone_get_count(void)53222ce4affSfengbojiang memstat_malloc_zone_get_count(void)
53322ce4affSfengbojiang {
53422ce4affSfengbojiang
53522ce4affSfengbojiang return (memstat_malloc_zone_count);
53622ce4affSfengbojiang }
53722ce4affSfengbojiang
53822ce4affSfengbojiang size_t
memstat_malloc_zone_get_size(size_t n)53922ce4affSfengbojiang memstat_malloc_zone_get_size(size_t n)
54022ce4affSfengbojiang {
54122ce4affSfengbojiang
54222ce4affSfengbojiang if (n >= nitems(memstat_malloc_zone_sizes)) {
54322ce4affSfengbojiang return (-1);
54422ce4affSfengbojiang }
54522ce4affSfengbojiang
54622ce4affSfengbojiang return (memstat_malloc_zone_sizes[n]);
54722ce4affSfengbojiang }
54822ce4affSfengbojiang
54922ce4affSfengbojiang int
memstat_malloc_zone_used(const struct memory_type * mtp,size_t n)55022ce4affSfengbojiang memstat_malloc_zone_used(const struct memory_type *mtp, size_t n)
55122ce4affSfengbojiang {
55222ce4affSfengbojiang
55322ce4affSfengbojiang if (memstat_get_sizemask(mtp) & (1 << n))
55422ce4affSfengbojiang return (1);
55522ce4affSfengbojiang
55622ce4affSfengbojiang return (0);
55722ce4affSfengbojiang }
558*d4a07e70Sfengbojiang #endif
559*d4a07e70Sfengbojiang
560