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