memstat.c revision 261726
1170530Ssam/*-
2178354Ssam * Copyright (c) 2005 Robert N. M. Watson
3170530Ssam * All rights reserved.
4170530Ssam *
5170530Ssam * Redistribution and use in source and binary forms, with or without
6170530Ssam * modification, are permitted provided that the following conditions
7170530Ssam * are met:
8170530Ssam * 1. Redistributions of source code must retain the above copyright
9170530Ssam *    notice, this list of conditions and the following disclaimer.
10170530Ssam * 2. Redistributions in binary form must reproduce the above copyright
11170530Ssam *    notice, this list of conditions and the following disclaimer in the
12170530Ssam *    documentation and/or other materials provided with the distribution.
13170530Ssam *
14170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15170530Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16170530Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17170530Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18170530Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19170530Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20170530Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21170530Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22170530Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23170530Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24170530Ssam * SUCH DAMAGE.
25170530Ssam *
26170530Ssam * $FreeBSD: head/lib/libmemstat/memstat.c 261726 2014-02-10 20:09:10Z glebius $
27170530Ssam */
28170530Ssam
29170530Ssam#include <sys/param.h>
30170530Ssam#include <sys/sysctl.h>
31170530Ssam
32178354Ssam#include <err.h>
33178354Ssam#include <errno.h>
34170530Ssam#include <stdio.h>
35170530Ssam#include <stdlib.h>
36170530Ssam#include <string.h>
37170530Ssam
38170530Ssam#include "memstat.h"
39170530Ssam#include "memstat_internal.h"
40170530Ssam
41170530Ssamconst char *
42170530Ssammemstat_strerror(int error)
43170530Ssam{
44170530Ssam
45170530Ssam	switch (error) {
46170530Ssam	case MEMSTAT_ERROR_NOMEMORY:
47170530Ssam		return ("Cannot allocate memory");
48178354Ssam	case MEMSTAT_ERROR_VERSION:
49178354Ssam		return ("Version mismatch");
50170530Ssam	case MEMSTAT_ERROR_PERMISSION:
51227293Sed		return ("Permission denied");
52178354Ssam	case MEMSTAT_ERROR_DATAERROR:
53170530Ssam		return ("Data format error");
54170530Ssam	case MEMSTAT_ERROR_KVM:
55170530Ssam		return ("KVM error");
56178354Ssam	case MEMSTAT_ERROR_KVM_NOSYMBOL:
57178354Ssam		return ("KVM unable to find symbol");
58178354Ssam	case MEMSTAT_ERROR_KVM_SHORTREAD:
59178354Ssam		return ("KVM short read");
60178354Ssam	case MEMSTAT_ERROR_UNDEFINED:
61178354Ssam	default:
62178354Ssam		return ("Unknown error");
63178354Ssam	}
64178354Ssam}
65178354Ssam
66178354Ssamstruct memory_type_list *
67178354Ssammemstat_mtl_alloc(void)
68170530Ssam{
69178354Ssam	struct memory_type_list *mtlp;
70178354Ssam
71170530Ssam	mtlp = malloc(sizeof(*mtlp));
72241138Sadrian	if (mtlp == NULL)
73241138Sadrian		return (NULL);
74170530Ssam
75170530Ssam	LIST_INIT(&mtlp->mtl_list);
76170530Ssam	mtlp->mtl_error = MEMSTAT_ERROR_UNDEFINED;
77178354Ssam	return (mtlp);
78170530Ssam}
79170530Ssam
80170530Ssamstruct memory_type *
81170530Ssammemstat_mtl_first(struct memory_type_list *list)
82170530Ssam{
83178354Ssam
84178354Ssam	return (LIST_FIRST(&list->mtl_list));
85186302Ssam}
86178354Ssam
87178354Ssamstruct memory_type *
88170530Ssammemstat_mtl_next(struct memory_type *mtp)
89170530Ssam{
90178354Ssam
91170530Ssam	return (LIST_NEXT(mtp, mt_list));
92170530Ssam}
93170530Ssam
94170530Ssamvoid
95170530Ssam_memstat_mtl_empty(struct memory_type_list *list)
96178354Ssam{
97170530Ssam	struct memory_type *mtp;
98178354Ssam
99186302Ssam	while ((mtp = LIST_FIRST(&list->mtl_list))) {
100178354Ssam		free(mtp->mt_percpu_alloc);
101170530Ssam		free(mtp->mt_percpu_cache);
102170530Ssam		LIST_REMOVE(mtp, mt_list);
103170530Ssam		free(mtp);
104184288Ssam	}
105184288Ssam}
106184288Ssam
107223842Skevlovoid
108184288Ssammemstat_mtl_free(struct memory_type_list *list)
109184288Ssam{
110184288Ssam
111184288Ssam	_memstat_mtl_empty(list);
112184288Ssam	free(list);
113184288Ssam}
114184288Ssam
115184288Ssamint
116184288Ssammemstat_mtl_geterror(struct memory_type_list *list)
117184288Ssam{
118184288Ssam
119184288Ssam	return (list->mtl_error);
120184288Ssam}
121184288Ssam
122184288Ssam/*
123170530Ssam * Look for an existing memory_type entry in a memory_type list, based on the
124184288Ssam * allocator and name of the type.  If not found, return NULL.  No errno or
125184288Ssam * memstat error.
126184288Ssam */
127184288Ssamstruct memory_type *
128184288Ssammemstat_mtl_find(struct memory_type_list *list, int allocator,
129184288Ssam    const char *name)
130184288Ssam{
131184288Ssam	struct memory_type *mtp;
132184288Ssam
133184288Ssam	LIST_FOREACH(mtp, &list->mtl_list, mt_list) {
134184288Ssam		if ((mtp->mt_allocator == allocator ||
135184288Ssam		    allocator == ALLOCATOR_ANY) &&
136184288Ssam		    strcmp(mtp->mt_name, name) == 0)
137184288Ssam			return (mtp);
138184288Ssam	}
139184288Ssam	return (NULL);
140184288Ssam}
141184288Ssam
142184288Ssam/*
143184288Ssam * Allocate a new memory_type with the specificed allocator type and name,
144184288Ssam * then insert into the list.  The structure will be zero'd.
145184288Ssam *
146184288Ssam * libmemstat(3) internal function.
147184288Ssam */
148184288Ssamstruct memory_type *
149184288Ssam_memstat_mt_allocate(struct memory_type_list *list, int allocator,
150184288Ssam    const char *name, int maxcpus)
151184288Ssam{
152184288Ssam	struct memory_type *mtp;
153184288Ssam
154184288Ssam	mtp = malloc(sizeof(*mtp));
155184288Ssam	if (mtp == NULL)
156184288Ssam		return (NULL);
157184288Ssam
158184288Ssam	bzero(mtp, sizeof(*mtp));
159184288Ssam
160184288Ssam	mtp->mt_allocator = allocator;
161184288Ssam	mtp->mt_percpu_alloc = malloc(sizeof(struct mt_percpu_alloc_s) *
162184288Ssam	    maxcpus);
163184288Ssam	mtp->mt_percpu_cache = malloc(sizeof(struct mt_percpu_cache_s) *
164184288Ssam	    maxcpus);
165184288Ssam	strlcpy(mtp->mt_name, name, MEMTYPE_MAXNAME);
166184288Ssam	LIST_INSERT_HEAD(&list->mtl_list, mtp, mt_list);
167184288Ssam	return (mtp);
168184288Ssam}
169184288Ssam
170184288Ssam/*
171184288Ssam * Reset any libmemstat(3)-owned statistics in a memory_type record so that
172184288Ssam * it can be reused without incremental addition problems.  Caller-owned
173170530Ssam * memory is left "as-is", and must be updated by the caller if desired.
174170530Ssam *
175184288Ssam * libmemstat(3) internal function.
176184288Ssam */
177170530Ssamvoid
178184288Ssam_memstat_mt_reset_stats(struct memory_type *mtp, int maxcpus)
179184288Ssam{
180170530Ssam	int i;
181170530Ssam
182184288Ssam	mtp->mt_countlimit = 0;
183184288Ssam	mtp->mt_byteslimit = 0;
184184288Ssam	mtp->mt_sizemask = 0;
185184288Ssam	mtp->mt_size = 0;
186184288Ssam
187184288Ssam	mtp->mt_memalloced = 0;
188184288Ssam	mtp->mt_memfreed = 0;
189184288Ssam	mtp->mt_numallocs = 0;
190184288Ssam	mtp->mt_numfrees = 0;
191184288Ssam	mtp->mt_bytes = 0;
192184288Ssam	mtp->mt_count = 0;
193184288Ssam	mtp->mt_free = 0;
194184288Ssam	mtp->mt_failures = 0;
195184288Ssam	mtp->mt_sleeps = 0;
196184288Ssam
197184288Ssam	mtp->mt_zonefree = 0;
198170530Ssam	mtp->mt_kegfree = 0;
199170530Ssam
200170530Ssam	for (i = 0; i < maxcpus; i++) {
201170530Ssam		mtp->mt_percpu_alloc[i].mtp_memalloced = 0;
202170530Ssam		mtp->mt_percpu_alloc[i].mtp_memfreed = 0;
203184288Ssam		mtp->mt_percpu_alloc[i].mtp_numallocs = 0;
204184288Ssam		mtp->mt_percpu_alloc[i].mtp_numfrees = 0;
205184288Ssam		mtp->mt_percpu_alloc[i].mtp_sizemask = 0;
206184288Ssam		mtp->mt_percpu_cache[i].mtp_free = 0;
207184288Ssam	}
208184288Ssam}
209184288Ssam
210184288Ssam/*
211184288Ssam * Accessor methods for struct memory_type.  Avoids encoding the structure
212184288Ssam * ABI into the application.
213170530Ssam */
214170530Ssamconst char *
215170530Ssammemstat_get_name(const struct memory_type *mtp)
216170530Ssam{
217170530Ssam
218170530Ssam	return (mtp->mt_name);
219170530Ssam}
220170530Ssam
221170530Ssamint
222170530Ssammemstat_get_allocator(const struct memory_type *mtp)
223184288Ssam{
224170530Ssam
225184288Ssam	return (mtp->mt_allocator);
226170530Ssam}
227170530Ssam
228184288Ssamuint64_t
229178354Ssammemstat_get_countlimit(const struct memory_type *mtp)
230178354Ssam{
231178354Ssam
232184288Ssam	return (mtp->mt_countlimit);
233170530Ssam}
234170530Ssam
235184288Ssamuint64_t
236184288Ssammemstat_get_byteslimit(const struct memory_type *mtp)
237184288Ssam{
238184288Ssam
239184288Ssam	return (mtp->mt_byteslimit);
240178354Ssam}
241178354Ssam
242184288Ssamuint64_t
243184288Ssammemstat_get_sizemask(const struct memory_type *mtp)
244184288Ssam{
245184288Ssam
246184288Ssam	return (mtp->mt_sizemask);
247184288Ssam}
248184288Ssam
249170530Ssamuint64_t
250170530Ssammemstat_get_size(const struct memory_type *mtp)
251184288Ssam{
252184288Ssam
253184288Ssam	return (mtp->mt_size);
254184288Ssam}
255170530Ssam
256170530Ssamuint64_t
257184288Ssammemstat_get_rsize(const struct memory_type *mtp)
258170530Ssam{
259178354Ssam
260170530Ssam	return (mtp->mt_rsize);
261170530Ssam}
262170530Ssam
263170530Ssamuint64_t
264170530Ssammemstat_get_memalloced(const struct memory_type *mtp)
265170530Ssam{
266170530Ssam
267178354Ssam	return (mtp->mt_memalloced);
268178354Ssam}
269178354Ssam
270178354Ssamuint64_t
271178354Ssammemstat_get_memfreed(const struct memory_type *mtp)
272178354Ssam{
273178354Ssam
274178354Ssam	return (mtp->mt_memfreed);
275178354Ssam}
276178354Ssam
277178354Ssamuint64_t
278178354Ssammemstat_get_numallocs(const struct memory_type *mtp)
279170530Ssam{
280170530Ssam
281178354Ssam	return (mtp->mt_numallocs);
282170530Ssam}
283170530Ssam
284178354Ssamuint64_t
285170530Ssammemstat_get_numfrees(const struct memory_type *mtp)
286170530Ssam{
287178354Ssam
288170530Ssam	return (mtp->mt_numfrees);
289178354Ssam}
290178354Ssam
291178354Ssamuint64_t
292170530Ssammemstat_get_bytes(const struct memory_type *mtp)
293170530Ssam{
294178354Ssam
295178354Ssam	return (mtp->mt_bytes);
296170530Ssam}
297178354Ssam
298178354Ssamuint64_t
299178354Ssammemstat_get_count(const struct memory_type *mtp)
300170530Ssam{
301178354Ssam
302178354Ssam	return (mtp->mt_count);
303170530Ssam}
304178354Ssam
305178354Ssamuint64_t
306170530Ssammemstat_get_free(const struct memory_type *mtp)
307178354Ssam{
308178354Ssam
309170530Ssam	return (mtp->mt_free);
310178354Ssam}
311178354Ssam
312178354Ssamuint64_t
313170530Ssammemstat_get_failures(const struct memory_type *mtp)
314170530Ssam{
315170530Ssam
316170530Ssam	return (mtp->mt_failures);
317170530Ssam}
318170530Ssam
319170530Ssamuint64_t
320184288Ssammemstat_get_sleeps(const struct memory_type *mtp)
321170530Ssam{
322170530Ssam
323184288Ssam	return (mtp->mt_sleeps);
324178354Ssam}
325170530Ssam
326184288Ssamvoid *
327170530Ssammemstat_get_caller_pointer(const struct memory_type *mtp, int index)
328170530Ssam{
329184288Ssam
330184288Ssam	return (mtp->mt_caller_pointer[index]);
331184288Ssam}
332184288Ssam
333178354Ssamvoid
334178354Ssammemstat_set_caller_pointer(struct memory_type *mtp, int index, void *value)
335184288Ssam{
336170530Ssam
337178354Ssam	mtp->mt_caller_pointer[index] = value;
338178354Ssam}
339178354Ssam
340170530Ssamuint64_t
341184288Ssammemstat_get_caller_uint64(const struct memory_type *mtp, int index)
342184288Ssam{
343170530Ssam
344170530Ssam	return (mtp->mt_caller_uint64[index]);
345184288Ssam}
346184288Ssam
347184288Ssamvoid
348184288Ssammemstat_set_caller_uint64(struct memory_type *mtp, int index, uint64_t value)
349184288Ssam{
350170530Ssam
351170530Ssam	mtp->mt_caller_uint64[index] = value;
352170530Ssam}
353184288Ssam
354184288Ssamuint64_t
355184288Ssammemstat_get_zonefree(const struct memory_type *mtp)
356184288Ssam{
357184288Ssam
358184288Ssam	return (mtp->mt_zonefree);
359184288Ssam}
360184288Ssam
361184288Ssamuint64_t
362184288Ssammemstat_get_kegfree(const struct memory_type *mtp)
363184288Ssam{
364184288Ssam
365170530Ssam	return (mtp->mt_kegfree);
366184288Ssam}
367184288Ssam
368184288Ssamuint64_t
369184288Ssammemstat_get_percpu_memalloced(const struct memory_type *mtp, int cpu)
370184288Ssam{
371184288Ssam
372184288Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_memalloced);
373184288Ssam}
374184288Ssam
375184288Ssamuint64_t
376184288Ssammemstat_get_percpu_memfreed(const struct memory_type *mtp, int cpu)
377184288Ssam{
378184288Ssam
379184288Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_memfreed);
380184288Ssam}
381184288Ssam
382184288Ssamuint64_t
383184288Ssammemstat_get_percpu_numallocs(const struct memory_type *mtp, int cpu)
384184288Ssam{
385184288Ssam
386184288Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_numallocs);
387184288Ssam}
388184288Ssam
389184288Ssamuint64_t
390184288Ssammemstat_get_percpu_numfrees(const struct memory_type *mtp, int cpu)
391184288Ssam{
392184288Ssam
393184288Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_numfrees);
394184288Ssam}
395184288Ssam
396184288Ssamuint64_t
397178354Ssammemstat_get_percpu_sizemask(const struct memory_type *mtp, int cpu)
398178354Ssam{
399170530Ssam
400178354Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_sizemask);
401178354Ssam}
402184288Ssam
403184288Ssamvoid *
404170530Ssammemstat_get_percpu_caller_pointer(const struct memory_type *mtp, int cpu,
405170530Ssam    int index)
406170530Ssam{
407184288Ssam
408184288Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index]);
409184288Ssam}
410184288Ssam
411170530Ssamvoid
412178354Ssammemstat_set_percpu_caller_pointer(struct memory_type *mtp, int cpu,
413178354Ssam    int index, void *value)
414170530Ssam{
415184288Ssam
416248069Sadrian	mtp->mt_percpu_alloc[cpu].mtp_caller_pointer[index] = value;
417184288Ssam}
418184288Ssam
419184288Ssamuint64_t
420245464Sadrianmemstat_get_percpu_caller_uint64(const struct memory_type *mtp, int cpu,
421245464Sadrian    int index)
422170530Ssam{
423184288Ssam
424184288Ssam	return (mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index]);
425184288Ssam}
426184288Ssam
427184288Ssamvoid
428184288Ssammemstat_set_percpu_caller_uint64(struct memory_type *mtp, int cpu, int index,
429184288Ssam    uint64_t value)
430184288Ssam{
431170530Ssam
432178354Ssam	mtp->mt_percpu_alloc[cpu].mtp_caller_uint64[index] = value;
433245464Sadrian}
434184288Ssam
435184288Ssamuint64_t
436184288Ssammemstat_get_percpu_free(const struct memory_type *mtp, int cpu)
437184288Ssam{
438184288Ssam
439184288Ssam	return (mtp->mt_percpu_cache[cpu].mtp_free);
440184288Ssam}
441184288Ssam