Commit b7939fec authored by rtoy's avatar rtoy
Browse files

Add some heuristics to gc_alloc (and gc_alloc_unboxed), based on

some suggestions from Douglas.

Currently, if there's not enough free space left in the region, a
large alloc is done.  Douglahs suggested increasing the threshold,
which we have increased from 32 to PAGE_SIZE/64.

Also, he mentioned it's a bug that we abandon the region if we have a
large object allocate.  We now also do a large alloc if the object is
large enough.  (The object won't get copied in the next GC, so that's
a win.)

Finally, we add a simple heuristic where we keep track of how many
consecutive large allocs have been done.  If the threshold is
exceeded, we abandon the region (wasting space) and allocate a new
region.  This prevents spectacularly bad performance (10 times slower
or more) on sparc when the object is small, and there's some room in
the region but not enough for the object.  The boxed region would
never get updated so the allocation would never be inline.

For debugging, the consecutive alloc limit is a variable.  We also
keep track of how many times we abandon a region.
parent a771ba8a
Loading
Loading
Loading
Loading
+63 −16
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@
 *
 * Douglas Crosher, 1996, 1997, 1998, 1999.
 *
 * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/gencgc.c,v 1.95.2.1.2.3 2009/04/29 21:28:04 rtoy Exp $
 * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/gencgc.c,v 1.95.2.1.2.4 2009/05/01 16:09:10 rtoy Exp $
 *
 */

@@ -1588,6 +1588,30 @@ gc_alloc_large(int nbytes, int unboxed, struct alloc_region *alloc_region)
    return (void *) (page_address(first_page) + orig_first_page_bytes_used);
}

/*
 * If the current region has more than this much space left, we don't
 * want to abandon the region (wasting space), but do a "large" alloc
 * to a new region.
 */

#define REGION_EMPTY_THRESHOLD  (PAGE_SIZE >> 6)

/*
 * How many consecutive large alloc we can do before we abandon the
 * current region
 */
int consecutive_large_alloc_limit = 10;


/*
 * This is for debugging.  It gets incremented every time we have to
 * abandon the current region, because we done too many gc_alloc's in
 * the current region without changing the region.
 */
int abandon_boxed_region_count = 0;
int abandon_unboxed_region_count = 0;


/*
 * Allocate bytes from the boxed_region. It first checks if there is
 * room, if not then it calls gc_alloc_new_region to find a new region
@@ -1597,6 +1621,8 @@ static void *
gc_alloc(int nbytes)
{
    char *new_free_pointer;
    static int consecutive_large_alloc = 0;
    

#if 0
    fprintf(stderr, "gc_alloc %d\n", nbytes);
@@ -1618,6 +1644,8 @@ gc_alloc(int nbytes)
	    /* Setup a new region. */
	    gc_alloc_new_region(32, 0, &boxed_region);
	}

        consecutive_large_alloc = 0;
	return (void *) new_obj;
    }

@@ -1627,7 +1655,7 @@ gc_alloc(int nbytes)
     * If there is a bit of room left in the current region then
     * allocate a large object.
     */
#if (defined(i386) || defined(__x86_64))

    /*
     * This has potentially very bad behavior on sparc if the current
     * boxed region is too small for the allocation, but the free
@@ -1637,20 +1665,32 @@ gc_alloc(int nbytes)
     * change boxed_region, the next allocation will again be
     * out-of-line and we hit a kernel trap again.  And so on, so we
     * waste all of our time doing kernel traps to allocate small
     * things.  So disable this test on sparc.  This should also be a
     * problem on ppc, but I didn't test it.
     * things.  This also affects ppc.
     *
     * X86 seems not affected or affected as badly, perhaps because
     * x86 doesn't do a kernel trap to handle allocation.  Didn't test
     * this either, but we leave this in for x86.
     * X86 has the same issue, but the affect is less because the
     * out-of-line allocation is a just a function call, not a kernel
     * trap.
     *
     * We should also do a large alloc if the object is large, even if
     * the free space left in the region is too small.  This helps GC
     * so we don't have to copy this object again.
     *
     * Heuristic: If
     * we do too many consecutive large allocations because the
     * current region has some space left, we give up and abandon the
     * region. This will prevent the bad scenario above from killing
     * gc allocation performance.
     *
     * I don't know what the impact of this change will be except that
     * regions may have wasted space in them when they could have had
     * other thing allocated in the region.
     */
    if (boxed_region.end_addr - boxed_region.free_pointer > 32)
    if ((boxed_region.end_addr - boxed_region.free_pointer > REGION_EMPTY_THRESHOLD)
        || (nbytes >= large_object_size)
        || (consecutive_large_alloc < consecutive_large_alloc_limit)) {
        ++consecutive_large_alloc;
	return gc_alloc_large(nbytes, 0, &boxed_region);
#endif
    }
    
    consecutive_large_alloc = 0;
    ++abandon_boxed_region_count;

    /* Else find a new region. */

@@ -1749,6 +1789,7 @@ static void *
gc_alloc_unboxed(int nbytes)
{
    char *new_free_pointer;
    static int consecutive_large_alloc = 0;

#if 0
    fprintf(stderr, "gc_alloc_unboxed %d\n", nbytes);
@@ -1772,6 +1813,7 @@ gc_alloc_unboxed(int nbytes)
	    gc_alloc_new_region(32, 1, &unboxed_region);
	}

        consecutive_large_alloc = 0;
	return (void *) new_obj;
    }

@@ -1782,11 +1824,16 @@ gc_alloc_unboxed(int nbytes)
     * allocate a large object.
     */

#if (defined(i386) || defined(__x86_64))
    /* See gc_alloc for the reason for this */
    if (unboxed_region.end_addr - unboxed_region.free_pointer > 32)
    /* See gc_alloc for what we're doing here. */
    if ((unboxed_region.end_addr - unboxed_region.free_pointer > REGION_EMPTY_THRESHOLD)
        || (nbytes >= large_object_size)
        || (consecutive_large_alloc < consecutive_large_alloc_limit)) {
        ++consecutive_large_alloc;
	return gc_alloc_large(nbytes, 1, &unboxed_region);
#endif
    }

    consecutive_large_alloc = 0;
    ++abandon_unboxed_region_count;

    /* Else find a new region. */