2010-03-08 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Mon, 8 Mar 2010 16:32:10 +0000 (16:32 -0000)
committerZoltan Varga <vargaz@gmail.com>
Mon, 8 Mar 2010 16:32:10 +0000 (16:32 -0000)
* sgen-gc.c (scan_needed_big_objects): Call drain_gray_stack () to avoid
uncontrolled growth of the gray stack.

* sgen-gray.c: Rewrite this so it behaves like a stack, not a queue, so recently
added items are removed first, improving cache locality. Avoid freeing queue
segments in the fast path, use the list of segments as the free list, truncate
it to its max size at the start of collection.

svn path=/trunk/mono/; revision=153264

mono/metadata/ChangeLog
mono/metadata/sgen-gc.c
mono/metadata/sgen-gray.c

index 9fcda458a0cb26018fa88a79125da94776290cd1..8f11863ddd735f32a22dad7b122e163f99b225c4 100644 (file)
@@ -1,3 +1,12 @@
+2010-03-08  Zoltan Varga  <vargaz@gmail.com>
+
+       * sgen-gc.c (scan_needed_big_objects): Call drain_gray_stack () to avoid
+       uncontrolled growth of the gray stack.
+
+       * sgen-gray.c: Rewrite this so it behaves like a stack, not a queue, so recently
+       added items are removed first, improving cache locality. Avoid freeing queue
+       segments in the fast path, use the list of segments as the free list, truncate
+       it to its max size at the start of collection.
 
 Mon Mar 8 10:13:52 CET 2010 Paolo Molaro <lupus@ximian.com>
 
 
 Mon Mar 8 10:13:52 CET 2010 Paolo Molaro <lupus@ximian.com>
 
index 34edd9024b6da8c368918dc1e41a39035f1db077..e3a7756041456db735498676431e16072c6053ba 100644 (file)
@@ -2833,6 +2833,7 @@ scan_needed_big_objects (char *start_addr, char *end_addr)
                if (!big_object->scanned && object_is_pinned (big_object->data)) {
                        DEBUG (5, fprintf (gc_debug_file, "Scan of big object: %p (%s), size: %zd\n", big_object->data, safe_name (big_object->data), big_object->size));
                        scan_object (big_object->data, start_addr, end_addr);
                if (!big_object->scanned && object_is_pinned (big_object->data)) {
                        DEBUG (5, fprintf (gc_debug_file, "Scan of big object: %p (%s), size: %zd\n", big_object->data, safe_name (big_object->data), big_object->size));
                        scan_object (big_object->data, start_addr, end_addr);
+                       drain_gray_stack (start_addr, end_addr);
                        big_object->scanned = TRUE;
                        count++;
                }
                        big_object->scanned = TRUE;
                        count++;
                }
index 42f86383bc57aa92b8d12288f9c4670c362f8271..5088eb3c35ac861e20207470629563d6a2fe7485 100644 (file)
@@ -1,20 +1,21 @@
-#define GRAY_QUEUE_SECTION_SIZE        125
+#define GRAY_QUEUE_SECTION_SIZE        (128 - 4)
 #define GRAY_QUEUE_LENGTH_LIMIT        64
 
 #define GRAY_QUEUE_LENGTH_LIMIT        64
 
+/*
+ * This is a stack now instead of a queue, so the most recently added items are removed
+ * first, improving cache locality, and keeping the stack size manageable.
+ */
 typedef struct _GrayQueueSection GrayQueueSection;
 struct _GrayQueueSection {
        int start;
        int end;
 typedef struct _GrayQueueSection GrayQueueSection;
 struct _GrayQueueSection {
        int start;
        int end;
-       GrayQueueSection *next;
+       GrayQueueSection *next, *prev;
        char *objects [GRAY_QUEUE_SECTION_SIZE];
 };
 
 static GrayQueueSection *gray_queue_start = NULL;
 static GrayQueueSection *gray_queue_end = NULL;
 
        char *objects [GRAY_QUEUE_SECTION_SIZE];
 };
 
 static GrayQueueSection *gray_queue_start = NULL;
 static GrayQueueSection *gray_queue_end = NULL;
 
-static GrayQueueSection *gray_queue_section_free_list = NULL;
-static int gray_queue_free_list_length = 0;
-
 static int gray_queue_balance = 0;
 static int num_gray_queue_sections = 0;
 
 static int gray_queue_balance = 0;
 static int num_gray_queue_sections = 0;
 
@@ -23,32 +24,49 @@ gray_object_alloc_queue_section (void)
 {
        GrayQueueSection *section;
 
 {
        GrayQueueSection *section;
 
-       if (gray_queue_section_free_list) {
-               section = gray_queue_section_free_list;
-               gray_queue_section_free_list = gray_queue_section_free_list->next;
-               --gray_queue_free_list_length;
-       } else {
-               section = get_internal_mem (sizeof (GrayQueueSection), INTERNAL_MEM_GRAY_QUEUE);
-               ++num_gray_queue_sections;
+       /* Use the previously allocated queue sections if possible */
+       if (!gray_queue_end && gray_queue_start) {
+               gray_queue_end = gray_queue_start;
+               gray_queue_end->start = gray_queue_end->end = 0;
+               return;
        }
        }
+       if (gray_queue_end && gray_queue_end->next) {
+               gray_queue_end = gray_queue_end->next;
+               gray_queue_end->start = gray_queue_end->end = 0;
+               return;
+       }
+
+       /* Allocate a new section */
+       section = get_internal_mem (sizeof (GrayQueueSection), INTERNAL_MEM_GRAY_QUEUE);
+       ++num_gray_queue_sections;
 
        section->start = section->end = 0;
        section->next = NULL;
 
        section->start = section->end = 0;
        section->next = NULL;
+       section->prev = NULL;
 
 
+       /* Link it with the others */
        if (gray_queue_end) {
        if (gray_queue_end) {
-               g_assert (gray_queue_start);
-               gray_queue_end = gray_queue_end->next = section;
+               gray_queue_end->next = section;
+               section->prev = gray_queue_end;
        } else {
                g_assert (!gray_queue_start);
        } else {
                g_assert (!gray_queue_start);
-               gray_queue_start = gray_queue_end = section;
+               gray_queue_start = section;
        }
        }
+       gray_queue_end = section;
 }
 
 static void
 }
 
 static void
+gray_object_free_queue_section (GrayQueueSection *section)
+{
+       free_internal_mem (section, INTERNAL_MEM_GRAY_QUEUE);
+       --num_gray_queue_sections;
+}
+
+static inline void
 gray_object_enqueue (char *obj)
 {
        g_assert (obj);
 gray_object_enqueue (char *obj)
 {
        g_assert (obj);
-       if (!gray_queue_end || gray_queue_end->end == GRAY_QUEUE_SECTION_SIZE)
+       if (G_UNLIKELY (!gray_queue_end || gray_queue_end->end == GRAY_QUEUE_SECTION_SIZE))
                gray_object_alloc_queue_section ();
        g_assert (gray_queue_end && gray_queue_end->end < GRAY_QUEUE_SECTION_SIZE);
        gray_queue_end->objects [gray_queue_end->end++] = obj;
                gray_object_alloc_queue_section ();
        g_assert (gray_queue_end && gray_queue_end->end < GRAY_QUEUE_SECTION_SIZE);
        gray_queue_end->objects [gray_queue_end->end++] = obj;
@@ -56,19 +74,13 @@ gray_object_enqueue (char *obj)
        ++gray_queue_balance;
 }
 
        ++gray_queue_balance;
 }
 
-static gboolean
+static inline gboolean
 gray_object_queue_is_empty (void)
 {
 gray_object_queue_is_empty (void)
 {
-       if (!gray_queue_start) {
-               g_assert (!gray_queue_end);
-               return TRUE;
-       } else {
-               g_assert (gray_queue_end);
-               return FALSE;
-       }
+       return gray_queue_end == NULL;
 }
 
 }
 
-static char*
+static inline char*
 gray_object_dequeue (void)
 {
        char *obj;
 gray_object_dequeue (void)
 {
        char *obj;
@@ -76,24 +88,12 @@ gray_object_dequeue (void)
        if (gray_object_queue_is_empty ())
                return NULL;
 
        if (gray_object_queue_is_empty ())
                return NULL;
 
-       g_assert (gray_queue_start->start < gray_queue_start->end);
+       g_assert (gray_queue_end->start < gray_queue_end->end);
 
 
-       obj = gray_queue_start->objects [gray_queue_start->start++];
+       obj = gray_queue_end->objects [--gray_queue_end->end];
 
 
-       if (gray_queue_start->start == gray_queue_start->end) {
-               GrayQueueSection *section = gray_queue_start->next;
-               if (gray_queue_free_list_length >= GRAY_QUEUE_LENGTH_LIMIT) {
-                       free_internal_mem (gray_queue_start, INTERNAL_MEM_GRAY_QUEUE);
-               } else {
-                       gray_queue_start->next = gray_queue_section_free_list;
-                       gray_queue_section_free_list = gray_queue_start;
-                       ++gray_queue_free_list_length;
-               }
-               if (section)
-                       gray_queue_start = section;
-               else
-                       gray_queue_start = gray_queue_end = NULL;
-       }
+       if (G_UNLIKELY (gray_queue_end->start == gray_queue_end->end))
+               gray_queue_end = gray_queue_end->prev;
 
        --gray_queue_balance;
 
 
        --gray_queue_balance;
 
@@ -103,7 +103,23 @@ gray_object_dequeue (void)
 static void
 gray_object_queue_init (void)
 {
 static void
 gray_object_queue_init (void)
 {
+       GrayQueueSection *section, *next;
+       int i;
+
        g_assert (gray_object_queue_is_empty ());
        g_assert (sizeof (GrayQueueSection) < MAX_FREELIST_SIZE);
        g_assert (gray_queue_balance == 0);
        g_assert (gray_object_queue_is_empty ());
        g_assert (sizeof (GrayQueueSection) < MAX_FREELIST_SIZE);
        g_assert (gray_queue_balance == 0);
+
+       /* Free the extra sections allocated during the last collection */
+       i = 0;
+       for (section = gray_queue_start; section && i < GRAY_QUEUE_LENGTH_LIMIT; section = section->next)
+               i ++;
+       if (section) {
+               if (section->prev)
+                       section->prev->next = NULL;
+               for (; section; section = next) {
+                       next = section->next;
+                       gray_object_free_queue_section (section);
+               }
+       }
 }
 }