xref: /f-stack/tools/libmemstat/memstat_uma.c (revision d4a07e70)
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