diff options
author | Surya Prakki <Surya.Prakki@Sun.COM> | 2009-02-10 20:45:27 -0800 |
---|---|---|
committer | Surya Prakki <Surya.Prakki@Sun.COM> | 2009-02-10 20:45:27 -0800 |
commit | db3659e514c8bf3f03bcca6dd082e363bd7b466a (patch) | |
tree | 6969110633c12e2c4a186af162ed47709e039206 /usr/src | |
parent | 84e1ed4249618c81c3c770730fe3e5ba51a9a246 (diff) | |
download | illumos-gate-db3659e514c8bf3f03bcca6dd082e363bd7b466a.tar.gz |
6794660 Optimize realloc() of libmtmalloc for normal sized caches
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/libmtmalloc/common/mtmalloc.c | 148 | ||||
-rw-r--r-- | usr/src/lib/libmtmalloc/tests/Makefile | 14 | ||||
-rw-r--r-- | usr/src/lib/libmtmalloc/tests/reallocs.c | 54 |
3 files changed, 140 insertions, 76 deletions
diff --git a/usr/src/lib/libmtmalloc/common/mtmalloc.c b/usr/src/lib/libmtmalloc/common/mtmalloc.c index bce5e872f5..91d9ae2371 100644 --- a/usr/src/lib/libmtmalloc/common/mtmalloc.c +++ b/usr/src/lib/libmtmalloc/common/mtmalloc.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <mtmalloc.h> #include "mtmalloc_impl.h" #include <unistd.h> @@ -267,6 +265,21 @@ realloc(void * ptr, size_t bytes) data_ptr = ptr; mem = (caddr_t)ptr - OVERHEAD; + /* + * Optimization possibility : + * p = malloc(64); + * q = realloc(p, 64); + * q can be same as p. + * Apply this optimization for the normal + * sized caches for now. + */ + if (*(uintptr_t *)mem < MTMALLOC_OVERSIZE_MAGIC || + *(uintptr_t *)mem > MTMALLOC_MEMALIGN_MIN_MAGIC) { + cacheptr = (cache_t *)*(uintptr_t *)mem; + if (bytes <= (cacheptr->mt_size - OVERHEAD)) + return (ptr); + } + new = malloc(bytes); if (new == NULL) @@ -308,7 +321,7 @@ realloc(void * ptr, size_t bytes) cacheptr = (cache_t *)*(uintptr_t *)mem; (void) memcpy(new, data_ptr, - MIN(cacheptr->mt_size - OVERHEAD - shift, bytes)); + MIN(cacheptr->mt_size - OVERHEAD - shift, bytes)); free(ptr); return (new); @@ -439,9 +452,8 @@ memalign(size_t alignment, size_t size) void *alloc_buf; void *ret_buf; - if (size == 0 || alignment == 0 || - misaligned(alignment) || - (alignment & (alignment - 1)) != 0) { + if (size == 0 || alignment == 0 || misaligned(alignment) || + (alignment & (alignment - 1)) != 0) { errno = EINVAL; return (NULL); } @@ -477,7 +489,7 @@ memalign(size_t alignment, size_t size) /* aligned correctly */ size_t frag_size = alloc_size - - (size + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); + (size + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); /* * If the leftover piece of the memory > MAX_CACHED, @@ -488,12 +500,12 @@ memalign(size_t alignment, size_t size) uintptr_t taddr; size_t data_size; taddr = ALIGN((uintptr_t)alloc_buf + size, - MTMALLOC_MIN_ALIGN); + MTMALLOC_MIN_ALIGN); data_size = taddr - (uintptr_t)alloc_buf; orig = (oversize_t *)((uintptr_t)alloc_buf - - OVSZ_HEADER_SIZE); + OVSZ_HEADER_SIZE); frag_size = orig->size - data_size - - OVSZ_HEADER_SIZE; + OVSZ_HEADER_SIZE; orig->size = data_size; tail = oversize_header_alloc(taddr, frag_size); free_oversize(tail); @@ -528,17 +540,17 @@ memalign(size_t alignment, size_t size) head_sz = shift - MAX(MEMALIGN_HEADER_SIZE, OVSZ_HEADER_SIZE); tail_sz = alloc_size - - (shift + size + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); + (shift + size + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); oversize_bits |= IS_OVERSIZE(head_sz, alloc_size) | - IS_OVERSIZE(size, alloc_size) << DATA_SHIFT | - IS_OVERSIZE(tail_sz, alloc_size) << TAIL_SHIFT; + IS_OVERSIZE(size, alloc_size) << DATA_SHIFT | + IS_OVERSIZE(tail_sz, alloc_size) << TAIL_SHIFT; switch (oversize_bits) { case NONE_OVERSIZE: case DATA_OVERSIZE: MEMALIGN_HEADER_ALLOC(ret_addr, shift, - alloc_buf); + alloc_buf); break; case HEAD_OVERSIZE: /* @@ -548,19 +560,19 @@ memalign(size_t alignment, size_t size) * otherwise just create memalign header. */ tsize = (shift + size) - (MAX_CACHED + 8 + - MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); + MTMALLOC_MIN_ALIGN + OVSZ_HEADER_SIZE); if (!IS_OVERSIZE(tsize, alloc_size)) { MEMALIGN_HEADER_ALLOC(ret_addr, shift, - alloc_buf); + alloc_buf); break; } else { tsize += OVSZ_HEADER_SIZE; taddr = ALIGN((uintptr_t)alloc_buf + - tsize, MTMALLOC_MIN_ALIGN); + tsize, MTMALLOC_MIN_ALIGN); tshift = ret_addr - taddr; MEMALIGN_HEADER_ALLOC(ret_addr, tshift, - taddr); + taddr); ret_addr = taddr; shift = ret_addr - (uintptr_t)alloc_buf; } @@ -573,10 +585,9 @@ memalign(size_t alignment, size_t size) * of (data + tail fragment). */ orig = (oversize_t *)((uintptr_t)alloc_buf - - OVSZ_HEADER_SIZE); + OVSZ_HEADER_SIZE); big = oversize_header_alloc(ret_addr - - OVSZ_HEADER_SIZE, - (orig->size - shift)); + OVSZ_HEADER_SIZE, (orig->size - shift)); (void) mutex_lock(&oversize_lock); insert_hash(big); (void) mutex_unlock(&oversize_lock); @@ -592,13 +603,13 @@ memalign(size_t alignment, size_t size) * end, otherwise just create memalign header. */ orig = (oversize_t *)((uintptr_t)alloc_buf - - OVSZ_HEADER_SIZE); + OVSZ_HEADER_SIZE); tsize = orig->size - (MAX_CACHED + 8 + - shift + OVSZ_HEADER_SIZE + - MTMALLOC_MIN_ALIGN); + shift + OVSZ_HEADER_SIZE + + MTMALLOC_MIN_ALIGN); if (!IS_OVERSIZE(tsize, alloc_size)) { MEMALIGN_HEADER_ALLOC(ret_addr, shift, - alloc_buf); + alloc_buf); break; } else { size = MAX_CACHED + 8; @@ -613,15 +624,15 @@ memalign(size_t alignment, size_t size) * (head fragment + data). */ taddr = ALIGN(ret_addr + size, - MTMALLOC_MIN_ALIGN); + MTMALLOC_MIN_ALIGN); data_sz = (size_t)(taddr - - (uintptr_t)alloc_buf); + (uintptr_t)alloc_buf); orig = (oversize_t *)((uintptr_t)alloc_buf - - OVSZ_HEADER_SIZE); + OVSZ_HEADER_SIZE); tsize = orig->size - data_sz; orig->size = data_sz; MEMALIGN_HEADER_ALLOC(ret_buf, shift, - alloc_buf); + alloc_buf); tsize -= OVSZ_HEADER_SIZE; tail = oversize_header_alloc(taddr, tsize); free_oversize(tail); @@ -636,10 +647,10 @@ memalign(size_t alignment, size_t size) * should be oversize in size. */ orig = (oversize_t *)((uintptr_t)alloc_buf - - OVSZ_HEADER_SIZE); + OVSZ_HEADER_SIZE); tsize = orig->size - (MAX_CACHED + 8 + - OVSZ_HEADER_SIZE + shift + - MTMALLOC_MIN_ALIGN); + OVSZ_HEADER_SIZE + shift + + MTMALLOC_MIN_ALIGN); if (!IS_OVERSIZE(tsize, alloc_size)) { /* @@ -648,13 +659,12 @@ memalign(size_t alignment, size_t size) * we just keep them as one piece. */ big = oversize_header_alloc(ret_addr - - OVSZ_HEADER_SIZE, - orig->size - shift); + OVSZ_HEADER_SIZE, + orig->size - shift); (void) mutex_lock(&oversize_lock); insert_hash(big); (void) mutex_unlock(&oversize_lock); - orig->size = shift - - OVSZ_HEADER_SIZE; + orig->size = shift - OVSZ_HEADER_SIZE; free_oversize(orig); break; } else { @@ -673,22 +683,22 @@ memalign(size_t alignment, size_t size) * Alloc oversize header for data seg. */ orig = (oversize_t *)((uintptr_t)alloc_buf - - OVSZ_HEADER_SIZE); + OVSZ_HEADER_SIZE); tsize = orig->size; orig->size = shift - OVSZ_HEADER_SIZE; free_oversize(orig); taddr = ALIGN(ret_addr + size, - MTMALLOC_MIN_ALIGN); + MTMALLOC_MIN_ALIGN); data_sz = taddr - ret_addr; assert(tsize > (shift + data_sz + - OVSZ_HEADER_SIZE)); + OVSZ_HEADER_SIZE)); tail_sz = tsize - - (shift + data_sz + OVSZ_HEADER_SIZE); + (shift + data_sz + OVSZ_HEADER_SIZE); /* create oversize header for data seg */ big = oversize_header_alloc(ret_addr - - OVSZ_HEADER_SIZE, data_sz); + OVSZ_HEADER_SIZE, data_sz); (void) mutex_lock(&oversize_lock); insert_hash(big); (void) mutex_unlock(&oversize_lock); @@ -904,10 +914,10 @@ create_cache(cache_t *cp, size_t size, uint_t chunksize) *(cp->mt_freelist) = mask; } else { cp->mt_arena = (caddr_t)ALIGN((caddr_t)cp->mt_freelist + - nblocks, 32); + nblocks, 32); /* recompute nblocks */ nblocks = (uintptr_t)((caddr_t)cp->mt_freelist + - cp->mt_span - cp->mt_arena) / cp->mt_size; + cp->mt_span - cp->mt_arena) / cp->mt_size; cp->mt_nfree = ((nblocks >> 3) << 3); /* Set everything to free */ (void) memset(cp->mt_freelist, 0xff, nblocks >> 3); @@ -938,9 +948,9 @@ reinit_cpu_list(void) for (cpuptr = &cpu_list[0]; cpuptr < &cpu_list[ncpus]; cpuptr++) { (void) mutex_lock(&cpuptr->mt_parent_lock); for (cachehead = &cpuptr->mt_caches[0]; cachehead < - &cpuptr->mt_caches[NUM_CACHES]; cachehead++) { + &cpuptr->mt_caches[NUM_CACHES]; cachehead++) { for (thiscache = cachehead->mt_cache; thiscache != NULL; - thiscache = thiscache->mt_next) { + thiscache = thiscache->mt_next) { (void) mutex_lock(&thiscache->mt_cache_lock); if (thiscache->mt_nfree == 0) { (void) mutex_unlock( @@ -967,17 +977,17 @@ reinit_cache(cache_t *thiscache) freeblocks = (uint32_t *)thiscache->mt_freelist; while (freeblocks < (uint32_t *)thiscache->mt_arena) { if (*freeblocks & 0xffffffff) { - for (i = 0; i < 32; i++) { - if (FLIP_EM(*freeblocks) & (0x80000000 >> i)) { - n = (uintptr_t)(((freeblocks - - (uint32_t *)thiscache->mt_freelist) << 5) - + i) * thiscache->mt_size; - ret = thiscache->mt_arena + n; - ret += OVERHEAD; - copy_pattern(FREEPATTERN, ret, - thiscache->mt_size); + for (i = 0; i < 32; i++) { + if (FLIP_EM(*freeblocks) & (0x80000000 >> i)) { + n = (uintptr_t)(((freeblocks - + (uint32_t *)thiscache->mt_freelist) + << 5) + i) * thiscache->mt_size; + ret = thiscache->mt_arena + n; + ret += OVERHEAD; + copy_pattern(FREEPATTERN, ret, + thiscache->mt_size); + } } - } } freeblocks++; } @@ -1043,9 +1053,9 @@ malloc_internal(size_t size, percpu_t *cpuptr) thiscache = (cache_t *)morecore(thisrequest * HUNKSIZE); if (thiscache == (cache_t *)-1) { - (void) mutex_unlock(&cpuptr->mt_parent_lock); - errno = EAGAIN; - return (NULL); + (void) mutex_unlock(&cpuptr->mt_parent_lock); + errno = EAGAIN; + return (NULL); } create_cache(thiscache, buffer_size, thisrequest); @@ -1105,7 +1115,7 @@ malloc_internal(size_t size, percpu_t *cpuptr) (void) mutex_unlock(&cpuptr->mt_parent_lock); n = (uintptr_t)(((freeblocks - (uint32_t *)thiscache->mt_freelist) << 5) - + i) * thiscache->mt_size; + + i) * thiscache->mt_size; /* * Now you have the offset in n, you've changed the free mask * in the freelist. Nothing left to do but find the block @@ -1123,7 +1133,7 @@ malloc_internal(size_t size, percpu_t *cpuptr) * owned by this cache. */ assert(ret + thiscache->mt_size <= thiscache->mt_freelist + - thiscache->mt_span); + thiscache->mt_span); ret += OVERHEAD; @@ -1332,14 +1342,14 @@ add_oversize(oversize_t *lp) if (nx->size) { - /* Check for adjacency with right chunk */ - if ((uintptr_t)nx == endp_lp) { - size_nx = OVSZ_HEADER_SIZE + nx->size; - endp_nx = ALIGN((uintptr_t)nx + size_nx, - MTMALLOC_MIN_ALIGN); - size_nx = endp_nx - (uintptr_t)nx; - merge_flags |= COALESCE_RIGHT; - } + /* Check for adjacency with right chunk */ + if ((uintptr_t)nx == endp_lp) { + size_nx = OVSZ_HEADER_SIZE + nx->size; + endp_nx = ALIGN((uintptr_t)nx + size_nx, + MTMALLOC_MIN_ALIGN); + size_nx = endp_nx - (uintptr_t)nx; + merge_flags |= COALESCE_RIGHT; + } } /* diff --git a/usr/src/lib/libmtmalloc/tests/Makefile b/usr/src/lib/libmtmalloc/tests/Makefile index 71bbc8e15a..1527dcb873 100644 --- a/usr/src/lib/libmtmalloc/tests/Makefile +++ b/usr/src/lib/libmtmalloc/tests/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,13 +19,11 @@ # CDDL HEADER END # # -# Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# -PROGS = dblfree exhaust align dirtymem general wideload failwide +PROGS = dblfree exhaust align dirtymem general wideload failwide reallocs all: ${PROGS} @@ -51,5 +48,8 @@ wideload: wideload.c failwide: failwide.c cc -o $@ -O $? -L../${MACH} -R../${MACH} -lmtmalloc +reallocs: reallocs.c + cc -o $@ -O $? -L../${MACH} -R../${MACH} -lmtmalloc + clobber clean: rm -f ${PROGS} core diff --git a/usr/src/lib/libmtmalloc/tests/reallocs.c b/usr/src/lib/libmtmalloc/tests/reallocs.c new file mode 100644 index 0000000000..c734b005fb --- /dev/null +++ b/usr/src/lib/libmtmalloc/tests/reallocs.c @@ -0,0 +1,54 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <stdio.h> +#include <stdlib.h> + +/* + * realloc() optimization for Small sized caches. + * If a malloc'ed buffer can satisfy a realloc() request + * as well, it should return the same buffer. + * + * cc -O -o reallocs reallocs.c -lmtmalloc + */ + +#define MAX_CACHE_SZ 65536 + +int +main() +{ + void *p, *q; + size_t size; + + for (size = 1; size <= MAX_CACHE_SZ; size++) { + p = malloc(size); + q = realloc(p, size); + if (p != q) + (void) fprintf(stderr, "size: %d, p: 0x%p, q: 0x%p\n", + size, p, q); + free(q); + } + return (0); +} |