memstat.c revision 148627
12726Sjlahoda/*- 22726Sjlahoda * Copyright (c) 2005 Robert N. M. Watson 32726Sjlahoda * All rights reserved. 42726Sjlahoda * 52726Sjlahoda * Redistribution and use in source and binary forms, with or without 62726Sjlahoda * modification, are permitted provided that the following conditions 72726Sjlahoda * are met: 82726Sjlahoda * 1. Redistributions of source code must retain the above copyright 92726Sjlahoda * notice, this list of conditions and the following disclaimer. 102726Sjlahoda * 2. Redistributions in binary form must reproduce the above copyright 112726Sjlahoda * notice, this list of conditions and the following disclaimer in the 122726Sjlahoda * documentation and/or other materials provided with the distribution. 132726Sjlahoda * 142726Sjlahoda * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152726Sjlahoda * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162726Sjlahoda * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172726Sjlahoda * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182726Sjlahoda * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192726Sjlahoda * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202726Sjlahoda * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212726Sjlahoda * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222726Sjlahoda * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232726Sjlahoda * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242726Sjlahoda * SUCH DAMAGE. 252726Sjlahoda * 262726Sjlahoda * $FreeBSD: head/lib/libmemstat/memstat.c 148627 2005-08-01 19:07:39Z rwatson $ 272726Sjlahoda */ 282726Sjlahoda 292726Sjlahoda#include <sys/param.h> 302726Sjlahoda#include <sys/sysctl.h> 312726Sjlahoda 322726Sjlahoda#include <err.h> 332726Sjlahoda#include <errno.h> 342726Sjlahoda#include <stdio.h> 352726Sjlahoda#include <stdlib.h> 362726Sjlahoda#include <string.h> 372726Sjlahoda 382726Sjlahoda#include "memstat.h" 392726Sjlahoda#include "memstat_internal.h" 403160Sjlahoda 413160Sjlahodaconst char * 423160Sjlahodamemstat_strerror(int error) 433160Sjlahoda{ 443160Sjlahoda 453160Sjlahoda switch (error) { 463160Sjlahoda case MEMSTAT_ERROR_NOMEMORY: 473160Sjlahoda return ("Cannot allocate memory"); 483160Sjlahoda case MEMSTAT_ERROR_VERSION: 493160Sjlahoda return ("Version mismatch"); 503160Sjlahoda case MEMSTAT_ERROR_PERMISSION: 513160Sjlahoda return ("Permission denied"); 523160Sjlahoda case MEMSTAT_ERROR_TOOMANYCPUS: 533160Sjlahoda return ("Too many CPUs"); 543160Sjlahoda case MEMSTAT_ERROR_DATAERROR: 553160Sjlahoda return ("Data format error"); 563160Sjlahoda case MEMSTAT_ERROR_KVM: 573160Sjlahoda return ("KVM error"); 583160Sjlahoda case MEMSTAT_ERROR_KVM_NOSYMBOL: 593160Sjlahoda return ("KVM unable to find symbol"); 603160Sjlahoda case MEMSTAT_ERROR_KVM_SHORTREAD: 613160Sjlahoda return ("KVM short read"); 623160Sjlahoda case MEMSTAT_ERROR_UNDEFINED: 633160Sjlahoda default: 643160Sjlahoda return ("Unknown error"); 653160Sjlahoda } 663160Sjlahoda} 673160Sjlahoda 683160Sjlahodastruct memory_type_list * 693160Sjlahodamemstat_mtl_alloc(void) 703160Sjlahoda{ 713160Sjlahoda struct memory_type_list *mtlp; 723160Sjlahoda 733160Sjlahoda mtlp = malloc(sizeof(*mtlp)); 743160Sjlahoda if (mtlp == NULL) 753160Sjlahoda return (NULL); 763160Sjlahoda 773160Sjlahoda LIST_INIT(&mtlp->mtl_list); 783160Sjlahoda mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED; 793160Sjlahoda return (mtlp); 803160Sjlahoda} 813160Sjlahoda 823160Sjlahodastruct memory_type * 832726Sjlahodamemstat_mtl_first(struct memory_type_list *list) 842726Sjlahoda{ 852726Sjlahoda 862726Sjlahoda return (LIST_FIRST(&list->mtl_list)); 872726Sjlahoda} 882726Sjlahoda 892726Sjlahodastruct memory_type * 902726Sjlahodamemstat_mtl_next(struct memory_type *mtp) 912726Sjlahoda{ 922726Sjlahoda 932726Sjlahoda return (LIST_NEXT(mtp, mt_list)); 942726Sjlahoda} 952726Sjlahoda 962726Sjlahodavoid 972726Sjlahoda_memstat_mtl_empty(struct memory_type_list *list) 982726Sjlahoda{ 992726Sjlahoda struct memory_type *mtp; 1002726Sjlahoda 1012726Sjlahoda while ((mtp = LIST_FIRST(&list->mtl_list))) { 1022726Sjlahoda LIST_REMOVE(mtp, mt_list); 1032726Sjlahoda free(mtp); 1042726Sjlahoda } 1052726Sjlahoda} 1062726Sjlahoda 1072726Sjlahodavoid 1082726Sjlahodamemstat_mtl_free(struct memory_type_list *list) 1092726Sjlahoda{ 1102726Sjlahoda 1112726Sjlahoda _memstat_mtl_empty(list); 1123160Sjlahoda free(list); 1133160Sjlahoda} 1143160Sjlahoda 1153160Sjlahodaint 1163160Sjlahodamemstat_mtl_geterror(struct memory_type_list *list) 1173160Sjlahoda{ 1183160Sjlahoda 1193160Sjlahoda return (list->mtl_error); 1203160Sjlahoda} 1212726Sjlahoda 122/* 123 * Look for an existing memory_type entry in a memory_type list, based on the 124 * allocator and name of the type. If not found, return NULL. No errno or 125 * memstat error. 126 */ 127struct memory_type * 128memstat_mtl_find(struct memory_type_list *list, int allocator, 129 const char *name) 130{ 131 struct memory_type *mtp; 132 133 LIST_FOREACH(mtp, &list->mtl_list, mt_list) { 134 if ((mtp->mt_allocator == allocator || 135 allocator == ALLOCATOR_ANY) && 136 strcmp(mtp->mt_name, name) == 0) 137 return (mtp); 138 } 139 return (NULL); 140} 141 142/* 143 * Allocate a new memory_type with the specificed allocator type and name, 144 * then insert into the list. The structure will be zero'd. 145 * 146 * libmemstat(3) internal function. 147 */ 148struct memory_type * 149_memstat_mt_allocate(struct memory_type_list *list, int allocator, 150 const char *name) 151{ 152 struct memory_type *mtp; 153 154 mtp = malloc(sizeof(*mtp)); 155 if (mtp == NULL) 156 return (NULL); 157 158 bzero(mtp, sizeof(*mtp)); 159 160 mtp->mt_allocator = allocator; 161 strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME); 162 LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list); 163 return (mtp); 164} 165 166/* 167 * Reset any libmemstat(3)-owned statistics in a memory_type record so that 168 * it can be reused without incremental addition problems. Caller-owned 169 * memory is left "as-is", and must be updated by the caller if desired. 170 * 171 * libmemstat(3) internal function. 172 */ 173void 174_memstat_mt_reset_stats(struct memory_type *mtp) 175{ 176 int i; 177 178 mtp->mt_countlimit = 0; 179 mtp->mt_byteslimit = 0; 180 mtp->mt_sizemask = 0; 181 mtp->mt_size = 0; 182 183 mtp->mt_memalloced = 0; 184 mtp->mt_memfreed = 0; 185 mtp->mt_numallocs = 0; 186 mtp->mt_numfrees = 0; 187 mtp->mt_bytes = 0; 188 mtp->mt_count = 0; 189 mtp->mt_free = 0; 190 mtp->mt_failures = 0; 191 192 mtp->mt_zonefree = 0; 193 mtp->mt_kegfree = 0; 194 195 for (i = 0; i < MEMSTAT_MAXCPU; i++) { 196 mtp->mt_percpu_alloc[i].mtp_memalloced = 0; 197 mtp->mt_percpu_alloc[i].mtp_memfreed = 0; 198 mtp->mt_percpu_alloc[i].mtp_numallocs = 0; 199 mtp->mt_percpu_alloc[i].mtp_numfrees = 0; 200 mtp->mt_percpu_alloc[i].mtp_sizemask = 0; 201 mtp->mt_percpu_cache[i].mtp_free = 0; 202 } 203} 204 205/* 206 * Accessor methods for struct memory_type. Avoids encoding the structure 207 * ABI into the application. 208 */ 209const char * 210memstat_get_name(const struct memory_type *mtp) 211{ 212 213 return (mtp->mt_name); 214} 215 216int 217memstat_get_allocator(const struct memory_type *mtp) 218{ 219 220 return (mtp->mt_allocator); 221} 222 223uint64_t 224memstat_get_countlimit(const struct memory_type *mtp) 225{ 226 227 return (mtp->mt_countlimit); 228} 229 230uint64_t 231memstat_get_byteslimit(const struct memory_type *mtp) 232{ 233 234 return (mtp->mt_byteslimit); 235} 236 237uint64_t 238memstat_get_sizemask(const struct memory_type *mtp) 239{ 240 241 return (mtp->mt_sizemask); 242} 243 244uint64_t 245memstat_get_size(const struct memory_type *mtp) 246{ 247 248 return (mtp->mt_size); 249} 250 251uint64_t 252memstat_get_memalloced(const struct memory_type *mtp) 253{ 254 255 return (mtp->mt_memalloced); 256} 257 258uint64_t 259memstat_get_memfreed(const struct memory_type *mtp) 260{ 261 262 return (mtp->mt_memfreed); 263} 264 265uint64_t 266memstat_get_numallocs(const struct memory_type *mtp) 267{ 268 269 return (mtp->mt_numallocs); 270} 271 272uint64_t 273memstat_get_numfrees(const struct memory_type *mtp) 274{ 275 276 return (mtp->mt_numfrees); 277} 278 279uint64_t 280memstat_get_bytes(const struct memory_type *mtp) 281{ 282 283 return (mtp->mt_bytes); 284} 285 286uint64_t 287memstat_get_count(const struct memory_type *mtp) 288{ 289 290 return (mtp->mt_count); 291} 292 293uint64_t 294memstat_get_free(const struct memory_type *mtp) 295{ 296 297 return (mtp->mt_free); 298} 299 300uint64_t 301memstat_get_failures(const struct memory_type *mtp) 302{ 303 304 return (mtp->mt_failures); 305} 306 307void * 308memstat_get_caller_pointer(const struct memory_type *mtp, int index) 309{ 310 311 return (mtp->mt_caller_pointer[index]); 312} 313 314void 315memstat_set_caller_pointer(struct memory_type *mtp, int index, void *value) 316{ 317 318 mtp->mt_caller_pointer[index] = value; 319} 320 321uint64_t 322memstat_get_caller_uint64(const struct memory_type *mtp, int index) 323{ 324 325 return (mtp->mt_caller_uint64[index]); 326} 327 328void 329memstat_set_caller_uint64(struct memory_type *mtp, int index, uint64_t value) 330{ 331 332 mtp->mt_caller_uint64[index] = value; 333} 334 335uint64_t 336memstat_get_zonefree(const struct memory_type *mtp) 337{ 338 339 return (mtp->mt_zonefree); 340} 341 342uint64_t 343memstat_get_kegfree(const struct memory_type *mtp) 344{ 345 346 return (mtp->mt_kegfree); 347} 348 349uint64_t 350memstat_get_percpu_memalloced(const struct memory_type *mtp, int cpu) 351{ 352 353 return (mtp->mt_percpu_alloc[cpu].mtp_memalloced); 354} 355 356uint64_t 357memstat_get_percpu_memfreed(const struct memory_type *mtp, int cpu) 358{ 359 360 return (mtp->mt_percpu_alloc[cpu].mtp_memfreed); 361} 362 363uint64_t 364memstat_get_percpu_numallocs(const struct memory_type *mtp, int cpu) 365{ 366 367 return (mtp->mt_percpu_alloc[cpu].mtp_numallocs); 368} 369 370uint64_t 371memstat_get_percpu_numfrees(const struct memory_type *mtp, int cpu) 372{ 373 374 return (mtp->mt_percpu_alloc[cpu].mtp_numfrees); 375} 376 377uint64_t 378memstat_get_percpu_sizemask(const struct memory_type *mtp, int cpu) 379{ 380 381 return (mtp->mt_percpu_alloc[cpu].mtp_sizemask); 382} 383 384void * 385memstat_get_percpu_caller_pointer(const struct memory_type *mtp, int cpu, 386 int index) 387{ 388 389 return (mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index]); 390} 391 392void 393memstat_set_percpu_caller_pointer(struct memory_type *mtp, int cpu, 394 int index, void *value) 395{ 396 397 mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index] = value; 398} 399 400uint64_t 401memstat_get_percpu_caller_uint64(const struct memory_type *mtp, int cpu, 402 int index) 403{ 404 405 return (mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index]); 406} 407 408void 409memstat_set_percpu_caller_uint64(struct memory_type *mtp, int cpu, int index, 410 uint64_t value) 411{ 412 413 mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index] = value; 414} 415 416uint64_t 417memstat_get_percpu_free(const struct memory_type *mtp, int cpu) 418{ 419 420 return (mtp->mt_percpu_cache[cpu].mtp_free); 421} 422