X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fsgen%2Fsgen-nursery-allocator.c;h=53a7999a74e88ff75f06565f4c59fb3134f510b6;hb=HEAD;hp=e42e3bf64aa75efc7001025dbb4a124c254d0576;hpb=88dbb8625b735a08dbd36c9fa1a48bfb67073272;p=mono.git diff --git a/mono/sgen/sgen-nursery-allocator.c b/mono/sgen/sgen-nursery-allocator.c index e42e3bf64aa..53a7999a74e 100644 --- a/mono/sgen/sgen-nursery-allocator.c +++ b/mono/sgen/sgen-nursery-allocator.c @@ -1,5 +1,6 @@ -/* - * sgen-nursery-allocator.c: Nursery allocation code. +/** + * \file + * Nursery allocation code. * * Copyright 2009-2010 Novell, Inc. * 2011 Rodrigo Kumpera @@ -7,18 +8,7 @@ * Copyright 2011 Xamarin Inc (http://www.xamarin.com) * Copyright (C) 2012 Xamarin Inc * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License 2.0 as published by the Free Software Foundation; - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License 2.0 along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ /* @@ -76,16 +66,21 @@ static SgenFragmentAllocator mutator_allocator; /* freeelist of fragment structures */ static SgenFragment *fragment_freelist = NULL; -/* Allocator cursors */ -static char *nursery_last_pinned_end = NULL; - char *sgen_nursery_start; char *sgen_nursery_end; -#ifdef USER_CONFIG -size_t sgen_nursery_size = (1 << 22); -int sgen_nursery_bits = 22; -#endif +/* good sizes are 512KB-1MB: larger ones increase a lot memzeroing time */ +size_t sgen_nursery_size; +/* + * Maximum size that we can resize the nursery to. + * If sgen_nursery_default_size == sgen_nursery_max_size then we are not + * dynamically resizing the nursery + */ +size_t sgen_nursery_max_size; +size_t sgen_nursery_min_size; +/* The number of trailing 0 bits in sgen_nursery_max_size */ +int sgen_nursery_bits; + char *sgen_space_bitmap; size_t sgen_space_bitmap_size; @@ -355,7 +350,7 @@ par_alloc_from_fragment (SgenFragmentAllocator *allocator, SgenFragment *frag, s char *p = frag->fragment_next; char *end = p + size; - if (end > frag->fragment_end) + if (end > frag->fragment_end || end > (sgen_nursery_start + sgen_nursery_size)) return NULL; /* p = frag->fragment_next must happen before */ @@ -449,9 +444,14 @@ sgen_fragment_allocator_par_alloc (SgenFragmentAllocator *allocator, size_t size restart: for (frag = (SgenFragment *)unmask (allocator->alloc_head); unmask (frag); frag = (SgenFragment *)unmask (frag->next)) { + size_t frag_size = frag->fragment_end - frag->fragment_next; + + if (frag->fragment_next >= (sgen_nursery_start + sgen_nursery_size)) + continue; + HEAVY_STAT (++stat_alloc_iterations); - if (size <= (size_t)(frag->fragment_end - frag->fragment_next)) { + if (size <= frag_size) { void *p = par_alloc_from_fragment (allocator, frag, size); if (!p) { HEAVY_STAT (++stat_alloc_retries); @@ -466,33 +466,6 @@ restart: return NULL; } -void* -sgen_fragment_allocator_serial_alloc (SgenFragmentAllocator *allocator, size_t size) -{ - SgenFragment *frag; - SgenFragment **previous; -#ifdef NALLOC_DEBUG - InterlockedIncrement (&alloc_count); -#endif - - previous = &allocator->alloc_head; - - for (frag = *previous; frag; frag = *previous) { - char *p = (char *)serial_alloc_from_fragment (previous, frag, size); - - HEAVY_STAT (++stat_alloc_iterations); - - if (p) { -#ifdef NALLOC_DEBUG - add_alloc_record (p, size, FIXED_ALLOC); -#endif - return p; - } - previous = &frag->next; - } - return NULL; -} - void* sgen_fragment_allocator_serial_range_alloc (SgenFragmentAllocator *allocator, size_t desired_size, size_t minimum_size, size_t *out_alloc_size) { @@ -561,6 +534,9 @@ restart: for (frag = (SgenFragment *)unmask (allocator->alloc_head); frag; frag = (SgenFragment *)unmask (frag->next)) { size_t frag_size = frag->fragment_end - frag->fragment_next; + if (frag->fragment_next >= (sgen_nursery_start + sgen_nursery_size)) + continue; + HEAVY_STAT (++stat_alloc_range_iterations); if (desired_size <= frag_size) { @@ -588,9 +564,8 @@ restart: if (min_frag) { void *p; - size_t frag_size; + size_t frag_size = min_frag->fragment_end - min_frag->fragment_next; - frag_size = min_frag->fragment_end - min_frag->fragment_next; if (frag_size < minimum_size) goto restart; @@ -715,6 +690,26 @@ fragment_list_reverse (SgenFragmentAllocator *allocator) allocator->region_head = allocator->alloc_head = prev; } +/* + * We split fragments at the border of the current nursery limit. When we + * allocate from the nursery we only consider fragments that start in the + * current nursery section. We build fragments for the entire nursery in + * order to facilitate scanning it for objects (adding a nursery frag also + * marks a region in the nursery as being free) + */ +static void +add_nursery_frag_checks (SgenFragmentAllocator *allocator, char *frag_start, char *frag_end) +{ + char *nursery_limit = sgen_nursery_start + sgen_nursery_size; + + if (frag_start < nursery_limit && frag_end > nursery_limit) { + add_nursery_frag (allocator, nursery_limit - frag_start, frag_start, nursery_limit); + add_nursery_frag (allocator, frag_end - nursery_limit, nursery_limit, frag_end); + } else { + add_nursery_frag (allocator, frag_end - frag_start, frag_start, frag_end); + } +} + mword sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpin_queue) { @@ -753,7 +748,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi if (addr0 < addr1) { if (unpin_queue) - GRAY_OBJECT_ENQUEUE (unpin_queue, (GCObject*)addr0, sgen_obj_get_descriptor_safe ((GCObject*)addr0)); + GRAY_OBJECT_ENQUEUE_SERIAL (unpin_queue, (GCObject*)addr0, sgen_obj_get_descriptor_safe ((GCObject*)addr0)); else SGEN_UNPIN_OBJECT (addr0); size = SGEN_ALIGN_UP (sgen_safe_object_get_size ((GCObject*)addr0)); @@ -775,7 +770,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi g_assert (frag_size >= 0); g_assert (size > 0); if (frag_size && size) - add_nursery_frag (&mutator_allocator, frag_size, frag_start, frag_end); + add_nursery_frag_checks (&mutator_allocator, frag_start, frag_end); frag_size = size; #ifdef NALLOC_DEBUG @@ -784,11 +779,10 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi frag_start = frag_end + frag_size; } - nursery_last_pinned_end = frag_start; frag_end = sgen_nursery_end; frag_size = frag_end - frag_start; if (frag_size) - add_nursery_frag (&mutator_allocator, frag_size, frag_start, frag_end); + add_nursery_frag_checks (&mutator_allocator, frag_start, frag_end); /* Now it's safe to release the fragments exclude list. */ sgen_minor_collector.build_fragments_release_exclude_head (); @@ -809,13 +803,6 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section, SgenGrayQueue *unpi return fragment_total; } -char * -sgen_nursery_alloc_get_upper_alloc_bound (void) -{ - /*FIXME we need to calculate the collector upper bound as well, but this must be done in the previous GC. */ - return sgen_nursery_end; -} - /*** Nursery memory allocation ***/ void sgen_nursery_retire_region (void *address, ptrdiff_t size) @@ -907,21 +894,59 @@ sgen_nursery_alloc_prepare_for_major (void) } void -sgen_nursery_allocator_set_nursery_bounds (char *start, char *end) +sgen_nursery_allocator_set_nursery_bounds (char *start, size_t min_size, size_t max_size) { sgen_nursery_start = start; - sgen_nursery_end = end; + sgen_nursery_end = start + max_size; + + sgen_nursery_size = min_size; + sgen_nursery_min_size = min_size; + sgen_nursery_max_size = max_size; + + sgen_nursery_bits = 0; + while (ONE_P << (++ sgen_nursery_bits) != sgen_nursery_max_size) + ; /* * This will not divide evenly for tiny nurseries (<4kb), so we make sure to be on * the right side of things and round up. We could just do a MIN(1,x) instead, * since the nursery size must be a power of 2. */ - sgen_space_bitmap_size = (end - start + SGEN_TO_SPACE_GRANULE_IN_BYTES * 8 - 1) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8); + sgen_space_bitmap_size = (sgen_nursery_end - sgen_nursery_start + SGEN_TO_SPACE_GRANULE_IN_BYTES * 8 - 1) / (SGEN_TO_SPACE_GRANULE_IN_BYTES * 8); sgen_space_bitmap = (char *)g_malloc0 (sgen_space_bitmap_size); /* Setup the single first large fragment */ - sgen_minor_collector.init_nursery (&mutator_allocator, start, end); + sgen_minor_collector.init_nursery (&mutator_allocator, sgen_nursery_start, sgen_nursery_end); +} + +void +sgen_resize_nursery (gboolean need_shrink) +{ + size_t major_size; + + if (sgen_nursery_min_size == sgen_nursery_max_size) + return; + + major_size = major_collector.get_num_major_sections () * major_collector.section_size + los_memory_usage; + /* + * We attempt to use a larger nursery size, as long as it doesn't + * exceed a certain percentage of the major heap. + * + * FIXME + * Commit memory when expanding and release it when shrinking (which + * would only be possible if there aren't any pinned objects in the + * section). + */ + if ((sgen_nursery_size * 2) < (major_size / SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO) && + (sgen_nursery_size * 2) <= sgen_nursery_max_size && !need_shrink) { + if ((nursery_section->end_data - nursery_section->data) == sgen_nursery_size) + nursery_section->end_data += sgen_nursery_size; + sgen_nursery_size *= 2; + } else if ((sgen_nursery_size > (major_size / SGEN_DEFAULT_ALLOWANCE_NURSERY_SIZE_RATIO) || need_shrink) && + (sgen_nursery_size / 2) >= sgen_nursery_min_size) { + sgen_nursery_size /= 2; + } } + #endif