unlock_section_queue (queue);
}
+/*
+ * Compacts and attempts to fill the prefetch queue from the gray
+ * queue. Returns whether the prefetch queue contains any elements.
+ */
+gboolean
+sgen_gray_object_fill_prefetch (SgenGrayQueue *queue)
+{
+ GrayQueueEntry *to = queue->prefetch;
+ GrayQueueEntry *from = queue->prefetch;
+ GrayQueueEntry *const end = queue->prefetch + SGEN_GRAY_QUEUE_PREFETCH_SIZE;
+ while (from < end) {
+ if (from->obj)
+ *to++ = *from;
+ ++from;
+ }
+ while (to < end) {
+ GRAY_OBJECT_DEQUEUE (queue, &to->obj, &to->desc);
+ /* This doesn't necessarily matter because this function constitutes the slow path. */
+ PREFETCH (to->obj);
+ ++to;
+ }
+ queue->prefetch_cursor = queue->prefetch;
+ return queue->prefetch [0].obj != NULL;
+}
+
void
sgen_init_gray_queues (void)
{
typedef void (*GrayQueueAllocPrepareFunc) (SgenGrayQueue*);
typedef void (*GrayQueueEnqueueCheckFunc) (char*);
+#define SGEN_GRAY_QUEUE_PREFETCH_SIZE (2)
+
struct _SgenGrayQueue {
GrayQueueEntry *cursor;
GrayQueueSection *first;
GrayQueueEnqueueCheckFunc enqueue_check_func;
#endif
void *alloc_prepare_data;
+ GrayQueueEntry prefetch [SGEN_GRAY_QUEUE_PREFETCH_SIZE];
+ GrayQueueEntry *prefetch_cursor;
};
typedef struct _SgenSectionGrayQueue SgenSectionGrayQueue;
GrayQueueSection* sgen_section_gray_queue_dequeue (SgenSectionGrayQueue *queue) MONO_INTERNAL;
void sgen_section_gray_queue_enqueue (SgenSectionGrayQueue *queue, GrayQueueSection *section) MONO_INTERNAL;
+gboolean sgen_gray_object_fill_prefetch (SgenGrayQueue *queue);
+
static inline gboolean
sgen_gray_object_queue_is_empty (SgenGrayQueue *queue)
{
#endif
}
+static inline void
+sgen_gray_object_dequeue_fast (SgenGrayQueue *queue, char** obj, mword *desc) {
+ GrayQueueEntry *cursor = queue->prefetch_cursor;
+ GrayQueueEntry *const end = queue->prefetch + SGEN_GRAY_QUEUE_PREFETCH_SIZE;
+ *obj = cursor->obj;
+ *desc = cursor->desc;
+ GRAY_OBJECT_DEQUEUE (queue, &cursor->obj, &cursor->desc);
+ PREFETCH (cursor->obj);
+ ++cursor;
+ if (cursor == end)
+ cursor = queue->prefetch;
+ queue->prefetch_cursor = cursor;
+}
+
#endif
static long long stat_optimized_nursery_regular;
static long long stat_optimized_major;
static long long stat_optimized_major_forwarded;
-static long long stat_optimized_major_small;
+static long long stat_optimized_major_small_fast;
+static long long stat_optimized_major_small_slow;
static long long stat_optimized_major_large;
+
+static long long stat_drain_prefetch_fills;
+static long long stat_drain_prefetch_fill_failures;
+static long long stat_drain_loops;
#endif
/* Returns whether the object is still in the nursery. */
SGEN_ASSERT (0, ctx.scan_func == major_scan_object, "Wrong scan function");
+ HEAVY_STAT (++stat_drain_prefetch_fills);
+ if (!sgen_gray_object_fill_prefetch (queue)) {
+ HEAVY_STAT (++stat_drain_prefetch_fill_failures);
+ return TRUE;
+ }
+
for (;;) {
char *obj;
mword desc;
int type;
- GRAY_OBJECT_DEQUEUE (queue, &obj, &desc);
- if (!obj)
- return TRUE;
+
+ HEAVY_STAT (++stat_drain_loops);
+
+ sgen_gray_object_dequeue_fast (queue, &obj, &desc);
+ if (!obj) {
+ HEAVY_STAT (++stat_drain_prefetch_fills);
+ if (!sgen_gray_object_fill_prefetch (queue)) {
+ HEAVY_STAT (++stat_drain_prefetch_fill_failures);
+ return TRUE;
+ }
+ continue;
+ }
+
+#ifdef HEAVY_STATISTICS
+ sgen_descriptor_count_scanned_object (desc);
+#endif
type = desc & 7;
if (type == DESC_TYPE_SMALL_BITMAP) {
void **_objptr = (void**)(obj);
void *__old = *(_objptr);
if (__old) {
gboolean still_in_nursery;
- PREFETCH (__old);
still_in_nursery = optimized_copy_or_mark_object (_objptr, __old, queue);
if (G_UNLIKELY (still_in_nursery && !sgen_ptr_in_nursery ((_objptr)))) {
void *__copy = *(_objptr);
mono_counters_register ("Optimized nursery regular", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_nursery_regular);
mono_counters_register ("Optimized major", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_major);
mono_counters_register ("Optimized major forwarded", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_major_forwarded);
- mono_counters_register ("Optimized major small", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_major_small);
+ mono_counters_register ("Optimized major small fast", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_major_small_fast);
+ mono_counters_register ("Optimized major small slow", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_major_small_slow);
mono_counters_register ("Optimized major large", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_optimized_major_large);
+
+ mono_counters_register ("Gray stack drain loops", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_drain_loops);
+ mono_counters_register ("Gray stack prefetch fills", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_drain_prefetch_fills);
+ mono_counters_register ("Gray stack prefetch failures", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_drain_prefetch_fill_failures);
#endif
#endif