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