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/queue.h> 33 #include <sys/sysctl.h> 34 35 #include <err.h> 36 #include <errno.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 #ifdef FSTACK 42 #include <stdint.h> 43 #endif 44 45 #include "memstat.h" 46 #include "memstat_internal.h" 47 48 const char * 49 memstat_strerror(int error) 50 { 51 52 switch (error) { 53 case MEMSTAT_ERROR_NOMEMORY: 54 return ("Cannot allocate memory"); 55 case MEMSTAT_ERROR_VERSION: 56 return ("Version mismatch"); 57 case MEMSTAT_ERROR_PERMISSION: 58 return ("Permission denied"); 59 case MEMSTAT_ERROR_DATAERROR: 60 return ("Data format error"); 61 case MEMSTAT_ERROR_KVM: 62 return ("KVM error"); 63 case MEMSTAT_ERROR_KVM_NOSYMBOL: 64 return ("KVM unable to find symbol"); 65 case MEMSTAT_ERROR_KVM_SHORTREAD: 66 return ("KVM short read"); 67 case MEMSTAT_ERROR_UNDEFINED: 68 default: 69 return ("Unknown error"); 70 } 71 } 72 73 struct memory_type_list * 74 memstat_mtl_alloc(void) 75 { 76 struct memory_type_list *mtlp; 77 78 mtlp = malloc(sizeof(*mtlp)); 79 if (mtlp == NULL) 80 return (NULL); 81 82 LIST_INIT(&mtlp->mtl_list); 83 mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED; 84 return (mtlp); 85 } 86 87 struct memory_type * 88 memstat_mtl_first(struct memory_type_list *list) 89 { 90 91 return (LIST_FIRST(&list->mtl_list)); 92 } 93 94 struct memory_type * 95 memstat_mtl_next(struct memory_type *mtp) 96 { 97 98 return (LIST_NEXT(mtp, mt_list)); 99 } 100 101 void 102 _memstat_mtl_empty(struct memory_type_list *list) 103 { 104 struct memory_type *mtp; 105 106 while ((mtp = LIST_FIRST(&list->mtl_list))) { 107 free(mtp->mt_percpu_alloc); 108 free(mtp->mt_percpu_cache); 109 LIST_REMOVE(mtp, mt_list); 110 free(mtp); 111 } 112 } 113 114 void 115 memstat_mtl_free(struct memory_type_list *list) 116 { 117 118 _memstat_mtl_empty(list); 119 free(list); 120 } 121 122 int 123 memstat_mtl_geterror(struct memory_type_list *list) 124 { 125 126 return (list->mtl_error); 127 } 128 129 /* 130 * Look for an existing memory_type entry in a memory_type list, based on the 131 * allocator and name of the type. If not found, return NULL. No errno or 132 * memstat error. 133 */ 134 struct memory_type * 135 memstat_mtl_find(struct memory_type_list *list, int allocator, 136 const char *name) 137 { 138 struct memory_type *mtp; 139 140 LIST_FOREACH(mtp, &list->mtl_list, mt_list) { 141 if ((mtp->mt_allocator == allocator || 142 allocator == ALLOCATOR_ANY) && 143 strcmp(mtp->mt_name, name) == 0) 144 return (mtp); 145 } 146 return (NULL); 147 } 148 149 /* 150 * Allocate a new memory_type with the specificed allocator type and name, 151 * then insert into the list. The structure will be zero'd. 152 * 153 * libmemstat(3) internal function. 154 */ 155 struct memory_type * 156 _memstat_mt_allocate(struct memory_type_list *list, int allocator, 157 const char *name, int maxcpus) 158 { 159 struct memory_type *mtp; 160 161 mtp = malloc(sizeof(*mtp)); 162 if (mtp == NULL) 163 return (NULL); 164 165 bzero(mtp, sizeof(*mtp)); 166 167 mtp->mt_allocator = allocator; 168 mtp->mt_percpu_alloc = malloc(sizeof(struct mt_percpu_alloc_s) * 169 maxcpus); 170 mtp->mt_percpu_cache = malloc(sizeof(struct mt_percpu_cache_s) * 171 maxcpus); 172 strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME); 173 LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list); 174 return (mtp); 175 } 176 177 /* 178 * Reset any libmemstat(3)-owned statistics in a memory_type record so that 179 * it can be reused without incremental addition problems. Caller-owned 180 * memory is left "as-is", and must be updated by the caller if desired. 181 * 182 * libmemstat(3) internal function. 183 */ 184 void 185 _memstat_mt_reset_stats(struct memory_type *mtp, int maxcpus) 186 { 187 int i; 188 189 mtp->mt_countlimit = 0; 190 mtp->mt_byteslimit = 0; 191 mtp->mt_sizemask = 0; 192 mtp->mt_size = 0; 193 194 mtp->mt_memalloced = 0; 195 mtp->mt_memfreed = 0; 196 mtp->mt_numallocs = 0; 197 mtp->mt_numfrees = 0; 198 mtp->mt_bytes = 0; 199 mtp->mt_count = 0; 200 mtp->mt_free = 0; 201 mtp->mt_failures = 0; 202 mtp->mt_sleeps = 0; 203 204 mtp->mt_zonefree = 0; 205 mtp->mt_kegfree = 0; 206 207 for (i = 0; i < maxcpus; i++) { 208 mtp->mt_percpu_alloc[i].mtp_memalloced = 0; 209 mtp->mt_percpu_alloc[i].mtp_memfreed = 0; 210 mtp->mt_percpu_alloc[i].mtp_numallocs = 0; 211 mtp->mt_percpu_alloc[i].mtp_numfrees = 0; 212 mtp->mt_percpu_alloc[i].mtp_sizemask = 0; 213 mtp->mt_percpu_cache[i].mtp_free = 0; 214 } 215 } 216 217 /* 218 * Accessor methods for struct memory_type. Avoids encoding the structure 219 * ABI into the application. 220 */ 221 const char * 222 memstat_get_name(const struct memory_type *mtp) 223 { 224 225 return (mtp->mt_name); 226 } 227 228 int 229 memstat_get_allocator(const struct memory_type *mtp) 230 { 231 232 return (mtp->mt_allocator); 233 } 234 235 uint64_t 236 memstat_get_countlimit(const struct memory_type *mtp) 237 { 238 239 return (mtp->mt_countlimit); 240 } 241 242 uint64_t 243 memstat_get_byteslimit(const struct memory_type *mtp) 244 { 245 246 return (mtp->mt_byteslimit); 247 } 248 249 uint64_t 250 memstat_get_sizemask(const struct memory_type *mtp) 251 { 252 253 return (mtp->mt_sizemask); 254 } 255 256 uint64_t 257 memstat_get_size(const struct memory_type *mtp) 258 { 259 260 return (mtp->mt_size); 261 } 262 263 uint64_t 264 memstat_get_rsize(const struct memory_type *mtp) 265 { 266 267 return (mtp->mt_rsize); 268 } 269 270 uint64_t 271 memstat_get_memalloced(const struct memory_type *mtp) 272 { 273 274 return (mtp->mt_memalloced); 275 } 276 277 uint64_t 278 memstat_get_memfreed(const struct memory_type *mtp) 279 { 280 281 return (mtp->mt_memfreed); 282 } 283 284 uint64_t 285 memstat_get_numallocs(const struct memory_type *mtp) 286 { 287 288 return (mtp->mt_numallocs); 289 } 290 291 uint64_t 292 memstat_get_numfrees(const struct memory_type *mtp) 293 { 294 295 return (mtp->mt_numfrees); 296 } 297 298 uint64_t 299 memstat_get_bytes(const struct memory_type *mtp) 300 { 301 302 return (mtp->mt_bytes); 303 } 304 305 uint64_t 306 memstat_get_count(const struct memory_type *mtp) 307 { 308 309 return (mtp->mt_count); 310 } 311 312 uint64_t 313 memstat_get_free(const struct memory_type *mtp) 314 { 315 316 return (mtp->mt_free); 317 } 318 319 uint64_t 320 memstat_get_failures(const struct memory_type *mtp) 321 { 322 323 return (mtp->mt_failures); 324 } 325 326 uint64_t 327 memstat_get_sleeps(const struct memory_type *mtp) 328 { 329 330 return (mtp->mt_sleeps); 331 } 332 333 uint64_t 334 memstat_get_xdomain(const struct memory_type *mtp) 335 { 336 337 return (mtp->mt_xdomain); 338 } 339 340 void * 341 memstat_get_caller_pointer(const struct memory_type *mtp, int index) 342 { 343 344 return (mtp->mt_caller_pointer[index]); 345 } 346 347 void 348 memstat_set_caller_pointer(struct memory_type *mtp, int index, void *value) 349 { 350 351 mtp->mt_caller_pointer[index] = value; 352 } 353 354 uint64_t 355 memstat_get_caller_uint64(const struct memory_type *mtp, int index) 356 { 357 358 return (mtp->mt_caller_uint64[index]); 359 } 360 361 void 362 memstat_set_caller_uint64(struct memory_type *mtp, int index, uint64_t value) 363 { 364 365 mtp->mt_caller_uint64[index] = value; 366 } 367 368 uint64_t 369 memstat_get_zonefree(const struct memory_type *mtp) 370 { 371 372 return (mtp->mt_zonefree); 373 } 374 375 uint64_t 376 memstat_get_kegfree(const struct memory_type *mtp) 377 { 378 379 return (mtp->mt_kegfree); 380 } 381 382 uint64_t 383 memstat_get_percpu_memalloced(const struct memory_type *mtp, int cpu) 384 { 385 386 return (mtp->mt_percpu_alloc[cpu].mtp_memalloced); 387 } 388 389 uint64_t 390 memstat_get_percpu_memfreed(const struct memory_type *mtp, int cpu) 391 { 392 393 return (mtp->mt_percpu_alloc[cpu].mtp_memfreed); 394 } 395 396 uint64_t 397 memstat_get_percpu_numallocs(const struct memory_type *mtp, int cpu) 398 { 399 400 return (mtp->mt_percpu_alloc[cpu].mtp_numallocs); 401 } 402 403 uint64_t 404 memstat_get_percpu_numfrees(const struct memory_type *mtp, int cpu) 405 { 406 407 return (mtp->mt_percpu_alloc[cpu].mtp_numfrees); 408 } 409 410 uint64_t 411 memstat_get_percpu_sizemask(const struct memory_type *mtp, int cpu) 412 { 413 414 return (mtp->mt_percpu_alloc[cpu].mtp_sizemask); 415 } 416 417 void * 418 memstat_get_percpu_caller_pointer(const struct memory_type *mtp, int cpu, 419 int index) 420 { 421 422 return (mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index]); 423 } 424 425 void 426 memstat_set_percpu_caller_pointer(struct memory_type *mtp, int cpu, 427 int index, void *value) 428 { 429 430 mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index] = value; 431 } 432 433 uint64_t 434 memstat_get_percpu_caller_uint64(const struct memory_type *mtp, int cpu, 435 int index) 436 { 437 438 return (mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index]); 439 } 440 441 void 442 memstat_set_percpu_caller_uint64(struct memory_type *mtp, int cpu, int index, 443 uint64_t value) 444 { 445 446 mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index] = value; 447 } 448 449 uint64_t 450 memstat_get_percpu_free(const struct memory_type *mtp, int cpu) 451 { 452 453 return (mtp->mt_percpu_cache[cpu].mtp_free); 454 } 455