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