Deleted Added
full compact
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}