11eaf0ac3Slogwang /*-
222ce4affSfengbojiang * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
322ce4affSfengbojiang *
41eaf0ac3Slogwang * Copyright (c) 2005-2006 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/param.h>
3622ce4affSfengbojiang #include <sys/counter.h>
371eaf0ac3Slogwang #include <sys/cpuset.h>
381eaf0ac3Slogwang #include <sys/sysctl.h>
391eaf0ac3Slogwang
401eaf0ac3Slogwang #include <vm/uma.h>
411eaf0ac3Slogwang #include <vm/uma_int.h>
421eaf0ac3Slogwang
431eaf0ac3Slogwang #include <err.h>
441eaf0ac3Slogwang #include <errno.h>
45*d4a07e70Sfengbojiang #ifndef FSTACK
461eaf0ac3Slogwang #include <kvm.h>
47*d4a07e70Sfengbojiang #endif
481eaf0ac3Slogwang #include <nlist.h>
491eaf0ac3Slogwang #include <stddef.h>
501eaf0ac3Slogwang #include <stdio.h>
511eaf0ac3Slogwang #include <stdlib.h>
521eaf0ac3Slogwang #include <string.h>
531eaf0ac3Slogwang #include <unistd.h>
541eaf0ac3Slogwang
551eaf0ac3Slogwang #include "memstat.h"
561eaf0ac3Slogwang #include "memstat_internal.h"
571eaf0ac3Slogwang
58*d4a07e70Sfengbojiang #ifndef FSTACK
591eaf0ac3Slogwang static struct nlist namelist[] = {
601eaf0ac3Slogwang #define X_UMA_KEGS 0
611eaf0ac3Slogwang { .n_name = "_uma_kegs" },
621eaf0ac3Slogwang #define X_MP_MAXID 1
631eaf0ac3Slogwang { .n_name = "_mp_maxid" },
641eaf0ac3Slogwang #define X_ALL_CPUS 2
651eaf0ac3Slogwang { .n_name = "_all_cpus" },
6622ce4affSfengbojiang #define X_VM_NDOMAINS 3
6722ce4affSfengbojiang { .n_name = "_vm_ndomains" },
681eaf0ac3Slogwang { .n_name = "" },
691eaf0ac3Slogwang };
70*d4a07e70Sfengbojiang #endif
711eaf0ac3Slogwang
721eaf0ac3Slogwang /*
731eaf0ac3Slogwang * Extract uma(9) statistics from the running kernel, and store all memory
741eaf0ac3Slogwang * type information in the passed list. For each type, check the list for an
751eaf0ac3Slogwang * existing entry with the right name/allocator -- if present, update that
761eaf0ac3Slogwang * entry. Otherwise, add a new entry. On error, the entire list will be
771eaf0ac3Slogwang * cleared, as entries will be in an inconsistent state.
781eaf0ac3Slogwang *
791eaf0ac3Slogwang * To reduce the level of work for a list that starts empty, we keep around a
801eaf0ac3Slogwang * hint as to whether it was empty when we began, so we can avoid searching
811eaf0ac3Slogwang * the list for entries to update. Updates are O(n^2) due to searching for
821eaf0ac3Slogwang * each entry before adding it.
831eaf0ac3Slogwang */
841eaf0ac3Slogwang int
memstat_sysctl_uma(struct memory_type_list * list,int flags)851eaf0ac3Slogwang memstat_sysctl_uma(struct memory_type_list *list, int flags)
861eaf0ac3Slogwang {
871eaf0ac3Slogwang struct uma_stream_header *ushp;
881eaf0ac3Slogwang struct uma_type_header *uthp;
891eaf0ac3Slogwang struct uma_percpu_stat *upsp;
901eaf0ac3Slogwang struct memory_type *mtp;
911eaf0ac3Slogwang int count, hint_dontsearch, i, j, maxcpus, maxid;
921eaf0ac3Slogwang char *buffer, *p;
931eaf0ac3Slogwang size_t size;
941eaf0ac3Slogwang
951eaf0ac3Slogwang hint_dontsearch = LIST_EMPTY(&list->mtl_list);
961eaf0ac3Slogwang
971eaf0ac3Slogwang /*
981eaf0ac3Slogwang * Query the number of CPUs, number of malloc types so that we can
991eaf0ac3Slogwang * guess an initial buffer size. We loop until we succeed or really
1001eaf0ac3Slogwang * fail. Note that the value of maxcpus we query using sysctl is not
1011eaf0ac3Slogwang * the version we use when processing the real data -- that is read
1021eaf0ac3Slogwang * from the header.
1031eaf0ac3Slogwang */
1041eaf0ac3Slogwang retry:
1051eaf0ac3Slogwang size = sizeof(maxid);
1061eaf0ac3Slogwang if (sysctlbyname("kern.smp.maxid", &maxid, &size, NULL, 0) < 0) {
1071eaf0ac3Slogwang if (errno == EACCES || errno == EPERM)
1081eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_PERMISSION;
1091eaf0ac3Slogwang else
1101eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_DATAERROR;
1111eaf0ac3Slogwang return (-1);
1121eaf0ac3Slogwang }
1131eaf0ac3Slogwang if (size != sizeof(maxid)) {
1141eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_DATAERROR;
1151eaf0ac3Slogwang return (-1);
1161eaf0ac3Slogwang }
1171eaf0ac3Slogwang
1181eaf0ac3Slogwang size = sizeof(count);
1191eaf0ac3Slogwang if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) {
1201eaf0ac3Slogwang if (errno == EACCES || errno == EPERM)
1211eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_PERMISSION;
1221eaf0ac3Slogwang else
1231eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1241eaf0ac3Slogwang return (-1);
1251eaf0ac3Slogwang }
1261eaf0ac3Slogwang if (size != sizeof(count)) {
1271eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_DATAERROR;
1281eaf0ac3Slogwang return (-1);
1291eaf0ac3Slogwang }
1301eaf0ac3Slogwang
1311eaf0ac3Slogwang size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) *
1321eaf0ac3Slogwang (maxid + 1));
1331eaf0ac3Slogwang
1341eaf0ac3Slogwang buffer = malloc(size);
1351eaf0ac3Slogwang if (buffer == NULL) {
1361eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
1371eaf0ac3Slogwang return (-1);
1381eaf0ac3Slogwang }
1391eaf0ac3Slogwang
1401eaf0ac3Slogwang if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) {
1411eaf0ac3Slogwang /*
1421eaf0ac3Slogwang * XXXRW: ENOMEM is an ambiguous return, we should bound the
1431eaf0ac3Slogwang * number of loops, perhaps.
1441eaf0ac3Slogwang */
1451eaf0ac3Slogwang if (errno == ENOMEM) {
1461eaf0ac3Slogwang free(buffer);
1471eaf0ac3Slogwang goto retry;
1481eaf0ac3Slogwang }
1491eaf0ac3Slogwang if (errno == EACCES || errno == EPERM)
1501eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_PERMISSION;
1511eaf0ac3Slogwang else
1521eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1531eaf0ac3Slogwang free(buffer);
1541eaf0ac3Slogwang return (-1);
1551eaf0ac3Slogwang }
1561eaf0ac3Slogwang
1571eaf0ac3Slogwang if (size == 0) {
1581eaf0ac3Slogwang free(buffer);
1591eaf0ac3Slogwang return (0);
1601eaf0ac3Slogwang }
1611eaf0ac3Slogwang
1621eaf0ac3Slogwang if (size < sizeof(*ushp)) {
1631eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1641eaf0ac3Slogwang free(buffer);
1651eaf0ac3Slogwang return (-1);
1661eaf0ac3Slogwang }
1671eaf0ac3Slogwang p = buffer;
1681eaf0ac3Slogwang ushp = (struct uma_stream_header *)p;
1691eaf0ac3Slogwang p += sizeof(*ushp);
1701eaf0ac3Slogwang
1711eaf0ac3Slogwang if (ushp->ush_version != UMA_STREAM_VERSION) {
1721eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_VERSION;
1731eaf0ac3Slogwang free(buffer);
1741eaf0ac3Slogwang return (-1);
1751eaf0ac3Slogwang }
1761eaf0ac3Slogwang
1771eaf0ac3Slogwang /*
1781eaf0ac3Slogwang * For the remainder of this function, we are quite trusting about
1791eaf0ac3Slogwang * the layout of structures and sizes, since we've determined we have
1801eaf0ac3Slogwang * a matching version and acceptable CPU count.
1811eaf0ac3Slogwang */
1821eaf0ac3Slogwang maxcpus = ushp->ush_maxcpus;
1831eaf0ac3Slogwang count = ushp->ush_count;
1841eaf0ac3Slogwang for (i = 0; i < count; i++) {
1851eaf0ac3Slogwang uthp = (struct uma_type_header *)p;
1861eaf0ac3Slogwang p += sizeof(*uthp);
1871eaf0ac3Slogwang
1881eaf0ac3Slogwang if (hint_dontsearch == 0) {
1891eaf0ac3Slogwang mtp = memstat_mtl_find(list, ALLOCATOR_UMA,
1901eaf0ac3Slogwang uthp->uth_name);
1911eaf0ac3Slogwang } else
1921eaf0ac3Slogwang mtp = NULL;
1931eaf0ac3Slogwang if (mtp == NULL)
1941eaf0ac3Slogwang mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA,
1951eaf0ac3Slogwang uthp->uth_name, maxid + 1);
1961eaf0ac3Slogwang if (mtp == NULL) {
1971eaf0ac3Slogwang _memstat_mtl_empty(list);
1981eaf0ac3Slogwang free(buffer);
1991eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
2001eaf0ac3Slogwang return (-1);
2011eaf0ac3Slogwang }
2021eaf0ac3Slogwang
2031eaf0ac3Slogwang /*
2041eaf0ac3Slogwang * Reset the statistics on a current node.
2051eaf0ac3Slogwang */
2061eaf0ac3Slogwang _memstat_mt_reset_stats(mtp, maxid + 1);
2071eaf0ac3Slogwang
2081eaf0ac3Slogwang mtp->mt_numallocs = uthp->uth_allocs;
2091eaf0ac3Slogwang mtp->mt_numfrees = uthp->uth_frees;
2101eaf0ac3Slogwang mtp->mt_failures = uthp->uth_fails;
2111eaf0ac3Slogwang mtp->mt_sleeps = uthp->uth_sleeps;
21222ce4affSfengbojiang mtp->mt_xdomain = uthp->uth_xdomain;
2131eaf0ac3Slogwang
2141eaf0ac3Slogwang for (j = 0; j < maxcpus; j++) {
2151eaf0ac3Slogwang upsp = (struct uma_percpu_stat *)p;
2161eaf0ac3Slogwang p += sizeof(*upsp);
2171eaf0ac3Slogwang
2181eaf0ac3Slogwang mtp->mt_percpu_cache[j].mtp_free =
2191eaf0ac3Slogwang upsp->ups_cache_free;
2201eaf0ac3Slogwang mtp->mt_free += upsp->ups_cache_free;
2211eaf0ac3Slogwang mtp->mt_numallocs += upsp->ups_allocs;
2221eaf0ac3Slogwang mtp->mt_numfrees += upsp->ups_frees;
2231eaf0ac3Slogwang }
2241eaf0ac3Slogwang
22522ce4affSfengbojiang /*
22622ce4affSfengbojiang * Values for uth_allocs and uth_frees frees are snap.
22722ce4affSfengbojiang * It may happen that kernel reports that number of frees
22822ce4affSfengbojiang * is greater than number of allocs. See counter(9) for
22922ce4affSfengbojiang * details.
23022ce4affSfengbojiang */
23122ce4affSfengbojiang if (mtp->mt_numallocs < mtp->mt_numfrees)
23222ce4affSfengbojiang mtp->mt_numallocs = mtp->mt_numfrees;
23322ce4affSfengbojiang
2341eaf0ac3Slogwang mtp->mt_size = uthp->uth_size;
2351eaf0ac3Slogwang mtp->mt_rsize = uthp->uth_rsize;
2361eaf0ac3Slogwang mtp->mt_memalloced = mtp->mt_numallocs * uthp->uth_size;
2371eaf0ac3Slogwang mtp->mt_memfreed = mtp->mt_numfrees * uthp->uth_size;
2381eaf0ac3Slogwang mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
2391eaf0ac3Slogwang mtp->mt_countlimit = uthp->uth_limit;
2401eaf0ac3Slogwang mtp->mt_byteslimit = uthp->uth_limit * uthp->uth_size;
2411eaf0ac3Slogwang
2421eaf0ac3Slogwang mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
2431eaf0ac3Slogwang mtp->mt_zonefree = uthp->uth_zone_free;
2441eaf0ac3Slogwang
2451eaf0ac3Slogwang /*
2461eaf0ac3Slogwang * UMA secondary zones share a keg with the primary zone. To
2471eaf0ac3Slogwang * avoid double-reporting of free items, report keg free
2481eaf0ac3Slogwang * items only in the primary zone.
2491eaf0ac3Slogwang */
2501eaf0ac3Slogwang if (!(uthp->uth_zone_flags & UTH_ZONE_SECONDARY)) {
2511eaf0ac3Slogwang mtp->mt_kegfree = uthp->uth_keg_free;
2521eaf0ac3Slogwang mtp->mt_free += mtp->mt_kegfree;
2531eaf0ac3Slogwang }
2541eaf0ac3Slogwang mtp->mt_free += mtp->mt_zonefree;
2551eaf0ac3Slogwang }
2561eaf0ac3Slogwang
2571eaf0ac3Slogwang free(buffer);
2581eaf0ac3Slogwang
2591eaf0ac3Slogwang return (0);
2601eaf0ac3Slogwang }
2611eaf0ac3Slogwang
262*d4a07e70Sfengbojiang #ifndef FSTACK
2631eaf0ac3Slogwang static int
kread(kvm_t * kvm,void * kvm_pointer,void * address,size_t size,size_t offset)2641eaf0ac3Slogwang kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size,
2651eaf0ac3Slogwang size_t offset)
2661eaf0ac3Slogwang {
2671eaf0ac3Slogwang ssize_t ret;
2681eaf0ac3Slogwang
2691eaf0ac3Slogwang ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address,
2701eaf0ac3Slogwang size);
2711eaf0ac3Slogwang if (ret < 0)
2721eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM);
2731eaf0ac3Slogwang if ((size_t)ret != size)
2741eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM_SHORTREAD);
2751eaf0ac3Slogwang return (0);
2761eaf0ac3Slogwang }
2771eaf0ac3Slogwang
2781eaf0ac3Slogwang static int
kread_string(kvm_t * kvm,const void * kvm_pointer,char * buffer,int buflen)2791eaf0ac3Slogwang kread_string(kvm_t *kvm, const void *kvm_pointer, char *buffer, int buflen)
2801eaf0ac3Slogwang {
2811eaf0ac3Slogwang ssize_t ret;
2821eaf0ac3Slogwang int i;
2831eaf0ac3Slogwang
2841eaf0ac3Slogwang for (i = 0; i < buflen; i++) {
2851eaf0ac3Slogwang ret = kvm_read(kvm, (unsigned long)kvm_pointer + i,
2861eaf0ac3Slogwang &(buffer[i]), sizeof(char));
2871eaf0ac3Slogwang if (ret < 0)
2881eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM);
2891eaf0ac3Slogwang if ((size_t)ret != sizeof(char))
2901eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM_SHORTREAD);
2911eaf0ac3Slogwang if (buffer[i] == '\0')
2921eaf0ac3Slogwang return (0);
2931eaf0ac3Slogwang }
2941eaf0ac3Slogwang /* Truncate. */
2951eaf0ac3Slogwang buffer[i-1] = '\0';
2961eaf0ac3Slogwang return (0);
2971eaf0ac3Slogwang }
2981eaf0ac3Slogwang
2991eaf0ac3Slogwang static int
kread_symbol(kvm_t * kvm,int index,void * address,size_t size,size_t offset)3001eaf0ac3Slogwang kread_symbol(kvm_t *kvm, int index, void *address, size_t size,
3011eaf0ac3Slogwang size_t offset)
3021eaf0ac3Slogwang {
3031eaf0ac3Slogwang ssize_t ret;
3041eaf0ac3Slogwang
3051eaf0ac3Slogwang ret = kvm_read(kvm, namelist[index].n_value + offset, address, size);
3061eaf0ac3Slogwang if (ret < 0)
3071eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM);
3081eaf0ac3Slogwang if ((size_t)ret != size)
3091eaf0ac3Slogwang return (MEMSTAT_ERROR_KVM_SHORTREAD);
3101eaf0ac3Slogwang return (0);
3111eaf0ac3Slogwang }
3121eaf0ac3Slogwang
3131eaf0ac3Slogwang /*
3141eaf0ac3Slogwang * memstat_kvm_uma() is similar to memstat_sysctl_uma(), only it extracts
3151eaf0ac3Slogwang * UMA(9) statistics from a kernel core/memory file.
3161eaf0ac3Slogwang */
3171eaf0ac3Slogwang int
memstat_kvm_uma(struct memory_type_list * list,void * kvm_handle)3181eaf0ac3Slogwang memstat_kvm_uma(struct memory_type_list *list, void *kvm_handle)
3191eaf0ac3Slogwang {
3201eaf0ac3Slogwang LIST_HEAD(, uma_keg) uma_kegs;
3211eaf0ac3Slogwang struct memory_type *mtp;
32222ce4affSfengbojiang struct uma_zone_domain uzd;
32322ce4affSfengbojiang struct uma_domain ukd;
3241eaf0ac3Slogwang struct uma_bucket *ubp, ub;
3251eaf0ac3Slogwang struct uma_cache *ucp, *ucp_array;
3261eaf0ac3Slogwang struct uma_zone *uzp, uz;
3271eaf0ac3Slogwang struct uma_keg *kzp, kz;
32822ce4affSfengbojiang uint64_t kegfree;
32922ce4affSfengbojiang int hint_dontsearch, i, mp_maxid, ndomains, ret;
3301eaf0ac3Slogwang char name[MEMTYPE_MAXNAME];
3311eaf0ac3Slogwang cpuset_t all_cpus;
3321eaf0ac3Slogwang long cpusetsize;
3331eaf0ac3Slogwang kvm_t *kvm;
3341eaf0ac3Slogwang
3351eaf0ac3Slogwang kvm = (kvm_t *)kvm_handle;
3361eaf0ac3Slogwang hint_dontsearch = LIST_EMPTY(&list->mtl_list);
3371eaf0ac3Slogwang if (kvm_nlist(kvm, namelist) != 0) {
3381eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_KVM;
3391eaf0ac3Slogwang return (-1);
3401eaf0ac3Slogwang }
3411eaf0ac3Slogwang if (namelist[X_UMA_KEGS].n_type == 0 ||
3421eaf0ac3Slogwang namelist[X_UMA_KEGS].n_value == 0) {
3431eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
3441eaf0ac3Slogwang return (-1);
3451eaf0ac3Slogwang }
3461eaf0ac3Slogwang ret = kread_symbol(kvm, X_MP_MAXID, &mp_maxid, sizeof(mp_maxid), 0);
3471eaf0ac3Slogwang if (ret != 0) {
3481eaf0ac3Slogwang list->mtl_error = ret;
3491eaf0ac3Slogwang return (-1);
3501eaf0ac3Slogwang }
35122ce4affSfengbojiang ret = kread_symbol(kvm, X_VM_NDOMAINS, &ndomains,
35222ce4affSfengbojiang sizeof(ndomains), 0);
35322ce4affSfengbojiang if (ret != 0) {
35422ce4affSfengbojiang list->mtl_error = ret;
35522ce4affSfengbojiang return (-1);
35622ce4affSfengbojiang }
3571eaf0ac3Slogwang ret = kread_symbol(kvm, X_UMA_KEGS, &uma_kegs, sizeof(uma_kegs), 0);
3581eaf0ac3Slogwang if (ret != 0) {
3591eaf0ac3Slogwang list->mtl_error = ret;
3601eaf0ac3Slogwang return (-1);
3611eaf0ac3Slogwang }
3621eaf0ac3Slogwang cpusetsize = sysconf(_SC_CPUSET_SIZE);
3631eaf0ac3Slogwang if (cpusetsize == -1 || (u_long)cpusetsize > sizeof(cpuset_t)) {
3641eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL;
3651eaf0ac3Slogwang return (-1);
3661eaf0ac3Slogwang }
3671eaf0ac3Slogwang CPU_ZERO(&all_cpus);
3681eaf0ac3Slogwang ret = kread_symbol(kvm, X_ALL_CPUS, &all_cpus, cpusetsize, 0);
3691eaf0ac3Slogwang if (ret != 0) {
3701eaf0ac3Slogwang list->mtl_error = ret;
3711eaf0ac3Slogwang return (-1);
3721eaf0ac3Slogwang }
3731eaf0ac3Slogwang ucp_array = malloc(sizeof(struct uma_cache) * (mp_maxid + 1));
3741eaf0ac3Slogwang if (ucp_array == NULL) {
3751eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
3761eaf0ac3Slogwang return (-1);
3771eaf0ac3Slogwang }
3781eaf0ac3Slogwang for (kzp = LIST_FIRST(&uma_kegs); kzp != NULL; kzp =
3791eaf0ac3Slogwang LIST_NEXT(&kz, uk_link)) {
3801eaf0ac3Slogwang ret = kread(kvm, kzp, &kz, sizeof(kz), 0);
3811eaf0ac3Slogwang if (ret != 0) {
3821eaf0ac3Slogwang free(ucp_array);
3831eaf0ac3Slogwang _memstat_mtl_empty(list);
3841eaf0ac3Slogwang list->mtl_error = ret;
3851eaf0ac3Slogwang return (-1);
3861eaf0ac3Slogwang }
3871eaf0ac3Slogwang for (uzp = LIST_FIRST(&kz.uk_zones); uzp != NULL; uzp =
3881eaf0ac3Slogwang LIST_NEXT(&uz, uz_link)) {
3891eaf0ac3Slogwang ret = kread(kvm, uzp, &uz, sizeof(uz), 0);
3901eaf0ac3Slogwang if (ret != 0) {
3911eaf0ac3Slogwang free(ucp_array);
3921eaf0ac3Slogwang _memstat_mtl_empty(list);
3931eaf0ac3Slogwang list->mtl_error = ret;
3941eaf0ac3Slogwang return (-1);
3951eaf0ac3Slogwang }
3961eaf0ac3Slogwang ret = kread(kvm, uzp, ucp_array,
3971eaf0ac3Slogwang sizeof(struct uma_cache) * (mp_maxid + 1),
3981eaf0ac3Slogwang offsetof(struct uma_zone, uz_cpu[0]));
3991eaf0ac3Slogwang if (ret != 0) {
4001eaf0ac3Slogwang free(ucp_array);
4011eaf0ac3Slogwang _memstat_mtl_empty(list);
4021eaf0ac3Slogwang list->mtl_error = ret;
4031eaf0ac3Slogwang return (-1);
4041eaf0ac3Slogwang }
4051eaf0ac3Slogwang ret = kread_string(kvm, uz.uz_name, name,
4061eaf0ac3Slogwang MEMTYPE_MAXNAME);
4071eaf0ac3Slogwang if (ret != 0) {
4081eaf0ac3Slogwang free(ucp_array);
4091eaf0ac3Slogwang _memstat_mtl_empty(list);
4101eaf0ac3Slogwang list->mtl_error = ret;
4111eaf0ac3Slogwang return (-1);
4121eaf0ac3Slogwang }
4131eaf0ac3Slogwang if (hint_dontsearch == 0) {
4141eaf0ac3Slogwang mtp = memstat_mtl_find(list, ALLOCATOR_UMA,
4151eaf0ac3Slogwang name);
4161eaf0ac3Slogwang } else
4171eaf0ac3Slogwang mtp = NULL;
4181eaf0ac3Slogwang if (mtp == NULL)
4191eaf0ac3Slogwang mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA,
4201eaf0ac3Slogwang name, mp_maxid + 1);
4211eaf0ac3Slogwang if (mtp == NULL) {
4221eaf0ac3Slogwang free(ucp_array);
4231eaf0ac3Slogwang _memstat_mtl_empty(list);
4241eaf0ac3Slogwang list->mtl_error = MEMSTAT_ERROR_NOMEMORY;
4251eaf0ac3Slogwang return (-1);
4261eaf0ac3Slogwang }
4271eaf0ac3Slogwang /*
4281eaf0ac3Slogwang * Reset the statistics on a current node.
4291eaf0ac3Slogwang */
4301eaf0ac3Slogwang _memstat_mt_reset_stats(mtp, mp_maxid + 1);
43122ce4affSfengbojiang mtp->mt_numallocs = kvm_counter_u64_fetch(kvm,
43222ce4affSfengbojiang (unsigned long )uz.uz_allocs);
43322ce4affSfengbojiang mtp->mt_numfrees = kvm_counter_u64_fetch(kvm,
43422ce4affSfengbojiang (unsigned long )uz.uz_frees);
43522ce4affSfengbojiang mtp->mt_failures = kvm_counter_u64_fetch(kvm,
43622ce4affSfengbojiang (unsigned long )uz.uz_fails);
43722ce4affSfengbojiang mtp->mt_xdomain = kvm_counter_u64_fetch(kvm,
43822ce4affSfengbojiang (unsigned long )uz.uz_xdomain);
4391eaf0ac3Slogwang mtp->mt_sleeps = uz.uz_sleeps;
44022ce4affSfengbojiang /* See comment above in memstat_sysctl_uma(). */
44122ce4affSfengbojiang if (mtp->mt_numallocs < mtp->mt_numfrees)
44222ce4affSfengbojiang mtp->mt_numallocs = mtp->mt_numfrees;
44322ce4affSfengbojiang
4441eaf0ac3Slogwang if (kz.uk_flags & UMA_ZFLAG_INTERNAL)
4451eaf0ac3Slogwang goto skip_percpu;
4461eaf0ac3Slogwang for (i = 0; i < mp_maxid + 1; i++) {
4471eaf0ac3Slogwang if (!CPU_ISSET(i, &all_cpus))
4481eaf0ac3Slogwang continue;
4491eaf0ac3Slogwang ucp = &ucp_array[i];
4501eaf0ac3Slogwang mtp->mt_numallocs += ucp->uc_allocs;
4511eaf0ac3Slogwang mtp->mt_numfrees += ucp->uc_frees;
4521eaf0ac3Slogwang
45322ce4affSfengbojiang mtp->mt_free += ucp->uc_allocbucket.ucb_cnt;
45422ce4affSfengbojiang mtp->mt_free += ucp->uc_freebucket.ucb_cnt;
45522ce4affSfengbojiang mtp->mt_free += ucp->uc_crossbucket.ucb_cnt;
4561eaf0ac3Slogwang }
4571eaf0ac3Slogwang skip_percpu:
4581eaf0ac3Slogwang mtp->mt_size = kz.uk_size;
4591eaf0ac3Slogwang mtp->mt_rsize = kz.uk_rsize;
4601eaf0ac3Slogwang mtp->mt_memalloced = mtp->mt_numallocs * mtp->mt_size;
4611eaf0ac3Slogwang mtp->mt_memfreed = mtp->mt_numfrees * mtp->mt_size;
4621eaf0ac3Slogwang mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed;
46322ce4affSfengbojiang mtp->mt_countlimit = uz.uz_max_items;
4641eaf0ac3Slogwang mtp->mt_byteslimit = mtp->mt_countlimit * mtp->mt_size;
4651eaf0ac3Slogwang mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees;
46622ce4affSfengbojiang for (i = 0; i < ndomains; i++) {
46722ce4affSfengbojiang ret = kread(kvm, ZDOM_GET(uzp, i), &uzd,
46822ce4affSfengbojiang sizeof(uzd), 0);
46922ce4affSfengbojiang if (ret != 0)
47022ce4affSfengbojiang continue;
47122ce4affSfengbojiang for (ubp =
47222ce4affSfengbojiang STAILQ_FIRST(&uzd.uzd_buckets);
47322ce4affSfengbojiang ubp != NULL;
47422ce4affSfengbojiang ubp = STAILQ_NEXT(&ub, ub_link)) {
47522ce4affSfengbojiang ret = kread(kvm, ubp, &ub,
47622ce4affSfengbojiang sizeof(ub), 0);
47722ce4affSfengbojiang if (ret != 0)
47822ce4affSfengbojiang continue;
4791eaf0ac3Slogwang mtp->mt_zonefree += ub.ub_cnt;
4801eaf0ac3Slogwang }
48122ce4affSfengbojiang }
4821eaf0ac3Slogwang if (!((kz.uk_flags & UMA_ZONE_SECONDARY) &&
4831eaf0ac3Slogwang LIST_FIRST(&kz.uk_zones) != uzp)) {
48422ce4affSfengbojiang kegfree = 0;
48522ce4affSfengbojiang for (i = 0; i < ndomains; i++) {
48622ce4affSfengbojiang ret = kread(kvm, &kzp->uk_domain[i],
48722ce4affSfengbojiang &ukd, sizeof(ukd), 0);
48822ce4affSfengbojiang if (ret != 0)
48922ce4affSfengbojiang kegfree += ukd.ud_free_items;
49022ce4affSfengbojiang }
49122ce4affSfengbojiang mtp->mt_kegfree = kegfree;
4921eaf0ac3Slogwang mtp->mt_free += mtp->mt_kegfree;
4931eaf0ac3Slogwang }
4941eaf0ac3Slogwang mtp->mt_free += mtp->mt_zonefree;
4951eaf0ac3Slogwang }
4961eaf0ac3Slogwang }
4971eaf0ac3Slogwang free(ucp_array);
4981eaf0ac3Slogwang return (0);
4991eaf0ac3Slogwang }
500*d4a07e70Sfengbojiang #endif
501*d4a07e70Sfengbojiang
502