Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / sgen / sgen-nursery-allocator.c
index e42e3bf64aa75efc7001025dbb4a124c254d0576..53a7999a74e88ff75f06565f4c59fb3134f510b6 100644 (file)
@@ -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