if (has_references) {
SGEN_LOG (9, "Enqueuing gray object %p (%s)", destination, sgen_client_vtable_get_name (vt));
- GRAY_OBJECT_ENQUEUE (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
+ GRAY_OBJECT_ENQUEUE_SERIAL (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
}
return (GCObject *)destination;
/* In a racing case, only the worker that allocated the object enqueues it */
if (has_references) {
SGEN_LOG (9, "Enqueuing gray object %p (%s)", destination, sgen_client_vtable_get_name (vt));
- GRAY_OBJECT_ENQUEUE (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
+ GRAY_OBJECT_ENQUEUE_PARALLEL (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
}
} else {
destination = final_destination;
for (;;) {
GCObject *obj;
SgenDescriptor desc;
- GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
+ GRAY_OBJECT_DEQUEUE_PARALLEL (queue, &obj, &desc);
if (!obj)
return TRUE;
SGEN_LOG (9, "Precise gray object scan %p (%s)", obj, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (obj)));
safe_object_get_size (obj_to_pin));
pin_object (obj_to_pin);
- GRAY_OBJECT_ENQUEUE (queue, obj_to_pin, desc);
+ GRAY_OBJECT_ENQUEUE_SERIAL (queue, obj_to_pin, desc);
sgen_pin_stats_register_object (obj_to_pin, GENERATION_NURSERY);
definitely_pinned [count] = obj_to_pin;
count++;
++objects_pinned;
sgen_pin_stats_register_object (object, GENERATION_NURSERY);
- GRAY_OBJECT_ENQUEUE (queue, object, sgen_obj_get_descriptor_safe (object));
+ GRAY_OBJECT_ENQUEUE_SERIAL (queue, object, sgen_obj_get_descriptor_safe (object));
}
/* Sort the addresses in array in increasing order.
}
sgen_los_pin_object (bigobj->data);
if (SGEN_OBJECT_HAS_REFERENCES (bigobj->data))
- GRAY_OBJECT_ENQUEUE (gc_thread_gray_queue, bigobj->data, sgen_obj_get_descriptor ((GCObject*)bigobj->data));
+ GRAY_OBJECT_ENQUEUE_SERIAL (gc_thread_gray_queue, bigobj->data, sgen_obj_get_descriptor ((GCObject*)bigobj->data));
sgen_pin_stats_register_object (bigobj->data, GENERATION_OLD);
SGEN_LOG (6, "Marked large object %p (%s) size: %lu from roots", bigobj->data,
sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (bigobj->data)),
static GrayQueueSection *last_gray_queue_free_list;
void
-sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue)
+sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue, gboolean is_parallel)
{
GrayQueueSection *section;
queue->first = section;
queue->cursor = section->entries - 1;
- mono_memory_write_barrier ();
- /*
- * FIXME
- * we could probably optimize the code to only rely on the write barrier
- * for synchronization with the stealer thread. Additionally we could also
- * do a write barrier once every other gray queue change, and request
- * to have a minimum of sections before stealing, to keep consistency.
- */
- InterlockedIncrement (&queue->num_sections);
+ if (is_parallel) {
+ mono_memory_write_barrier ();
+ /*
+ * FIXME
+ * we could probably optimize the code to only rely on the write barrier
+ * for synchronization with the stealer thread. Additionally we could also
+ * do a write barrier once every other gray queue change, and request
+ * to have a minimum of sections before stealing, to keep consistency.
+ */
+ InterlockedIncrement (&queue->num_sections);
+ } else {
+ queue->num_sections++;
+ }
}
void
*/
void
-sgen_gray_object_enqueue (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc)
+sgen_gray_object_enqueue (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc, gboolean is_parallel)
{
GrayQueueEntry entry = SGEN_GRAY_QUEUE_ENTRY (obj, desc);
queue->first->size = SGEN_GRAY_QUEUE_SECTION_SIZE;
}
- sgen_gray_object_alloc_queue_section (queue);
+ sgen_gray_object_alloc_queue_section (queue, is_parallel);
}
STATE_ASSERT (queue->first, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
SGEN_ASSERT (9, queue->cursor <= GRAY_LAST_CURSOR_POSITION (queue->first), "gray queue %p overflow, first %p, cursor %p", queue, queue->first, queue->cursor);
/* Allocate all needed sections */
while (queue->num_sections < num_sections_final)
- sgen_gray_object_alloc_queue_section (queue);
+ sgen_gray_object_alloc_queue_section (queue, TRUE);
/* Spread out the elements in the sections. By design, sections at the end are fuller. */
section_start = queue->first;
}
GrayQueueEntry
-sgen_gray_object_dequeue (SgenGrayQueue *queue)
+sgen_gray_object_dequeue (SgenGrayQueue *queue, gboolean is_parallel)
{
GrayQueueEntry entry;
if (G_UNLIKELY (queue->cursor < GRAY_FIRST_CURSOR_POSITION (queue->first))) {
GrayQueueSection *section;
- gint32 old_num_sections;
+ gint32 old_num_sections = 0;
- old_num_sections = InterlockedDecrement (&queue->num_sections);
+ if (is_parallel)
+ old_num_sections = InterlockedDecrement (&queue->num_sections);
+ else
+ queue->num_sections--;
- if (old_num_sections <= 0) {
+ if (is_parallel && old_num_sections <= 0) {
mono_os_mutex_lock (&queue->steal_mutex);
}
queue->free_list = section;
queue->cursor = queue->first ? queue->first->entries + queue->first->size - 1 : NULL;
- if (old_num_sections <= 0) {
+ if (is_parallel && old_num_sections <= 0) {
mono_os_mutex_unlock (&queue->steal_mutex);
}
}
}
void
-sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section)
+sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section, gboolean is_parallel)
{
STATE_TRANSITION (section, GRAY_QUEUE_SECTION_STATE_FLOATING, GRAY_QUEUE_SECTION_STATE_ENQUEUED);
queue->enqueue_check_func (section->entries [i].obj);
}
#endif
- mono_memory_write_barrier ();
- InterlockedIncrement (&queue->num_sections);
+ if (is_parallel) {
+ mono_memory_write_barrier ();
+ InterlockedIncrement (&queue->num_sections);
+ } else {
+ queue->num_sections++;
+ }
}
void
#define SGEN_GRAY_QUEUE_ENTRY(obj,desc) { (obj), (desc) }
+#define GRAY_OBJECT_ENQUEUE_SERIAL(queue, obj, desc) (GRAY_OBJECT_ENQUEUE (queue, obj, desc, FALSE))
+#define GRAY_OBJECT_ENQUEUE_PARALLEL(queue, obj, desc) (GRAY_OBJECT_ENQUEUE (queue, obj, desc, TRUE))
+#define GRAY_OBJECT_DEQUEUE_SERIAL(queue, obj, desc) (GRAY_OBJECT_DEQUEUE (queue, obj, desc, FALSE))
+#define GRAY_OBJECT_DEQUEUE_PARALLEL(queue, obj, desc) (GRAY_OBJECT_DEQUEUE (queue, obj, desc, TRUE))
+
/*
* 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.
void sgen_init_gray_queues (void);
-void sgen_gray_object_enqueue (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc);
-GrayQueueEntry sgen_gray_object_dequeue (SgenGrayQueue *queue);
+void sgen_gray_object_enqueue (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc, gboolean is_parallel);
+GrayQueueEntry sgen_gray_object_dequeue (SgenGrayQueue *queue, gboolean is_parallel);
GrayQueueSection* sgen_gray_object_dequeue_section (SgenGrayQueue *queue);
GrayQueueSection* sgen_gray_object_steal_section (SgenGrayQueue *queue);
void sgen_gray_object_spread (SgenGrayQueue *queue, int num_sections);
-void sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section);
+void sgen_gray_object_enqueue_section (SgenGrayQueue *queue, GrayQueueSection *section, gboolean is_parallel);
void sgen_gray_object_queue_trim_free_list (SgenGrayQueue *queue);
void sgen_gray_object_queue_init (SgenGrayQueue *queue, GrayQueueEnqueueCheckFunc enqueue_check_func, gboolean reuse_free_list);
void sgen_gray_object_queue_dispose (SgenGrayQueue *queue);
void sgen_gray_object_queue_deinit (SgenGrayQueue *queue);
-void sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue);
+void sgen_gray_object_alloc_queue_section (SgenGrayQueue *queue, gboolean is_parallel);
void sgen_gray_object_free_queue_section (GrayQueueSection *section);
void sgen_section_gray_queue_init (SgenSectionGrayQueue *queue, gboolean locked,
}
static inline MONO_ALWAYS_INLINE void
-GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc)
+GRAY_OBJECT_ENQUEUE (SgenGrayQueue *queue, GCObject *obj, SgenDescriptor desc, gboolean is_parallel)
{
#if SGEN_MAX_DEBUG_LEVEL >= 9
- sgen_gray_object_enqueue (queue, obj, desc);
+ sgen_gray_object_enqueue (queue, obj, desc, is_parallel);
#else
if (G_UNLIKELY (!queue->first || queue->cursor == GRAY_LAST_CURSOR_POSITION (queue->first))) {
- sgen_gray_object_enqueue (queue, obj, desc);
+ sgen_gray_object_enqueue (queue, obj, desc, is_parallel);
} else {
GrayQueueEntry entry = SGEN_GRAY_QUEUE_ENTRY (obj, desc);
}
static inline MONO_ALWAYS_INLINE void
-GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, GCObject** obj, SgenDescriptor *desc)
+GRAY_OBJECT_DEQUEUE (SgenGrayQueue *queue, GCObject** obj, SgenDescriptor *desc, gboolean is_parallel)
{
GrayQueueEntry entry;
#if SGEN_MAX_DEBUG_LEVEL >= 9
- entry = sgen_gray_object_dequeue (queue);
+ entry = sgen_gray_object_dequeue (queue, is_parallel);
*obj = entry.obj;
*desc = entry.desc;
#else
*obj = NULL;
} else if (G_UNLIKELY (queue->cursor == GRAY_FIRST_CURSOR_POSITION (queue->first))) {
- entry = sgen_gray_object_dequeue (queue);
+ entry = sgen_gray_object_dequeue (queue, is_parallel);
*obj = entry.obj;
*desc = entry.desc;
} else {
if (first) {
binary_protocol_pin (obj, (gpointer)SGEN_LOAD_VTABLE (obj), sgen_safe_object_get_size (obj));
if (SGEN_OBJECT_HAS_REFERENCES (obj))
- GRAY_OBJECT_ENQUEUE (queue, obj, desc);
+#ifdef COPY_OR_MARK_PARALLEL
+ GRAY_OBJECT_ENQUEUE_PARALLEL (queue, obj, desc);
+#else
+ GRAY_OBJECT_ENQUEUE_SERIAL (queue, obj, desc);
+#endif
}
}
return FALSE;
HEAVY_STAT (++stat_drain_loops);
- GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
+#if defined(COPY_OR_MARK_PARALLEL)
+ GRAY_OBJECT_DEQUEUE_PARALLEL (queue, &obj, &desc);
+#else
+ GRAY_OBJECT_DEQUEUE_SERIAL (queue, &obj, &desc);
+#endif
if (!obj)
return TRUE;
if (!MS_MARK_BIT ((block), __word, __bit)) { \
MS_SET_MARK_BIT ((block), __word, __bit); \
if (sgen_gc_descr_has_references (desc)) \
- GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \
+ GRAY_OBJECT_ENQUEUE_SERIAL ((queue), (obj), (desc)); \
binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
INC_NUM_MAJOR_OBJECTS_MARKED (); \
} \
MS_SET_MARK_BIT_PAR ((block), __word, __bit, first); \
if (first) { \
if (sgen_gc_descr_has_references (desc)) \
- GRAY_OBJECT_ENQUEUE ((queue), (obj), (desc)); \
+ GRAY_OBJECT_ENQUEUE_PARALLEL ((queue), (obj), (desc)); \
binary_protocol_mark ((obj), (gpointer)SGEN_LOAD_VTABLE ((obj)), sgen_safe_object_get_size ((obj))); \
INC_NUM_MAJOR_OBJECTS_MARKED (); \
} \
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));
if (major->is_concurrent) {
GrayQueueSection *section = sgen_section_gray_queue_dequeue (&workers_distribute_gray_queue);
if (section) {
- sgen_gray_object_enqueue_section (&data->private_gray_queue, section);
+ sgen_gray_object_enqueue_section (&data->private_gray_queue, section, major->is_parallel);
return TRUE;
}
}
}
if (section) {
- sgen_gray_object_enqueue_section (&data->private_gray_queue, section);
+ sgen_gray_object_enqueue_section (&data->private_gray_queue, section, TRUE);
return TRUE;
}