GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/systat/malloc.c Lines: 0 121 0.0 %
Date: 2017-11-07 Branches: 0 60 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: malloc.c,v 1.3 2015/01/16 00:03:37 deraadt Exp $	*/
2
/*
3
 * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/types.h>
19
#include <sys/signal.h>
20
#include <sys/sysctl.h>
21
#include <sys/malloc.h>
22
#include <errno.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <limits.h>
26
27
#include "systat.h"
28
29
void print_types(void);
30
void print_buckets(void);
31
int  read_types(void);
32
int  read_buckets(void);
33
void sort_types(void);
34
int  select_types(void);
35
int  select_buckets(void);
36
void showtype(int k);
37
void showbucket(int k);
38
39
40
/* qsort callbacks */
41
int sort_tname_callback(const void *s1, const void *s2);
42
int sort_treq_callback(const void *s1, const void *s2);
43
int sort_inuse_callback(const void *s1, const void *s2);
44
int sort_memuse_callback(const void *s1, const void *s2);
45
46
#define MAX_BUCKETS 16
47
48
struct type_info {
49
	const char *name;
50
	struct kmemstats stats;
51
	char buckets[MAX_BUCKETS];
52
};
53
54
55
struct type_info types[M_LAST];
56
57
struct kmembuckets buckets[MAX_BUCKETS];
58
int bucket_sizes[MAX_BUCKETS];
59
60
int num_types = 0;
61
int num_buckets = 0;
62
63
/*
64
 * These names are defined in <sys/malloc.h>.
65
 */
66
const char *kmemnames[] = INITKMEMNAMES;
67
68
field_def fields_malloc[] = {
69
	{"TYPE", 14, 32, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
70
	{"INUSE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
71
	{"MEMUSE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
72
	{"HIGHUSE", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
73
	{"LIMIT", 6, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
74
	{"REQUESTS", 8, 16, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
75
	{"TYPE LIMIT", 5, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
76
	{"KERN LIMIT", 5, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
77
	{"BUCKETS", MAX_BUCKETS, MAX_BUCKETS, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
78
79
	{"BUCKET", 8, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
80
	{"REQUESTS", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
81
	{"INUSE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
82
	{"FREE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
83
	{"HIWAT", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
84
	{"COULDFREE", 8, 24, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
85
};
86
87
88
#define FLD_TYPE_NAME		FIELD_ADDR(fields_malloc,0)
89
#define FLD_TYPE_INUSE		FIELD_ADDR(fields_malloc,1)
90
#define FLD_TYPE_MEMUSE		FIELD_ADDR(fields_malloc,2)
91
#define FLD_TYPE_HIGHUSE	FIELD_ADDR(fields_malloc,3)
92
#define FLD_TYPE_LIMIT		FIELD_ADDR(fields_malloc,4)
93
#define FLD_TYPE_REQUESTS	FIELD_ADDR(fields_malloc,5)
94
#define FLD_TYPE_TLIMIT		FIELD_ADDR(fields_malloc,6)
95
#define FLD_TYPE_KLIMIT		FIELD_ADDR(fields_malloc,7)
96
#define FLD_TYPE_SIZES		FIELD_ADDR(fields_malloc,8)
97
98
#define FLD_BUCKET_SIZE		FIELD_ADDR(fields_malloc,9)
99
#define FLD_BUCKET_REQUESTS	FIELD_ADDR(fields_malloc,10)
100
#define FLD_BUCKET_INUSE	FIELD_ADDR(fields_malloc,11)
101
#define FLD_BUCKET_FREE		FIELD_ADDR(fields_malloc,12)
102
#define FLD_BUCKET_HIWAT	FIELD_ADDR(fields_malloc,13)
103
#define FLD_BUCKET_COULDFREE	FIELD_ADDR(fields_malloc,14)
104
105
106
107
/* Define views */
108
field_def *view_malloc_0[] = {
109
	FLD_TYPE_NAME, FLD_TYPE_INUSE, FLD_TYPE_MEMUSE,
110
	FLD_TYPE_HIGHUSE, FLD_TYPE_LIMIT, FLD_TYPE_REQUESTS,
111
	FLD_TYPE_TLIMIT, FLD_TYPE_KLIMIT, FLD_TYPE_SIZES, NULL
112
};
113
114
field_def *view_malloc_1[] = {
115
	FLD_BUCKET_SIZE, FLD_BUCKET_REQUESTS, FLD_BUCKET_INUSE,
116
	FLD_BUCKET_FREE, FLD_BUCKET_HIWAT, FLD_BUCKET_COULDFREE, NULL
117
};
118
119
order_type type_order_list[] = {
120
	{"name", "name", 'N', sort_tname_callback},
121
	{"inuse", "in use", 'U', sort_inuse_callback},
122
	{"memuse", "mem use", 'S', sort_memuse_callback},
123
	{"requests", "requests", 'Q', sort_treq_callback},
124
	{NULL, NULL, 0, NULL}
125
};
126
127
/* Define view managers */
128
struct view_manager types_mgr = {
129
	"Types", select_types, read_types, sort_types, print_header,
130
	print_types, keyboard_callback, type_order_list, type_order_list
131
};
132
133
struct view_manager buckets_mgr = {
134
	"Buckets", select_buckets, read_buckets, NULL, print_header,
135
	print_buckets, keyboard_callback, NULL, NULL
136
};
137
138
field_view views_malloc[] = {
139
	{view_malloc_0, "malloc", '6', &types_mgr},
140
	{view_malloc_1, "buckets", '7', &buckets_mgr},
141
	{NULL, NULL, 0, NULL}
142
};
143
144
145
int
146
sort_tname_callback(const void *s1, const void *s2)
147
{
148
	struct type_info *t1, *t2;
149
	t1 = (struct type_info *)s1;
150
	t2 = (struct type_info *)s2;
151
152
	return strcmp(t1->name, t2->name) * sortdir;
153
}
154
155
int
156
sort_treq_callback(const void *s1, const void *s2)
157
{
158
	struct type_info *t1, *t2;
159
	t1 = (struct type_info *)s1;
160
	t2 = (struct type_info *)s2;
161
162
	if (t1->stats.ks_calls <  t2->stats.ks_calls)
163
		return sortdir;
164
	if (t1->stats.ks_calls >  t2->stats.ks_calls)
165
		return -sortdir;
166
167
	return sort_tname_callback(s1, s2);
168
}
169
170
int
171
sort_inuse_callback(const void *s1, const void *s2)
172
{
173
	struct type_info *t1, *t2;
174
	t1 = (struct type_info *)s1;
175
	t2 = (struct type_info *)s2;
176
177
	if (t1->stats.ks_inuse <  t2->stats.ks_inuse)
178
		return sortdir;
179
	if (t1->stats.ks_inuse >  t2->stats.ks_inuse)
180
		return -sortdir;
181
182
	return sort_tname_callback(s1, s2);
183
}
184
185
int
186
sort_memuse_callback(const void *s1, const void *s2)
187
{
188
	struct type_info *t1, *t2;
189
	t1 = (struct type_info *)s1;
190
	t2 = (struct type_info *)s2;
191
192
	if (t1->stats.ks_memuse <  t2->stats.ks_memuse)
193
		return sortdir;
194
	if (t1->stats.ks_memuse >  t2->stats.ks_memuse)
195
		return -sortdir;
196
197
	return sort_tname_callback(s1, s2);
198
}
199
200
201
void
202
sort_types(void)
203
{
204
	order_type *ordering;
205
206
	if (curr_mgr == NULL)
207
		return;
208
209
	ordering = curr_mgr->order_curr;
210
211
	if (ordering == NULL)
212
		return;
213
	if (ordering->func == NULL)
214
		return;
215
	if (num_types <= 0)
216
		return;
217
218
	mergesort(types, num_types, sizeof(struct type_info), ordering->func);
219
}
220
221
int
222
select_types(void)
223
{
224
	num_disp = num_types;
225
	return (0);
226
}
227
228
int
229
select_buckets(void)
230
{
231
	num_disp = num_buckets;
232
	return (0);
233
}
234
235
int
236
read_buckets(void)
237
{
238
	int mib[4];
239
	char buf[BUFSIZ], *bufp, *ap;
240
	const char *errstr;
241
	size_t siz;
242
243
	mib[0] = CTL_KERN;
244
	mib[1] = KERN_MALLOCSTATS;
245
	mib[2] = KERN_MALLOC_BUCKETS;
246
247
	siz = sizeof(buf);
248
	num_buckets = 0;
249
250
	if (sysctl(mib, 3, buf, &siz, NULL, 0) < 0) {
251
		error("sysctl(kern.malloc.buckets): %s", strerror(errno));
252
		return (-1);
253
	}
254
255
	bufp = buf;
256
	mib[2] = KERN_MALLOC_BUCKET;
257
	siz = sizeof(struct kmembuckets);
258
259
	while ((ap = strsep(&bufp, ",")) != NULL) {
260
		if (num_buckets >= MAX_BUCKETS)
261
			break;
262
		bucket_sizes[num_buckets] = strtonum(ap, 0, INT_MAX, &errstr);
263
		if (errstr) {
264
			error("strtonum(%s): %s", ap, errstr);
265
			return (-1);
266
		}
267
		mib[3] = bucket_sizes[num_buckets];
268
		if (sysctl(mib, 4, &buckets[num_buckets], &siz,
269
			   NULL, 0) < 0) {
270
			error("sysctl(kern.malloc.bucket.%d): %s",
271
			    mib[3], strerror(errno));
272
			return (-1);
273
		}
274
		num_buckets++;
275
	}
276
277
	return (0);
278
}
279
280
int
281
read_types(void)
282
{
283
	struct type_info *ti;
284
	int i, j, k, mib[4];
285
	size_t siz;
286
287
	bzero(types, sizeof(types));
288
	ti = types;
289
	siz = sizeof(struct kmemstats);
290
291
	num_types = 0;
292
293
	for (i = 0; i < M_LAST; i++) {
294
		mib[0] = CTL_KERN;
295
		mib[1] = KERN_MALLOCSTATS;
296
		mib[2] = KERN_MALLOC_KMEMSTATS;
297
		mib[3] = i;
298
299
		/*
300
		 * Skip errors -- these are presumed to be unallocated
301
		 * entries.
302
		 */
303
		if (sysctl(mib, 4, &ti->stats, &siz, NULL, 0) < 0)
304
			continue;
305
306
		if (ti->stats.ks_calls == 0)
307
			continue;
308
309
		ti->name = kmemnames[i];
310
		j = 1 << MINBUCKET;
311
312
		for (k = 0; k < MAX_BUCKETS; k++, j <<= 1)
313
			ti->buckets[k] = (ti->stats.ks_size & j) ? '|' : '.';
314
315
		ti++;
316
		num_types++;
317
	}
318
319
	return (0);
320
}
321
322
323
void
324
print_types(void)
325
{
326
	int n, count = 0;
327
328
	for (n = dispstart; n < num_disp; n++) {
329
		showtype(n);
330
		count++;
331
		if (maxprint > 0 && count >= maxprint)
332
			break;	}
333
}
334
335
void
336
print_buckets(void)
337
{
338
	int n, count = 0;
339
340
	for (n = dispstart; n < num_disp; n++) {
341
		showbucket(n);
342
		count++;
343
		if (maxprint > 0 && count >= maxprint)
344
			break;
345
	}
346
}
347
348
int
349
initmalloc(void)
350
{
351
	field_view *v;
352
353
	for (v = views_malloc; v->name != NULL; v++)
354
		add_view(v);
355
356
	read_buckets();
357
	read_types();
358
359
	return(0);
360
}
361
362
void
363
showbucket(int k)
364
{
365
	struct kmembuckets *kp = buckets + k;
366
367
	if (k < 0 || k >= num_buckets)
368
		return;
369
370
	print_fld_size(FLD_BUCKET_SIZE, bucket_sizes[k]);
371
	print_fld_size(FLD_BUCKET_INUSE, kp->kb_total - kp->kb_totalfree);
372
	print_fld_size(FLD_BUCKET_FREE, kp->kb_totalfree);
373
	print_fld_size(FLD_BUCKET_REQUESTS, kp->kb_calls);
374
	print_fld_size(FLD_BUCKET_HIWAT, kp->kb_highwat);
375
	print_fld_size(FLD_BUCKET_COULDFREE, kp->kb_couldfree);
376
377
	end_line();
378
}
379
380
381
void
382
showtype(int k)
383
{
384
	struct type_info *t = types + k;
385
386
	if (k < 0 || k >= num_types)
387
		return;
388
389
390
	print_fld_str(FLD_TYPE_NAME, t->name ? t->name : "undefined");
391
	print_fld_size(FLD_TYPE_INUSE, t->stats.ks_inuse);
392
	print_fld_size(FLD_TYPE_MEMUSE, t->stats.ks_memuse);
393
	print_fld_size(FLD_TYPE_HIGHUSE, t->stats.ks_maxused);
394
	print_fld_size(FLD_TYPE_LIMIT, t->stats.ks_limit);
395
	print_fld_size(FLD_TYPE_REQUESTS, t->stats.ks_calls);
396
	print_fld_size(FLD_TYPE_TLIMIT, t->stats.ks_limblocks);
397
	print_fld_size(FLD_TYPE_KLIMIT, t->stats.ks_mapblocks);
398
	print_fld_str(FLD_TYPE_SIZES, t->buckets);
399
400
	end_line();
401
}