memstat.c revision 148619
1/*- 2 * Copyright (c) 2005 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/lib/libmemstat/memstat.c 148619 2005-08-01 13:18:21Z rwatson $ 27 */ 28 29#include <sys/param.h> 30#include <sys/sysctl.h> 31 32#include <err.h> 33#include <errno.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37 38#include "memstat.h" 39#include "memstat_internal.h" 40 41const char * 42memstat_strerror(int error) 43{ 44 45 switch (error) { 46 case MEMSTAT_ERROR_NOMEMORY: 47 return ("Cannot allocate memory"); 48 case MEMSTAT_ERROR_VERSION: 49 return ("Version mismatch"); 50 case MEMSTAT_ERROR_PERMISSION: 51 return ("Permission denied"); 52 case MEMSTAT_ERROR_TOOMANYCPUS: 53 return ("Too many CPUs"); 54 case MEMSTAT_ERROR_DATAERROR: 55 return ("Data format error"); 56 case MEMSTAT_ERROR_UNDEFINED: 57 default: 58 return ("Unknown error"); 59 } 60} 61 62struct memory_type_list * 63memstat_mtl_alloc(void) 64{ 65 struct memory_type_list *mtlp; 66 67 mtlp = malloc(sizeof(*mtlp)); 68 if (mtlp == NULL) 69 return (NULL); 70 71 LIST_INIT(&mtlp->mtl_list); 72 mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED; 73 return (mtlp); 74} 75 76struct memory_type * 77memstat_mtl_first(struct memory_type_list *list) 78{ 79 80 return (LIST_FIRST(&list->mtl_list)); 81} 82 83struct memory_type * 84memstat_mtl_next(struct memory_type *mtp) 85{ 86 87 return (LIST_NEXT(mtp, mt_list)); 88} 89 90void 91_memstat_mtl_empty(struct memory_type_list *list) 92{ 93 struct memory_type *mtp; 94 95 while ((mtp = LIST_FIRST(&list->mtl_list))) { 96 LIST_REMOVE(mtp, mt_list); 97 free(mtp); 98 } 99} 100 101void 102memstat_mtl_free(struct memory_type_list *list) 103{ 104 105 _memstat_mtl_empty(list); 106 free(list); 107} 108 109int 110memstat_mtl_geterror(struct memory_type_list *list) 111{ 112 113 return (list->mtl_error); 114} 115 116/* 117 * Look for an existing memory_type entry in a memory_type list, based on the 118 * allocator and name of the type. If not found, return NULL. No errno or 119 * memstat error. 120 */ 121struct memory_type * 122memstat_mtl_find(struct memory_type_list *list, int allocator, 123 const char *name) 124{ 125 struct memory_type *mtp; 126 127 LIST_FOREACH(mtp, &list->mtl_list, mt_list) { 128 if ((mtp->mt_allocator == allocator || 129 allocator == ALLOCATOR_ANY) && 130 strcmp(mtp->mt_name, name) == 0) 131 return (mtp); 132 } 133 return (NULL); 134} 135 136/* 137 * Allocate a new memory_type with the specificed allocator type and name, 138 * then insert into the list. The structure will be zero'd. 139 * 140 * libmemstat(3) internal function. 141 */ 142struct memory_type * 143_memstat_mt_allocate(struct memory_type_list *list, int allocator, 144 const char *name) 145{ 146 struct memory_type *mtp; 147 148 mtp = malloc(sizeof(*mtp)); 149 if (mtp == NULL) 150 return (NULL); 151 152 bzero(mtp, sizeof(*mtp)); 153 154 mtp->mt_allocator = allocator; 155 strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME); 156 LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list); 157 return (mtp); 158} 159 160/* 161 * Reset any libmemstat(3)-owned statistics in a memory_type record so that 162 * it can be reused without incremental addition problems. Caller-owned 163 * memory is left "as-is", and must be updated by the caller if desired. 164 * 165 * libmemstat(3) internal function. 166 */ 167void 168_memstat_mt_reset_stats(struct memory_type *mtp) 169{ 170 int i; 171 172 mtp->mt_countlimit = 0; 173 mtp->mt_byteslimit = 0; 174 mtp->mt_sizemask = 0; 175 mtp->mt_size = 0; 176 177 mtp->mt_memalloced = 0; 178 mtp->mt_memfreed = 0; 179 mtp->mt_numallocs = 0; 180 mtp->mt_numfrees = 0; 181 mtp->mt_bytes = 0; 182 mtp->mt_count = 0; 183 mtp->mt_free = 0; 184 mtp->mt_failures = 0; 185 186 mtp->mt_zonefree = 0; 187 mtp->mt_kegfree = 0; 188 189 for (i = 0; i < MEMSTAT_MAXCPU; i++) { 190 mtp->mt_percpu_alloc[i].mtp_memalloced = 0; 191 mtp->mt_percpu_alloc[i].mtp_memfreed = 0; 192 mtp->mt_percpu_alloc[i].mtp_numallocs = 0; 193 mtp->mt_percpu_alloc[i].mtp_numfrees = 0; 194 mtp->mt_percpu_alloc[i].mtp_sizemask = 0; 195 mtp->mt_percpu_cache[i].mtp_free = 0; 196 } 197} 198 199/* 200 * Accessor methods for struct memory_type. Avoids encoding the structure 201 * ABI into the application. 202 */ 203const char * 204memstat_get_name(const struct memory_type *mtp) 205{ 206 207 return (mtp->mt_name); 208} 209 210int 211memstat_get_allocator(const struct memory_type *mtp) 212{ 213 214 return (mtp->mt_allocator); 215} 216 217uint64_t 218memstat_get_countlimit(const struct memory_type *mtp) 219{ 220 221 return (mtp->mt_countlimit); 222} 223 224uint64_t 225memstat_get_byteslimit(const struct memory_type *mtp) 226{ 227 228 return (mtp->mt_byteslimit); 229} 230 231uint64_t 232memstat_get_sizemask(const struct memory_type *mtp) 233{ 234 235 return (mtp->mt_sizemask); 236} 237 238uint64_t 239memstat_get_size(const struct memory_type *mtp) 240{ 241 242 return (mtp->mt_size); 243} 244 245uint64_t 246memstat_get_memalloced(const struct memory_type *mtp) 247{ 248 249 return (mtp->mt_memalloced); 250} 251 252uint64_t 253memstat_get_memfreed(const struct memory_type *mtp) 254{ 255 256 return (mtp->mt_memfreed); 257} 258 259uint64_t 260memstat_get_numallocs(const struct memory_type *mtp) 261{ 262 263 return (mtp->mt_numallocs); 264} 265 266uint64_t 267memstat_get_numfrees(const struct memory_type *mtp) 268{ 269 270 return (mtp->mt_numfrees); 271} 272 273uint64_t 274memstat_get_bytes(const struct memory_type *mtp) 275{ 276 277 return (mtp->mt_bytes); 278} 279 280uint64_t 281memstat_get_count(const struct memory_type *mtp) 282{ 283 284 return (mtp->mt_count); 285} 286 287uint64_t 288memstat_get_free(const struct memory_type *mtp) 289{ 290 291 return (mtp->mt_free); 292} 293 294uint64_t 295memstat_get_failures(const struct memory_type *mtp) 296{ 297 298 return (mtp->mt_failures); 299} 300 301void * 302memstat_get_caller_pointer(const struct memory_type *mtp, int index) 303{ 304 305 return (mtp->mt_caller_pointer[index]); 306} 307 308void 309memstat_set_caller_pointer(struct memory_type *mtp, int index, void *value) 310{ 311 312 mtp->mt_caller_pointer[index] = value; 313} 314 315uint64_t 316memstat_get_caller_uint64(const struct memory_type *mtp, int index) 317{ 318 319 return (mtp->mt_caller_uint64[index]); 320} 321 322void 323memstat_set_caller_uint64(struct memory_type *mtp, int index, uint64_t value) 324{ 325 326 mtp->mt_caller_uint64[index] = value; 327} 328 329uint64_t 330memstat_get_zonefree(const struct memory_type *mtp) 331{ 332 333 return (mtp->mt_zonefree); 334} 335 336uint64_t 337memstat_get_kegfree(const struct memory_type *mtp) 338{ 339 340 return (mtp->mt_kegfree); 341} 342 343uint64_t 344memstat_get_percpu_memalloced(const struct memory_type *mtp, int cpu) 345{ 346 347 return (mtp->mt_percpu_alloc[cpu].mtp_memalloced); 348} 349 350uint64_t 351memstat_get_percpu_memfreed(const struct memory_type *mtp, int cpu) 352{ 353 354 return (mtp->mt_percpu_alloc[cpu].mtp_memfreed); 355} 356 357uint64_t 358memstat_get_percpu_numallocs(const struct memory_type *mtp, int cpu) 359{ 360 361 return (mtp->mt_percpu_alloc[cpu].mtp_numallocs); 362} 363 364uint64_t 365memstat_get_percpu_numfrees(const struct memory_type *mtp, int cpu) 366{ 367 368 return (mtp->mt_percpu_alloc[cpu].mtp_numfrees); 369} 370 371uint64_t 372memstat_get_percpu_sizemask(const struct memory_type *mtp, int cpu) 373{ 374 375 return (mtp->mt_percpu_alloc[cpu].mtp_sizemask); 376} 377 378void * 379memstat_get_percpu_caller_pointer(const struct memory_type *mtp, int cpu, 380 int index) 381{ 382 383 return (mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index]); 384} 385 386void 387memstat_set_percpu_caller_pointer(struct memory_type *mtp, int cpu, 388 int index, void *value) 389{ 390 391 mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index] = value; 392} 393 394uint64_t 395memstat_get_percpu_caller_uint64(const struct memory_type *mtp, int cpu, 396 int index) 397{ 398 399 return (mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index]); 400} 401 402void 403memstat_set_percpu_caller_uint64(struct memory_type *mtp, int cpu, int index, 404 uint64_t value) 405{ 406 407 mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index] = value; 408} 409 410uint64_t 411memstat_get_percpu_free(const struct memory_type *mtp, int cpu) 412{ 413 414 return (mtp->mt_percpu_cache[cpu].mtp_free); 415} 416