memstat_uma.c revision 148381
1147997Srwatson/*- 2147997Srwatson * Copyright (c) 2005 Robert N. M. Watson 3147997Srwatson * All rights reserved. 4147997Srwatson * 5147997Srwatson * Redistribution and use in source and binary forms, with or without 6147997Srwatson * modification, are permitted provided that the following conditions 7147997Srwatson * are met: 8147997Srwatson * 1. Redistributions of source code must retain the above copyright 9147997Srwatson * notice, this list of conditions and the following disclaimer. 10147997Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11147997Srwatson * notice, this list of conditions and the following disclaimer in the 12147997Srwatson * documentation and/or other materials provided with the distribution. 13147997Srwatson * 14147997Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15147997Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16147997Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17147997Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18147997Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19147997Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20147997Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21147997Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22147997Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23147997Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24147997Srwatson * SUCH DAMAGE. 25147997Srwatson * 26147997Srwatson * $FreeBSD: head/lib/libmemstat/memstat_uma.c 148381 2005-07-25 09:52:59Z rwatson $ 27147997Srwatson */ 28147997Srwatson 29147997Srwatson#include <sys/param.h> 30147997Srwatson#include <sys/sysctl.h> 31147997Srwatson 32147997Srwatson#include <vm/uma.h> 33147997Srwatson 34147997Srwatson#include <err.h> 35147997Srwatson#include <errno.h> 36147997Srwatson#include <stdio.h> 37147997Srwatson#include <stdlib.h> 38147997Srwatson#include <string.h> 39147997Srwatson 40147997Srwatson#include "memstat.h" 41147997Srwatson#include "memstat_internal.h" 42147997Srwatson 43147997Srwatson/* 44147997Srwatson * Extract uma(9) statistics from the running kernel, and store all memory 45147997Srwatson * type information in the passed list. For each type, check the list for an 46147997Srwatson * existing entry with the right name/allocator -- if present, update that 47147997Srwatson * entry. Otherwise, add a new entry. On error, the entire list will be 48147997Srwatson * cleared, as entries will be in an inconsistent state. 49147997Srwatson * 50147997Srwatson * To reduce the level of work for a list that starts empty, we keep around a 51147997Srwatson * hint as to whether it was empty when we began, so we can avoid searching 52147997Srwatson * the list for entries to update. Updates are O(n^2) due to searching for 53147997Srwatson * each entry before adding it. 54147997Srwatson */ 55147997Srwatsonint 56147997Srwatsonmemstat_sysctl_uma(struct memory_type_list *list, int flags) 57147997Srwatson{ 58147997Srwatson struct uma_stream_header *ushp; 59147997Srwatson struct uma_type_header *uthp; 60147997Srwatson struct uma_percpu_stat *upsp; 61147997Srwatson struct memory_type *mtp; 62148357Srwatson int count, hint_dontsearch, i, j, maxcpus; 63147997Srwatson char *buffer, *p; 64147997Srwatson size_t size; 65147997Srwatson 66148357Srwatson hint_dontsearch = LIST_EMPTY(&list->mtl_list); 67147997Srwatson 68147997Srwatson /* 69147997Srwatson * Query the number of CPUs, number of malloc types so that we can 70147997Srwatson * guess an initial buffer size. We loop until we succeed or really 71147997Srwatson * fail. Note that the value of maxcpus we query using sysctl is not 72147997Srwatson * the version we use when processing the real data -- that is read 73147997Srwatson * from the header. 74147997Srwatson */ 75147997Srwatsonretry: 76147997Srwatson size = sizeof(maxcpus); 77147997Srwatson if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) { 78148357Srwatson if (errno == EACCES || errno == EPERM) 79148357Srwatson list->mtl_error = MEMSTAT_ERROR_PERMISSION; 80148357Srwatson else 81148357Srwatson list->mtl_error = MEMSTAT_ERROR_DATAERROR; 82147997Srwatson return (-1); 83147997Srwatson } 84147997Srwatson if (size != sizeof(maxcpus)) { 85148357Srwatson list->mtl_error = MEMSTAT_ERROR_DATAERROR; 86147997Srwatson return (-1); 87147997Srwatson } 88147997Srwatson 89147997Srwatson if (maxcpus > MEMSTAT_MAXCPU) { 90148357Srwatson list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS; 91147997Srwatson return (-1); 92147997Srwatson } 93147997Srwatson 94147997Srwatson size = sizeof(count); 95147997Srwatson if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) { 96148357Srwatson if (errno == EACCES || errno == EPERM) 97148357Srwatson list->mtl_error = MEMSTAT_ERROR_PERMISSION; 98148357Srwatson else 99148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 100147997Srwatson return (-1); 101147997Srwatson } 102147997Srwatson if (size != sizeof(count)) { 103148357Srwatson list->mtl_error = MEMSTAT_ERROR_DATAERROR; 104147997Srwatson return (-1); 105147997Srwatson } 106147997Srwatson 107147997Srwatson size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) * 108147997Srwatson maxcpus); 109147997Srwatson 110147997Srwatson buffer = malloc(size); 111147997Srwatson if (buffer == NULL) { 112148357Srwatson list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 113147997Srwatson return (-1); 114147997Srwatson } 115147997Srwatson 116147997Srwatson if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) { 117147997Srwatson /* 118147997Srwatson * XXXRW: ENOMEM is an ambiguous return, we should bound the 119147997Srwatson * number of loops, perhaps. 120147997Srwatson */ 121147997Srwatson if (errno == ENOMEM) { 122147997Srwatson free(buffer); 123147997Srwatson goto retry; 124147997Srwatson } 125148357Srwatson if (errno == EACCES || errno == EPERM) 126148357Srwatson list->mtl_error = MEMSTAT_ERROR_PERMISSION; 127148357Srwatson else 128148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 129147997Srwatson free(buffer); 130147997Srwatson return (-1); 131147997Srwatson } 132147997Srwatson 133147997Srwatson if (size == 0) { 134147997Srwatson free(buffer); 135147997Srwatson return (0); 136147997Srwatson } 137147997Srwatson 138147997Srwatson if (size < sizeof(*ushp)) { 139148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 140147997Srwatson free(buffer); 141147997Srwatson return (-1); 142147997Srwatson } 143147997Srwatson p = buffer; 144147997Srwatson ushp = (struct uma_stream_header *)p; 145147997Srwatson p += sizeof(*ushp); 146147997Srwatson 147147997Srwatson if (ushp->ush_version != UMA_STREAM_VERSION) { 148148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 149147997Srwatson free(buffer); 150147997Srwatson return (-1); 151147997Srwatson } 152147997Srwatson 153147997Srwatson if (ushp->ush_maxcpus > MEMSTAT_MAXCPU) { 154148357Srwatson list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS; 155147997Srwatson free(buffer); 156147997Srwatson return (-1); 157147997Srwatson } 158147997Srwatson 159147997Srwatson /* 160147997Srwatson * For the remainder of this function, we are quite trusting about 161147997Srwatson * the layout of structures and sizes, since we've determined we have 162147997Srwatson * a matching version and acceptable CPU count. 163147997Srwatson */ 164147997Srwatson maxcpus = ushp->ush_maxcpus; 165147997Srwatson count = ushp->ush_count; 166147997Srwatson for (i = 0; i < count; i++) { 167147997Srwatson uthp = (struct uma_type_header *)p; 168147997Srwatson p += sizeof(*uthp); 169147997Srwatson 170147997Srwatson if (hint_dontsearch == 0) { 171147997Srwatson mtp = memstat_mtl_find(list, ALLOCATOR_UMA, 172147997Srwatson uthp->uth_name); 173147997Srwatson } else 174147997Srwatson mtp = NULL; 175147997Srwatson if (mtp == NULL) 176148354Srwatson mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA, 177147997Srwatson uthp->uth_name); 178147997Srwatson if (mtp == NULL) { 179147997Srwatson memstat_mtl_free(list); 180147997Srwatson free(buffer); 181148357Srwatson list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 182147997Srwatson return (-1); 183147997Srwatson } 184147997Srwatson 185147997Srwatson /* 186147997Srwatson * Reset the statistics on a current node. 187147997Srwatson */ 188148354Srwatson _memstat_mt_reset_stats(mtp); 189147997Srwatson 190148007Srwatson mtp->mt_numallocs = uthp->uth_allocs; 191148007Srwatson mtp->mt_numfrees = uthp->uth_frees; 192148071Srwatson mtp->mt_failures = uthp->uth_fails; 193148007Srwatson 194147997Srwatson for (j = 0; j < maxcpus; j++) { 195147997Srwatson upsp = (struct uma_percpu_stat *)p; 196147997Srwatson p += sizeof(*upsp); 197147997Srwatson 198147997Srwatson mtp->mt_percpu_cache[j].mtp_free = 199147997Srwatson upsp->ups_cache_free; 200147997Srwatson mtp->mt_free += upsp->ups_cache_free; 201147997Srwatson mtp->mt_numallocs += upsp->ups_allocs; 202147997Srwatson mtp->mt_numfrees += upsp->ups_frees; 203147997Srwatson } 204147997Srwatson 205147997Srwatson mtp->mt_size = uthp->uth_size; 206148007Srwatson mtp->mt_memalloced = mtp->mt_numallocs * uthp->uth_size; 207148007Srwatson mtp->mt_memfreed = mtp->mt_numfrees * uthp->uth_size; 208147997Srwatson mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 209147997Srwatson mtp->mt_countlimit = uthp->uth_limit; 210147997Srwatson mtp->mt_byteslimit = uthp->uth_limit * uthp->uth_size; 211147997Srwatson 212147997Srwatson mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 213148170Srwatson mtp->mt_zonefree = uthp->uth_zone_free; 214148381Srwatson 215148381Srwatson /* 216148381Srwatson * UMA secondary zones share a keg with the primary zone. To 217148381Srwatson * avoid double-reporting of free items, report keg free 218148381Srwatson * items only in the primary zone. 219148381Srwatson */ 220148381Srwatson if (!(uthp->uth_zone_flags & UTH_ZONE_SECONDARY)) { 221148381Srwatson mtp->mt_free += mtp->mt_kegfree; 222148381Srwatson mtp->mt_kegfree = uthp->uth_keg_free; 223148381Srwatson } 224147997Srwatson mtp->mt_free += mtp->mt_zonefree; 225147997Srwatson } 226147997Srwatson 227147997Srwatson free(buffer); 228147997Srwatson 229147997Srwatson return (0); 230147997Srwatson} 231