diff options
Diffstat (limited to 'src/lib/libc/stdlib/malloc.c')
| -rw-r--r-- | src/lib/libc/stdlib/malloc.c | 278 |
1 files changed, 141 insertions, 137 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 0d1b2290be..025508a335 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: malloc.c,v 1.130 2011/05/05 12:11:20 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.131 2011/05/08 07:08:13 otto Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> | 3 | * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> |
| 4 | * | 4 | * |
| @@ -192,6 +192,11 @@ static u_char getrnibble(void); | |||
| 192 | 192 | ||
| 193 | extern char *__progname; | 193 | extern char *__progname; |
| 194 | 194 | ||
| 195 | #ifdef MALLOC_STATS | ||
| 196 | void malloc_dump(int); | ||
| 197 | static void malloc_exit(void); | ||
| 198 | #endif | ||
| 199 | |||
| 195 | /* low bits of r->p determine size: 0 means >= page size and p->size holding | 200 | /* low bits of r->p determine size: 0 means >= page size and p->size holding |
| 196 | * real size, otherwise r->size is a shift count, or 1 for malloc(0) | 201 | * real size, otherwise r->size is a shift count, or 1 for malloc(0) |
| 197 | */ | 202 | */ |
| @@ -217,142 +222,6 @@ hash(void *p) | |||
| 217 | return sum; | 222 | return sum; |
| 218 | } | 223 | } |
| 219 | 224 | ||
| 220 | #ifdef MALLOC_STATS | ||
| 221 | static void | ||
| 222 | dump_chunk(int fd, struct chunk_info *p, int fromfreelist) | ||
| 223 | { | ||
| 224 | char buf[64]; | ||
| 225 | |||
| 226 | while (p != NULL) { | ||
| 227 | snprintf(buf, sizeof(buf), "chunk %d %d/%d %p\n", p->size, | ||
| 228 | p->free, p->total, p->page); | ||
| 229 | write(fd, buf, strlen(buf)); | ||
| 230 | if (!fromfreelist) | ||
| 231 | break; | ||
| 232 | p = LIST_NEXT(p, entries); | ||
| 233 | if (p != NULL) { | ||
| 234 | snprintf(buf, sizeof(buf), " "); | ||
| 235 | write(fd, buf, strlen(buf)); | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | static void | ||
| 241 | dump_free_chunk_info(int fd, struct dir_info *d) | ||
| 242 | { | ||
| 243 | char buf[64]; | ||
| 244 | int i; | ||
| 245 | |||
| 246 | snprintf(buf, sizeof(buf), "Free chunk structs:\n"); | ||
| 247 | write(fd, buf, strlen(buf)); | ||
| 248 | for (i = 0; i < MALLOC_MAXSHIFT; i++) { | ||
| 249 | struct chunk_info *p = LIST_FIRST(&d->chunk_dir[i]); | ||
| 250 | if (p != NULL) { | ||
| 251 | snprintf(buf, sizeof(buf), "%2d) ", i); | ||
| 252 | write(fd, buf, strlen(buf)); | ||
| 253 | dump_chunk(fd, p, 1); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | } | ||
| 258 | |||
| 259 | static void | ||
| 260 | dump_free_page_info(int fd, struct dir_info *d) | ||
| 261 | { | ||
| 262 | char buf[64]; | ||
| 263 | int i; | ||
| 264 | |||
| 265 | snprintf(buf, sizeof(buf), "Free pages cached: %zu\n", | ||
| 266 | d->free_regions_size); | ||
| 267 | write(fd, buf, strlen(buf)); | ||
| 268 | for (i = 0; i < mopts.malloc_cache; i++) { | ||
| 269 | if (d->free_regions[i].p != NULL) { | ||
| 270 | snprintf(buf, sizeof(buf), "%2d) ", i); | ||
| 271 | write(fd, buf, strlen(buf)); | ||
| 272 | snprintf(buf, sizeof(buf), "free at %p: %zu\n", | ||
| 273 | d->free_regions[i].p, d->free_regions[i].size); | ||
| 274 | write(fd, buf, strlen(buf)); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | static void | ||
| 280 | malloc_dump1(int fd, struct dir_info *d) | ||
| 281 | { | ||
| 282 | char buf[64]; | ||
| 283 | size_t i, realsize; | ||
| 284 | |||
| 285 | snprintf(buf, sizeof(buf), "Malloc dir of %s at %p\n", __progname, d); | ||
| 286 | write(fd, buf, strlen(buf)); | ||
| 287 | if (d == NULL) | ||
| 288 | return; | ||
| 289 | snprintf(buf, sizeof(buf), "Regions slots %zu\n", d->regions_total); | ||
| 290 | write(fd, buf, strlen(buf)); | ||
| 291 | snprintf(buf, sizeof(buf), "Finds %zu/%zu %f\n", d->finds, | ||
| 292 | d->find_collisions, | ||
| 293 | 1.0 + (double)d->find_collisions / d->finds); | ||
| 294 | write(fd, buf, strlen(buf)); | ||
| 295 | snprintf(buf, sizeof(buf), "Inserts %zu/%zu %f\n", d->inserts, | ||
| 296 | d->insert_collisions, | ||
| 297 | 1.0 + (double)d->insert_collisions / d->inserts); | ||
| 298 | write(fd, buf, strlen(buf)); | ||
| 299 | snprintf(buf, sizeof(buf), "Deletes %zu/%zu\n", d->deletes, | ||
| 300 | d->delete_moves); | ||
| 301 | write(fd, buf, strlen(buf)); | ||
| 302 | snprintf(buf, sizeof(buf), "Cheap reallocs %zu/%zu\n", | ||
| 303 | d->cheap_reallocs, d->cheap_realloc_tries); | ||
| 304 | write(fd, buf, strlen(buf)); | ||
| 305 | snprintf(buf, sizeof(buf), "Regions slots free %zu\n", d->regions_free); | ||
| 306 | write(fd, buf, strlen(buf)); | ||
| 307 | for (i = 0; i < d->regions_total; i++) { | ||
| 308 | if (d->r[i].p != NULL) { | ||
| 309 | size_t h = hash(d->r[i].p) & | ||
| 310 | (d->regions_total - 1); | ||
| 311 | snprintf(buf, sizeof(buf), "%4zx) #%zx %zd ", | ||
| 312 | i, h, h - i); | ||
| 313 | write(fd, buf, strlen(buf)); | ||
| 314 | REALSIZE(realsize, &d->r[i]); | ||
| 315 | if (realsize > MALLOC_MAXCHUNK) { | ||
| 316 | snprintf(buf, sizeof(buf), | ||
| 317 | "%p: %zu\n", d->r[i].p, realsize); | ||
| 318 | write(fd, buf, strlen(buf)); | ||
| 319 | } else | ||
| 320 | dump_chunk(fd, | ||
| 321 | (struct chunk_info *)d->r[i].size, 0); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | dump_free_chunk_info(fd, d); | ||
| 325 | dump_free_page_info(fd, d); | ||
| 326 | snprintf(buf, sizeof(buf), "In use %zu\n", malloc_used); | ||
| 327 | write(fd, buf, strlen(buf)); | ||
| 328 | snprintf(buf, sizeof(buf), "Guarded %zu\n", malloc_guarded); | ||
| 329 | write(fd, buf, strlen(buf)); | ||
| 330 | } | ||
| 331 | |||
| 332 | |||
| 333 | void | ||
| 334 | malloc_dump(int fd) | ||
| 335 | { | ||
| 336 | malloc_dump1(fd, g_pool); | ||
| 337 | } | ||
| 338 | |||
| 339 | static void | ||
| 340 | malloc_exit(void) | ||
| 341 | { | ||
| 342 | static const char q[] = "malloc() warning: Couldn't dump stats\n"; | ||
| 343 | int save_errno = errno, fd; | ||
| 344 | |||
| 345 | fd = open("malloc.out", O_RDWR|O_APPEND); | ||
| 346 | if (fd != -1) { | ||
| 347 | malloc_dump(fd); | ||
| 348 | close(fd); | ||
| 349 | } else | ||
| 350 | write(STDERR_FILENO, q, sizeof(q) - 1); | ||
| 351 | errno = save_errno; | ||
| 352 | } | ||
| 353 | #endif /* MALLOC_STATS */ | ||
| 354 | |||
| 355 | |||
| 356 | static void | 225 | static void |
| 357 | wrterror(char *msg, void *p) | 226 | wrterror(char *msg, void *p) |
| 358 | { | 227 | { |
| @@ -1516,3 +1385,138 @@ posix_memalign(void **memptr, size_t alignment, size_t size) | |||
| 1516 | return 0; | 1385 | return 0; |
| 1517 | } | 1386 | } |
| 1518 | 1387 | ||
| 1388 | #ifdef MALLOC_STATS | ||
| 1389 | static void | ||
| 1390 | dump_chunk(int fd, struct chunk_info *p, int fromfreelist) | ||
| 1391 | { | ||
| 1392 | char buf[64]; | ||
| 1393 | |||
| 1394 | while (p != NULL) { | ||
| 1395 | snprintf(buf, sizeof(buf), "chunk %d %d/%d %p\n", p->size, | ||
| 1396 | p->free, p->total, p->page); | ||
| 1397 | write(fd, buf, strlen(buf)); | ||
| 1398 | if (!fromfreelist) | ||
| 1399 | break; | ||
| 1400 | p = LIST_NEXT(p, entries); | ||
| 1401 | if (p != NULL) { | ||
| 1402 | snprintf(buf, sizeof(buf), " "); | ||
| 1403 | write(fd, buf, strlen(buf)); | ||
| 1404 | } | ||
| 1405 | } | ||
| 1406 | } | ||
| 1407 | |||
| 1408 | static void | ||
| 1409 | dump_free_chunk_info(int fd, struct dir_info *d) | ||
| 1410 | { | ||
| 1411 | char buf[64]; | ||
| 1412 | int i; | ||
| 1413 | |||
| 1414 | snprintf(buf, sizeof(buf), "Free chunk structs:\n"); | ||
| 1415 | write(fd, buf, strlen(buf)); | ||
| 1416 | for (i = 0; i < MALLOC_MAXSHIFT; i++) { | ||
| 1417 | struct chunk_info *p = LIST_FIRST(&d->chunk_dir[i]); | ||
| 1418 | if (p != NULL) { | ||
| 1419 | snprintf(buf, sizeof(buf), "%2d) ", i); | ||
| 1420 | write(fd, buf, strlen(buf)); | ||
| 1421 | dump_chunk(fd, p, 1); | ||
| 1422 | } | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | } | ||
| 1426 | |||
| 1427 | static void | ||
| 1428 | dump_free_page_info(int fd, struct dir_info *d) | ||
| 1429 | { | ||
| 1430 | char buf[64]; | ||
| 1431 | int i; | ||
| 1432 | |||
| 1433 | snprintf(buf, sizeof(buf), "Free pages cached: %zu\n", | ||
| 1434 | d->free_regions_size); | ||
| 1435 | write(fd, buf, strlen(buf)); | ||
| 1436 | for (i = 0; i < mopts.malloc_cache; i++) { | ||
| 1437 | if (d->free_regions[i].p != NULL) { | ||
| 1438 | snprintf(buf, sizeof(buf), "%2d) ", i); | ||
| 1439 | write(fd, buf, strlen(buf)); | ||
| 1440 | snprintf(buf, sizeof(buf), "free at %p: %zu\n", | ||
| 1441 | d->free_regions[i].p, d->free_regions[i].size); | ||
| 1442 | write(fd, buf, strlen(buf)); | ||
| 1443 | } | ||
| 1444 | } | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | static void | ||
| 1448 | malloc_dump1(int fd, struct dir_info *d) | ||
| 1449 | { | ||
| 1450 | char buf[64]; | ||
| 1451 | size_t i, realsize; | ||
| 1452 | |||
| 1453 | snprintf(buf, sizeof(buf), "Malloc dir of %s at %p\n", __progname, d); | ||
| 1454 | write(fd, buf, strlen(buf)); | ||
| 1455 | if (d == NULL) | ||
| 1456 | return; | ||
| 1457 | snprintf(buf, sizeof(buf), "Regions slots %zu\n", d->regions_total); | ||
| 1458 | write(fd, buf, strlen(buf)); | ||
| 1459 | snprintf(buf, sizeof(buf), "Finds %zu/%zu %f\n", d->finds, | ||
| 1460 | d->find_collisions, | ||
| 1461 | 1.0 + (double)d->find_collisions / d->finds); | ||
| 1462 | write(fd, buf, strlen(buf)); | ||
| 1463 | snprintf(buf, sizeof(buf), "Inserts %zu/%zu %f\n", d->inserts, | ||
| 1464 | d->insert_collisions, | ||
| 1465 | 1.0 + (double)d->insert_collisions / d->inserts); | ||
| 1466 | write(fd, buf, strlen(buf)); | ||
| 1467 | snprintf(buf, sizeof(buf), "Deletes %zu/%zu\n", d->deletes, | ||
| 1468 | d->delete_moves); | ||
| 1469 | write(fd, buf, strlen(buf)); | ||
| 1470 | snprintf(buf, sizeof(buf), "Cheap reallocs %zu/%zu\n", | ||
| 1471 | d->cheap_reallocs, d->cheap_realloc_tries); | ||
| 1472 | write(fd, buf, strlen(buf)); | ||
| 1473 | snprintf(buf, sizeof(buf), "Regions slots free %zu\n", d->regions_free); | ||
| 1474 | write(fd, buf, strlen(buf)); | ||
| 1475 | for (i = 0; i < d->regions_total; i++) { | ||
| 1476 | if (d->r[i].p != NULL) { | ||
| 1477 | size_t h = hash(d->r[i].p) & | ||
| 1478 | (d->regions_total - 1); | ||
| 1479 | snprintf(buf, sizeof(buf), "%4zx) #%zx %zd ", | ||
| 1480 | i, h, h - i); | ||
| 1481 | write(fd, buf, strlen(buf)); | ||
| 1482 | REALSIZE(realsize, &d->r[i]); | ||
| 1483 | if (realsize > MALLOC_MAXCHUNK) { | ||
| 1484 | snprintf(buf, sizeof(buf), | ||
| 1485 | "%p: %zu\n", d->r[i].p, realsize); | ||
| 1486 | write(fd, buf, strlen(buf)); | ||
| 1487 | } else | ||
| 1488 | dump_chunk(fd, | ||
| 1489 | (struct chunk_info *)d->r[i].size, 0); | ||
| 1490 | } | ||
| 1491 | } | ||
| 1492 | dump_free_chunk_info(fd, d); | ||
| 1493 | dump_free_page_info(fd, d); | ||
| 1494 | snprintf(buf, sizeof(buf), "In use %zu\n", malloc_used); | ||
| 1495 | write(fd, buf, strlen(buf)); | ||
| 1496 | snprintf(buf, sizeof(buf), "Guarded %zu\n", malloc_guarded); | ||
| 1497 | write(fd, buf, strlen(buf)); | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | |||
| 1501 | void | ||
| 1502 | malloc_dump(int fd) | ||
| 1503 | { | ||
| 1504 | malloc_dump1(fd, g_pool); | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | static void | ||
| 1508 | malloc_exit(void) | ||
| 1509 | { | ||
| 1510 | static const char q[] = "malloc() warning: Couldn't dump stats\n"; | ||
| 1511 | int save_errno = errno, fd; | ||
| 1512 | |||
| 1513 | fd = open("malloc.out", O_RDWR|O_APPEND); | ||
| 1514 | if (fd != -1) { | ||
| 1515 | malloc_dump(fd); | ||
| 1516 | close(fd); | ||
| 1517 | } else | ||
| 1518 | write(STDERR_FILENO, q, sizeof(q) - 1); | ||
| 1519 | errno = save_errno; | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | #endif /* MALLOC_STATS */ | ||
