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