memstat_malloc.c (148619) | memstat_malloc.c (148789) |
---|---|
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 unchanged lines hidden (view full) --- 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 * | 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 unchanged lines hidden (view full) --- 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: head/lib/libmemstat/memstat_malloc.c 148619 2005-08-01 13:18:21Z rwatson $ | 26 * $FreeBSD: head/lib/libmemstat/memstat_malloc.c 148789 2005-08-06 13:54:03Z rwatson $ |
27 */ 28 29#include <sys/param.h> 30#include <sys/malloc.h> 31#include <sys/sysctl.h> 32 33#include <err.h> 34#include <errno.h> | 27 */ 28 29#include <sys/param.h> 30#include <sys/malloc.h> 31#include <sys/sysctl.h> 32 33#include <err.h> 34#include <errno.h> |
35#include <kvm.h> 36#include <nlist.h> |
|
35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38 39#include "memstat.h" 40#include "memstat_internal.h" 41 | 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40 41#include "memstat.h" 42#include "memstat_internal.h" 43 |
44static struct nlist namelist[] = { 45#define X_KMEMSTATISTICS 0 46 { .n_name = "_kmemstatistics" }, 47#define X_MP_MAXCPUS 1 48 { .n_name = "_mp_maxcpus" }, 49 { .n_name = "" }, 50}; 51 |
|
42/* 43 * Extract malloc(9) statistics from the running kernel, and store all memory 44 * type information in the passed list. For each type, check the list for an 45 * existing entry with the right name/allocator -- if present, update that 46 * entry. Otherwise, add a new entry. On error, the entire list will be 47 * cleared, as entries will be in an inconsistent state. 48 * 49 * To reduce the level of work for a list that starts empty, we keep around a --- 171 unchanged lines hidden (view full) --- 221 mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 222 mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 223 } 224 225 free(buffer); 226 227 return (0); 228} | 52/* 53 * Extract malloc(9) statistics from the running kernel, and store all memory 54 * type information in the passed list. For each type, check the list for an 55 * existing entry with the right name/allocator -- if present, update that 56 * entry. Otherwise, add a new entry. On error, the entire list will be 57 * cleared, as entries will be in an inconsistent state. 58 * 59 * To reduce the level of work for a list that starts empty, we keep around a --- 171 unchanged lines hidden (view full) --- 231 mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 232 mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 233 } 234 235 free(buffer); 236 237 return (0); 238} |
239 240static int 241kread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size, 242 size_t offset) 243{ 244 ssize_t ret; 245 246 ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address, 247 size); 248 if (ret < 0) 249 return (MEMSTAT_ERROR_KVM); 250 if ((size_t)ret != size) 251 return (MEMSTAT_ERROR_KVM_SHORTREAD); 252 return (0); 253} 254 255static int 256kread_string(kvm_t *kvm, void *kvm_pointer, char *buffer, int buflen) 257{ 258 ssize_t ret; 259 int i; 260 261 for (i = 0; i < buflen; i++) { 262 ret = kvm_read(kvm, (unsigned long)kvm_pointer + i, 263 &(buffer[i]), sizeof(char)); 264 if (ret < 0) 265 return (MEMSTAT_ERROR_KVM); 266 if ((size_t)ret != sizeof(char)) 267 return (MEMSTAT_ERROR_KVM_SHORTREAD); 268 if (buffer[i] == '\0') 269 return (0); 270 } 271 /* Truncate. */ 272 buffer[i-1] = '\0'; 273 return (0); 274} 275 276static int 277kread_symbol(kvm_t *kvm, int index, void *address, size_t size, 278 size_t offset) 279{ 280 ssize_t ret; 281 282 ret = kvm_read(kvm, namelist[index].n_value + offset, address, size); 283 if (ret < 0) 284 return (MEMSTAT_ERROR_KVM); 285 if ((size_t)ret != size) 286 return (MEMSTAT_ERROR_KVM_SHORTREAD); 287 return (0); 288} 289 290int 291memstat_kvm_malloc(struct memory_type_list *list, void *kvm_handle) 292{ 293 struct memory_type *mtp; 294 void *kmemstatistics; 295 int hint_dontsearch, j, mp_maxcpus, ret; 296 char name[MEMTYPE_MAXNAME]; 297 struct malloc_type_stats mts[MEMSTAT_MAXCPU], *mtsp; 298 struct malloc_type type, *typep; 299 kvm_t *kvm; 300 301 kvm = (kvm_t *)kvm_handle; 302 303 hint_dontsearch = LIST_EMPTY(&list->mtl_list); 304 305 if (kvm_nlist(kvm, namelist) != 0) { 306 list->mtl_error = MEMSTAT_ERROR_KVM; 307 return (-1); 308 } 309 310 if (namelist[X_KMEMSTATISTICS].n_type == 0 || 311 namelist[X_KMEMSTATISTICS].n_value == 0) { 312 list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL; 313 return (-1); 314 } 315 316 ret = kread_symbol(kvm, X_MP_MAXCPUS, &mp_maxcpus, 317 sizeof(mp_maxcpus), 0); 318 if (ret != 0) { 319 list->mtl_error = ret; 320 return (-1); 321 } 322 323 if (mp_maxcpus > MEMSTAT_MAXCPU) { 324 list->mtl_error = MEMSTAT_ERROR_TOOMANYCPUS; 325 return (-1); 326 } 327 328 ret = kread_symbol(kvm, X_KMEMSTATISTICS, &kmemstatistics, 329 sizeof(kmemstatistics), 0); 330 if (ret != 0) { 331 list->mtl_error = ret; 332 return (-1); 333 } 334 335 for (typep = kmemstatistics; typep != NULL; typep = type.ks_next) { 336 ret = kread(kvm, typep, &type, sizeof(type), 0); 337 if (ret != 0) { 338 _memstat_mtl_empty(list); 339 list->mtl_error = ret; 340 return (-1); 341 } 342 ret = kread_string(kvm, (void *)type.ks_shortdesc, name, 343 MEMTYPE_MAXNAME); 344 if (ret != 0) { 345 _memstat_mtl_empty(list); 346 list->mtl_error = ret; 347 return (-1); 348 } 349 350 /* 351 * Take advantage of explicit knowledge that 352 * malloc_type_internal is simply an array of statistics 353 * structures of number MAXCPU. Since our compile-time 354 * value for MAXCPU may differ from the kernel's, we 355 * populate our own array. 356 */ 357 ret = kread(kvm, type.ks_handle, mts, mp_maxcpus * 358 sizeof(struct malloc_type_stats), 0); 359 if (ret != 0) { 360 _memstat_mtl_empty(list); 361 list->mtl_error = ret; 362 return (-1); 363 } 364 365 if (hint_dontsearch == 0) { 366 mtp = memstat_mtl_find(list, ALLOCATOR_MALLOC, name); 367 } else 368 mtp = NULL; 369 if (mtp == NULL) 370 mtp = _memstat_mt_allocate(list, ALLOCATOR_MALLOC, 371 name); 372 if (mtp == NULL) { 373 _memstat_mtl_empty(list); 374 list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 375 return (-1); 376 } 377 378 /* 379 * This logic is replicated from kern_malloc.c, and should 380 * be kept in sync. 381 */ 382 _memstat_mt_reset_stats(mtp); 383 for (j = 0; j < mp_maxcpus; j++) { 384 mtsp = &mts[j]; 385 mtp->mt_memalloced += mtsp->mts_memalloced; 386 mtp->mt_memfreed += mtsp->mts_memfreed; 387 mtp->mt_numallocs += mtsp->mts_numallocs; 388 mtp->mt_numfrees += mtsp->mts_numfrees; 389 mtp->mt_sizemask |= mtsp->mts_size; 390 391 mtp->mt_percpu_alloc[j].mtp_memalloced = 392 mtsp->mts_memalloced; 393 mtp->mt_percpu_alloc[j].mtp_memfreed = 394 mtsp->mts_memfreed; 395 mtp->mt_percpu_alloc[j].mtp_numallocs = 396 mtsp->mts_numallocs; 397 mtp->mt_percpu_alloc[j].mtp_numfrees = 398 mtsp->mts_numfrees; 399 mtp->mt_percpu_alloc[j].mtp_sizemask = 400 mtsp->mts_size; 401 } 402 403 mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 404 mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 405 } 406 407 return (0); 408} |
|