xref: /netbsd/usr.sbin/acpitools/aml/aml_memman.c (revision 6550d01e)
1 /*	$NetBSD: aml_memman.c,v 1.3 2009/01/18 09:46:59 lukem Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *	Id: aml_memman.c,v 1.10 2000/08/09 14:47:43 iwasaki Exp
29  *	$FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_memman.c,v 1.2 2000/11/09 06:24:45 iwasaki Exp $
30  */
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: aml_memman.c,v 1.3 2009/01/18 09:46:59 lukem Exp $");
33 
34 /*
35  * Generic Memory Management
36  */
37 
38 #include <sys/param.h>
39 
40 #include <aml/aml_memman.h>
41 
42 #ifndef _KERNEL
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #else /* _KERNEL */
47 #include <sys/kernel.h>
48 #include <sys/systm.h>
49 #include <sys/malloc.h>
50 MALLOC_DEFINE(M_MEMMAN, "memman", "Generic and Simple Memory Management");
51 #endif /* !_KERNEL */
52 
53 unsigned int	memid_unkown = 255;
54 
55 static int		 manage_block(struct memman *memman, unsigned int id,
56 				      void *block, unsigned static_mem,
57 				      unsigned entries);
58 static int		 blockman_init(struct memman *memman, unsigned int id);
59 static void		 memman_flexsize_add_histogram(struct memman *memman,
60 						       size_t size,
61 						       int tolerance);
62 static int		 memman_comp_histogram_size(const void *a,
63 						    const void *b);
64 static void		 memman_sort_histogram_by_size(struct memman *memman);
65 static unsigned int	 memman_guess_memid(struct memman *memman, void *chunk);
66 static void		 memman_statistics_fixedsize(struct memman *memman);
67 static void		 memman_statistics_flexsize(struct memman *memman);
68 
69 static int
70 manage_block(struct memman *memman, unsigned int id, void *block,
71     unsigned static_mem, unsigned entries)
72 {
73 	unsigned int	i;
74 	size_t	alloc_size;
75 	void	*tmp, *realblock;
76 	struct	memman_blockman	*bmp;
77 	struct	memman_block *memblock;
78 	struct	memman_node *memnodes;
79 
80 	bmp = &memman->blockman[id];
81 	alloc_size = MEMMAN_BLOCKNODE_SIZE(entries);
82 
83 	if (static_mem) {
84 		tmp = (void *)block;
85 		realblock = (char *)block + alloc_size;
86 	} else {
87 		tmp = MEMMAN_SYSMALLOC(alloc_size);
88 		if (!tmp) {
89 			return (-1);
90 		}
91 		realblock = block;
92 
93 		memman->allocated_mem += alloc_size;
94 		memman->salloc_called++;
95 	}
96 
97 	memblock = (struct memman_block *)tmp;
98 	memnodes = (struct memman_node *)((char *)tmp + sizeof(struct memman_block));
99 
100 	memblock->block = realblock;
101 	memblock->static_mem = static_mem;
102 	memblock->allocated = entries;
103 	memblock->available = entries;
104 	if (!static_mem) {
105 		alloc_size += roundup(bmp->size * entries, ROUNDUP_UNIT);
106 	}
107 	memblock->allocated_mem = alloc_size;
108 	LIST_INSERT_HEAD(&bmp->block_list, memblock, links);
109 
110 	for (i = 0; i < entries; ++i) {
111 		memnodes[i].node = ((char *)realblock + (i * (bmp->size)));
112 		memnodes[i].memblock = memblock;
113 		LIST_INSERT_HEAD(&bmp->free_node_list, &memnodes[i], links);
114 	}
115 	bmp->available = entries;
116 
117 	return (0);
118 }
119 
120 static int
121 blockman_init(struct memman *memman, unsigned int id)
122 {
123 	int	status;
124 	struct	memman_blockman *bmp;
125 
126 	bmp = &memman->blockman[id];
127 	bmp->initialized = 1;
128 	LIST_INIT(&bmp->block_list);
129 	LIST_INIT(&bmp->free_node_list);
130 	LIST_INIT(&bmp->occupied_node_list);
131 	status = manage_block(memman, id, bmp->initial_block,
132 	    1, MEMMAN_INITIAL_SIZE);
133 	return (status);
134 }
135 
136 void *
137 memman_alloc(struct memman *memman, unsigned int id)
138 {
139 	size_t	alloc_size;
140 	void	*chunk, *block;
141 	struct	memman_blockman *bmp;
142 	struct	memman_node *memnode;
143 
144 	if (memman->max_memid <= id) {
145 		printf("memman_alloc: invalid memory type id\n");
146 		return (NULL);
147 	}
148 	bmp = &memman->blockman[id];
149 	if (!bmp->initialized) {
150 		if (blockman_init(memman, id)) {
151 			goto malloc_fail;
152 		}
153 	}
154 	memman->alloc_called++;
155 
156 	if (bmp->available == 0) {
157 		alloc_size = roundup(bmp->size * MEMMAN_INCR_SIZE,
158 		    ROUNDUP_UNIT);
159 		block = MEMMAN_SYSMALLOC(alloc_size);
160 		if (!block) {
161 			goto malloc_fail;
162 		}
163 		memman->required_mem += bmp->size * MEMMAN_INCR_SIZE;
164 		memman->allocated_mem += alloc_size;
165 		memman->salloc_called++;
166 
167 		if (manage_block(memman, id, block, 0, MEMMAN_INCR_SIZE)) {
168 			goto malloc_fail;
169 		}
170 	}
171 	memnode = LIST_FIRST(&bmp->free_node_list);
172 	LIST_REMOVE(memnode, links);
173 	chunk = memnode->node;
174 	LIST_INSERT_HEAD(&bmp->occupied_node_list, memnode, links);
175 	memnode->memblock->available--;
176 	bmp->available--;
177 
178 	return (chunk);
179 
180 malloc_fail:
181 	printf("memman_alloc: could not allocate memory\n");
182 	return (NULL);
183 }
184 
185 static void
186 memman_flexsize_add_histogram(struct memman *memman, size_t size,
187     int tolerance)
188 {
189 	unsigned int i;
190 	int	gap;
191 
192 	if (size == 0) {
193 		return;
194 	}
195 	for (i = 0; i < memman->flex_mem_histogram_ptr; i++) {
196 		gap = memman->flex_mem_histogram[i].mem_size - size;
197 		if (gap >= (tolerance * -1) && gap <= tolerance) {
198 			memman->flex_mem_histogram[i].count++;
199 			if (memman->flex_mem_histogram[i].mem_size < size) {
200 				memman->flex_mem_histogram[i].mem_size = size;
201 			}
202 			return;
203 		}
204 	}
205 
206 	if (memman->flex_mem_histogram_ptr == MEMMAN_HISTOGRAM_SIZE) {
207 		memman_flexsize_add_histogram(memman, size, tolerance + 1);
208 		return;
209 	}
210 	i = memman->flex_mem_histogram_ptr;
211 	memman->flex_mem_histogram[i].mem_size = size;
212 	memman->flex_mem_histogram[i].count = 1;
213 	memman->flex_mem_histogram_ptr++;
214 }
215 
216 static int
217 memman_comp_histogram_size(const void *a, const void *b)
218 {
219 	int	delta;
220 
221 	delta = ((const struct memman_histogram *)a)->mem_size -
222 	    ((const struct memman_histogram *)b)->mem_size;
223 	return (delta);
224 }
225 
226 static void
227 memman_sort_histogram_by_size(struct memman *memman)
228 {
229 	qsort(memman->flex_mem_histogram, memman->flex_mem_histogram_ptr,
230 	    sizeof(struct memman_histogram), memman_comp_histogram_size);
231 }
232 
233 void *
234 memman_alloc_flexsize(struct memman *memman, size_t size)
235 {
236 	void	*mem;
237 	struct	memman_flexmem_info *info;
238 
239 	if (size == 0) {
240 		return (NULL);
241 	}
242 	if ((mem = MEMMAN_SYSMALLOC(size)) != NULL) {	/* XXX */
243 
244 		info = MEMMAN_SYSMALLOC(sizeof(struct memman_flexmem_info));
245 		if (info) {
246 			if (!memman->flex_mem_initialized) {
247 				LIST_INIT(&memman->flexmem_info_list);
248 				bzero(memman->flex_mem_histogram,
249 				    sizeof(struct memman_histogram));
250 				memman->flex_mem_initialized = 1;
251 			}
252 			info->addr = mem;
253 			info->mem_size = size;
254 			LIST_INSERT_HEAD(&memman->flexmem_info_list, info, links);
255 		}
256 		memman->flex_alloc_called++;
257 		memman->flex_salloc_called++;
258 		memman->flex_required_mem += size;
259 		memman->flex_allocated_mem += size;
260 		if (memman->flex_mem_size_min == 0 ||
261 		    memman->flex_mem_size_min > size) {
262 			memman->flex_mem_size_min = size;
263 		}
264 		if (memman->flex_mem_size_max < size) {
265 			memman->flex_mem_size_max = size;
266 		}
267 		if (memman->flex_peak_mem_usage <
268 		    (memman->flex_allocated_mem - memman->flex_reclaimed_mem)) {
269 			memman->flex_peak_mem_usage =
270 			    (memman->flex_allocated_mem - memman->flex_reclaimed_mem);
271 		}
272 		memman_flexsize_add_histogram(memman, size,
273 		    memman->flex_mem_histogram_initial_tolerance);
274 	}
275 	return (mem);
276 }
277 
278 static unsigned int
279 memman_guess_memid(struct memman *memman, void *chunk)
280 {
281 	unsigned int	id;
282 	struct	memman_blockman *bmp;
283 	struct	memman_node *memnode;
284 
285 	for (id = 0; id < memman->max_memid; id++) {
286 		bmp = &memman->blockman[id];
287 		if (!bmp->initialized) {
288 			if (blockman_init(memman, id)) {
289 				printf("memman_free: could not initialized\n");
290 			}
291 		}
292 		LIST_FOREACH(memnode, &bmp->occupied_node_list, links) {
293 			if (memnode->node == chunk) {
294 				return (id);	/* got it! */
295 			}
296 		}
297 	}
298 	return (memid_unkown);	/* gave up */
299 }
300 
301 void
302 memman_free(struct memman *memman, unsigned int memid, void *chunk)
303 {
304 	unsigned int	id;
305 	unsigned	found;
306 	void	*block;
307 	struct	memman_blockman *bmp;
308 	struct	memman_block *memblock;
309 	struct	memman_node *memnode;
310 
311 	id = memid;
312 	if (memid == memid_unkown) {
313 		id = memman_guess_memid(memman, chunk);
314 	}
315 	if (memman->max_memid <= id) {
316 		printf("memman_free: invalid memory type id\n");
317 		MEMMAN_SYSABORT();
318 		return;
319 	}
320 	bmp = &memman->blockman[id];
321 	if (!bmp->initialized) {
322 		if (blockman_init(memman, id)) {
323 			printf("memman_free: could not initialized\n");
324 		}
325 	}
326 	found = 0;
327 	LIST_FOREACH(memnode, &bmp->occupied_node_list, links) {
328 		if (memnode->node == chunk) {
329 			found = 1;
330 			break;
331 		}
332 	}
333 	if (!found) {
334 		printf("memman_free: invalid address\n");
335 		return;
336 	}
337 	memman->free_called++;
338 
339 	LIST_REMOVE(memnode, links);
340 	memblock = memnode->memblock;
341 	memblock->available++;
342 	LIST_INSERT_HEAD(&bmp->free_node_list, memnode, links);
343 	bmp->available++;
344 
345 	if (!memblock->static_mem &&
346 	    memblock->available == memblock->allocated) {
347 		LIST_FOREACH(memnode, &bmp->free_node_list, links) {
348 			if (memnode->memblock != memblock) {
349 				continue;
350 			}
351 			LIST_REMOVE(memnode, links);
352 			bmp->available--;
353 		}
354 		block = memblock->block;
355 		MEMMAN_SYSFREE(block);
356 		memman->sfree_called++;
357 
358 		LIST_REMOVE(memblock, links);
359 		memman->sfree_called++;
360 		memman->reclaimed_mem += memblock->allocated_mem;
361 		MEMMAN_SYSFREE(memblock);
362 	}
363 }
364 
365 void
366 memman_free_flexsize(struct memman *memman, void *chunk)
367 {
368 	struct	memman_flexmem_info *info;
369 
370 	LIST_FOREACH(info, &memman->flexmem_info_list, links) {
371 		if (info->addr == chunk) {
372 			memman->flex_reclaimed_mem += info->mem_size;
373 			LIST_REMOVE(info, links);
374 			MEMMAN_SYSFREE(info);
375 			break;
376 		}
377 	}
378 	/* XXX */
379 	memman->flex_free_called++;
380 	memman->flex_sfree_called++;
381 	MEMMAN_SYSFREE(chunk);
382 }
383 
384 void
385 memman_freeall(struct memman *memman)
386 {
387 	unsigned int id;
388 	void	*chunk;
389 	struct	memman_blockman *bmp;
390 	struct	memman_node *memnode;
391 	struct	memman_block *memblock;
392 	struct	memman_flexmem_info *info;
393 
394 	for (id = 0; id < memman->max_memid; id++) {
395 		bmp = &memman->blockman[id];
396 
397 		while ((memnode = LIST_FIRST(&bmp->occupied_node_list))) {
398 			chunk = memnode->node;
399 			printf("memman_freeall: fixed size (id = %u)\n", id);
400 			memman_free(memman, id, chunk);
401 		}
402 		while ((memblock = LIST_FIRST(&bmp->block_list))) {
403 			LIST_REMOVE(memblock, links);
404 			if (!memblock->static_mem) {
405 				memman->sfree_called++;
406 				memman->reclaimed_mem += memblock->allocated_mem;
407 				MEMMAN_SYSFREE(memblock);
408 			}
409 		}
410 		bmp->initialized = 0;
411 	}
412 
413 	LIST_FOREACH(info, &memman->flexmem_info_list, links) {
414 		printf("memman_freeall: flex size (size = %zd, addr = %p)\n",
415 		    info->mem_size, info->addr);
416 		memman_free_flexsize(memman, info->addr);
417 	}
418 }
419 
420 static void
421 memman_statistics_fixedsize(struct memman *memman)
422 {
423 	printf("  fixed size memory blocks\n");
424 	printf("    alloc():		%d times\n", memman->alloc_called);
425 	printf("    system malloc():	%d times\n", memman->salloc_called);
426 	printf("    free():		%d times\n", memman->free_called);
427 	printf("    system free():	%d times\n", memman->sfree_called);
428 	printf("    required memory:	%zd bytes\n", memman->required_mem);
429 	printf("    allocated memory:	%zd bytes\n", memman->allocated_mem);
430 	printf("    reclaimed memory:	%zd bytes\n", memman->reclaimed_mem);
431 }
432 
433 static void
434 memman_statistics_flexsize(struct memman *memman)
435 {
436 	unsigned int	i;
437 
438 	printf("  flexible size memory blocks\n");
439 	printf("    alloc():		%d times\n", memman->flex_alloc_called);
440 	printf("    system malloc():	%d times\n", memman->flex_salloc_called);
441 	printf("    free():		%d times\n", memman->flex_free_called);
442 	printf("    system free():	%d times\n", memman->flex_sfree_called);
443 	printf("    required memory:	%zd bytes\n", memman->flex_required_mem);
444 	printf("    allocated memory:	%zd bytes\n", memman->flex_allocated_mem);
445 	printf("    reclaimed memory:	%zd bytes\n", memman->flex_reclaimed_mem);
446 	printf("    peak memory usage:	%zd bytes\n", memman->flex_peak_mem_usage);
447 	printf("    min memory size:	%zd bytes\n", memman->flex_mem_size_min);
448 	printf("    max memory size:	%zd bytes\n", memman->flex_mem_size_max);
449 	printf("    avg memory size:	%zd bytes\n",
450 	    (memman->flex_alloc_called) ?
451 	    memman->flex_allocated_mem / memman->flex_alloc_called : 0);
452 
453 	printf("    memory size histogram (%d entries):\n",
454 	    memman->flex_mem_histogram_ptr);
455 	printf("	size	count\n");
456 	memman_sort_histogram_by_size(memman);
457 	for (i = 0; i < memman->flex_mem_histogram_ptr; i++) {
458 		printf("	%zu	%d\n",
459 		    memman->flex_mem_histogram[i].mem_size,
460 		    memman->flex_mem_histogram[i].count);
461 	}
462 }
463 
464 void
465 memman_statistics(struct memman *memman)
466 {
467 	printf("memman: reporting statistics\n");
468 	memman_statistics_fixedsize(memman);
469 	memman_statistics_flexsize(memman);
470 }
471 
472 size_t
473 memman_memid2size(struct memman *memman, unsigned int id)
474 {
475 	if (memman->max_memid <= id) {
476 		printf("memman_alloc: invalid memory type id\n");
477 		return (0);
478 	}
479 	return (memman->blockman[id].size);
480 }
481