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