[pypy-commit] pypy quad-color-gc: QCGC update

ntruessel pypy.commits at gmail.com
Thu Sep 15 17:10:55 EDT 2016


Author: Nicolas Truessel <ntruessel at njsm.de>
Branch: quad-color-gc
Changeset: r87127:a870d33012f1
Date: 2016-09-15 18:45 +0200
http://bitbucket.org/pypy/pypy/changeset/a870d33012f1/

Log:	QCGC update

diff --git a/rpython/translator/c/src/qcgc/config.h b/rpython/translator/c/src/qcgc/config.h
--- a/rpython/translator/c/src/qcgc/config.h
+++ b/rpython/translator/c/src/qcgc/config.h
@@ -10,8 +10,8 @@
  */
 #define EVENT_LOG 1							// Enable event log
 #define LOGFILE "./qcgc_events.log"			// Default logfile
-#define LOG_ALLOCATION 0					// Enable allocation log (warning:
-											// significant performance impact)
+#define LOG_ALLOCATION 1					// Enable allocation log
+#define LOG_DUMP_FREELIST_STATS 1			// Dump freelist stats
 
 #define QCGC_SHADOWSTACK_SIZE 163840		// Total shadowstack size
 #define QCGC_ARENA_BAG_INIT_SIZE 16			// Initial size of the arena bag
@@ -31,7 +31,7 @@
 /**
  * Auto Mark/Collect
  */
-#define QCGC_INCMARK_THRESHOLD (1<<QCGC_ARENA_SIZE_EXP)
+#define QCGC_INCMARK_THRESHOLD (1<<(QCGC_ARENA_SIZE_EXP-4))
 #define QCGC_INCMARK_TO_SWEEP 5
 
 /**
diff --git a/rpython/translator/c/src/qcgc/qcgc.c b/rpython/translator/c/src/qcgc/qcgc.c
--- a/rpython/translator/c/src/qcgc/qcgc.c
+++ b/rpython/translator/c/src/qcgc/qcgc.c
@@ -34,7 +34,8 @@
 	qcgc_state.gp_gray_stack = qcgc_gray_stack_create(16); // XXX
 	qcgc_state.gray_stack_size = 0;
 	qcgc_state.phase = GC_PAUSE;
-	qcgc_state.bytes_since_incmark = 0;
+	qcgc_state.cells_since_incmark = 0;
+	qcgc_state.cells_since_collect = 0;
 	qcgc_state.incmark_since_sweep = 0;
 	qcgc_state.free_cells = 0;
 	qcgc_state.largest_free_block = 0;
@@ -62,12 +63,13 @@
 
 object_t *qcgc_allocate(size_t size) {
 #if LOG_ALLOCATION
-	qcgc_event_logger_log(EVENT_ALLOCATE_START, sizeof(size_t),
-			(uint8_t *) &size);
+	size_t cells = bytes_to_cells(size);
+	qcgc_event_logger_log(EVENT_ALLOCATE, sizeof(size_t),
+			(uint8_t *) &cells);
 #endif
 	object_t *result;
 
-	if (UNLIKELY(qcgc_state.bytes_since_incmark >
+	if (UNLIKELY(qcgc_state.cells_since_incmark >
 				qcgc_state.incmark_threshold)) {
 		if (qcgc_state.incmark_since_sweep == qcgc_state.incmark_to_sweep) {
 			qcgc_collect();
@@ -75,13 +77,11 @@
 			qcgc_incmark();
 			qcgc_state.incmark_since_sweep++;
 		}
-		
 	}
 
 	if (LIKELY(size <= 1<<QCGC_LARGE_ALLOC_THRESHOLD_EXP)) {
 		// Use bump / fit allocator
-		//if (qcgc_allocator_state.use_bump_allocator) {
-		if (false) {
+		if (qcgc_allocator_state.use_bump_allocator) {
 			result = bump_allocate(size);
 		} else {
 			result = qcgc_fit_allocate(size);
@@ -91,19 +91,13 @@
 				result = bump_allocate(size);
 			}
 		}
+		qcgc_state.free_cells -= bytes_to_cells(size);
 	} else {
 		// Use huge block allocator
 		result = qcgc_large_allocate(size);
 	}
-
-	// XXX: Should we use cells instead of bytes?
-	qcgc_state.bytes_since_incmark += size;
-
-
-#if LOG_ALLOCATION
-	qcgc_event_logger_log(EVENT_ALLOCATE_DONE, sizeof(object_t *),
-			(uint8_t *) &result);
-#endif
+	qcgc_state.cells_since_incmark += bytes_to_cells(size);
+	qcgc_state.cells_since_collect += bytes_to_cells(size);
 	return result;
 }
 
diff --git a/rpython/translator/c/src/qcgc/src/allocator.c b/rpython/translator/c/src/qcgc/src/allocator.c
--- a/rpython/translator/c/src/qcgc/src/allocator.c
+++ b/rpython/translator/c/src/qcgc/src/allocator.c
@@ -2,9 +2,7 @@
 
 #include <assert.h>
 #include <stdbool.h>
-#include <stdlib.h>
-
-#include "hugeblocktable.h"
+#include "gc_state.h"
 
 QCGC_STATIC QCGC_INLINE void bump_allocator_assign(cell_t *ptr, size_t cells);
 
@@ -65,25 +63,6 @@
 	free(qcgc_allocator_state.free_arenas);
 }
 
-void qcgc_fit_allocator_add(cell_t *ptr, size_t cells) {
-#if CHECKED
-	assert(cells > 0);
-#endif
-	if (is_small(cells)) {
-		size_t index = small_index(cells);
-		qcgc_allocator_state.fit_state.small_free_list[index] =
-			qcgc_linear_free_list_add(
-					qcgc_allocator_state.fit_state.small_free_list[index],
-					ptr);
-	} else {
-		size_t index = large_index(cells);
-		qcgc_allocator_state.fit_state.large_free_list[index] =
-			qcgc_exp_free_list_add(
-					qcgc_allocator_state.fit_state.large_free_list[index],
-					(struct exp_free_list_item_s) {ptr, cells});
-	}
-}
-
 /*******************************************************************************
  * Bump Allocator                                                              *
  ******************************************************************************/
@@ -124,6 +103,8 @@
 	} else {
 		// Grab a new arena
 		arena_t *arena = qcgc_arena_create();
+		qcgc_state.free_cells += QCGC_ARENA_CELLS_COUNT -
+			QCGC_ARENA_FIRST_CELL_INDEX;
 		bump_allocator_assign(&(arena->cells[QCGC_ARENA_FIRST_CELL_INDEX]),
 				QCGC_ARENA_CELLS_COUNT - QCGC_ARENA_FIRST_CELL_INDEX);
 		qcgc_allocator_state.arenas =
@@ -163,6 +144,10 @@
 	qcgc_allocator_state.bump_state.remaining_cells = cells;
 }
 
+/*******************************************************************************
+ * Fit Allocator                                                               *
+ ******************************************************************************/
+
 object_t *qcgc_fit_allocate(size_t bytes) {
 #if CHECKED
 	//free_list_consistency_check();
@@ -192,23 +177,6 @@
 	return result;
 }
 
-/**
- * Constraints:
- * - Zero initialized
- * - Aligned to arena size
- * - Multiple of arena size
- * - No header, metadata stored in hash-map
- */
-object_t *qcgc_large_allocate(size_t bytes) {
-	object_t *result = aligned_alloc(QCGC_ARENA_SIZE, bytes);
-#if QCGC_INIT_ZERO
-	memset(result, 0, bytes);
-#endif
-	qcgc_hbtable_insert(result);
-	result->flags = QCGC_GRAY_FLAG;
-	return result;
-}
-
 void qcgc_fit_allocator_empty_lists(void) {
 	for (size_t i = 0; i < QCGC_SMALL_FREE_LISTS; i++) {
 		qcgc_allocator_state.fit_state.small_free_list[i]->count = 0;
@@ -219,6 +187,25 @@
 	}
 }
 
+void qcgc_fit_allocator_add(cell_t *ptr, size_t cells) {
+#if CHECKED
+	assert(cells > 0);
+#endif
+	if (is_small(cells)) {
+		size_t index = small_index(cells);
+		qcgc_allocator_state.fit_state.small_free_list[index] =
+			qcgc_linear_free_list_add(
+					qcgc_allocator_state.fit_state.small_free_list[index],
+					ptr);
+	} else {
+		size_t index = large_index(cells);
+		qcgc_allocator_state.fit_state.large_free_list[index] =
+			qcgc_exp_free_list_add(
+					qcgc_allocator_state.fit_state.large_free_list[index],
+					(struct exp_free_list_item_s) {ptr, cells});
+	}
+}
+
 QCGC_STATIC cell_t *fit_allocator_small_first_fit(size_t index, size_t cells) {
 #if CHECKED
 	assert(small_index_to_cells(index) >= cells);
@@ -321,18 +308,18 @@
 	return NULL;
 }
 
-QCGC_STATIC bool is_small(size_t cells) {
+QCGC_STATIC QCGC_INLINE bool is_small(size_t cells) {
 	return cells <= QCGC_SMALL_FREE_LISTS;
 }
 
-QCGC_STATIC size_t small_index(size_t cells) {
+QCGC_STATIC QCGC_INLINE size_t small_index(size_t cells) {
 #if CHECKED
 	assert(is_small(cells));
 #endif
 	return cells - 1;
 }
 
-QCGC_STATIC size_t large_index(size_t cells) {
+QCGC_STATIC QCGC_INLINE size_t large_index(size_t cells) {
 #if CHECKED
 	assert(!is_small(cells));
 #endif
@@ -341,10 +328,11 @@
 	cells = cells >> QCGC_LARGE_FREE_LIST_FIRST_EXP;
 
 	// calculates floor(log(cells))
-	return MIN((8 * sizeof(unsigned long)) - __builtin_clzl(cells) - 1, QCGC_LARGE_FREE_LISTS - 1);
+	return MIN((8 * sizeof(unsigned long)) - __builtin_clzl(cells) - 1,
+			QCGC_LARGE_FREE_LISTS - 1);
 }
 
-QCGC_STATIC size_t small_index_to_cells(size_t index) {
+QCGC_STATIC QCGC_INLINE size_t small_index_to_cells(size_t index) {
 #if CHECKED
 	assert(index < QCGC_SMALL_FREE_LISTS);
 #endif
diff --git a/rpython/translator/c/src/qcgc/src/allocator.h b/rpython/translator/c/src/qcgc/src/allocator.h
--- a/rpython/translator/c/src/qcgc/src/allocator.h
+++ b/rpython/translator/c/src/qcgc/src/allocator.h
@@ -3,9 +3,11 @@
 #include "../qcgc.h"
 
 #include <string.h>
+#include <stdlib.h>
 
 #include "arena.h"
 #include "bag.h"
+#include "hugeblocktable.h"
 
 /**
  * Free lists:
@@ -71,15 +73,6 @@
 object_t *qcgc_fit_allocate(size_t bytes);
 
 /**
- * Allocate new memory region using huge block allocator
- *
- * @param	bytes	Desired size of the memory region in bytes
- * @return	Pointer to memory large enough to hold size bytes, NULL in case of
- *			errors, already zero initialized if QCGC_INIT_ZERO is set
- */
-object_t *qcgc_large_allocate(size_t bytes);
-
-/**
  * Empty all free lists (used before sweep)
  */
 void qcgc_fit_allocator_empty_lists(void);
@@ -131,3 +124,20 @@
 	result->flags = QCGC_GRAY_FLAG;
 	return result;
 }
+
+/**
+ * Allocate new memory region using huge block allocator
+ *
+ * @param	bytes	Desired size of the memory region in bytes
+ * @return	Pointer to memory large enough to hold size bytes, NULL in case of
+ *			errors, already zero initialized if QCGC_INIT_ZERO is set
+ */
+QCGC_STATIC QCGC_INLINE object_t *qcgc_large_allocate(size_t bytes) {
+	object_t *result = aligned_alloc(QCGC_ARENA_SIZE, bytes);
+#if QCGC_INIT_ZERO
+	memset(result, 0, bytes);
+#endif
+	qcgc_hbtable_insert(result);
+	result->flags = QCGC_GRAY_FLAG;
+	return result;
+}
diff --git a/rpython/translator/c/src/qcgc/src/collector.c b/rpython/translator/c/src/qcgc/src/collector.c
--- a/rpython/translator/c/src/qcgc/src/collector.c
+++ b/rpython/translator/c/src/qcgc/src/collector.c
@@ -14,7 +14,7 @@
 
 void qcgc_mark(void) {
 	mark_setup(false);
-	
+
 	while (qcgc_state.gray_stack_size > 0) {
 		// General purpose gray stack (prebuilt objects and huge blocks)
 
@@ -94,7 +94,7 @@
 				(uint8_t *) &log_info);
 	}
 
-	qcgc_state.bytes_since_incmark = 0;
+	qcgc_state.cells_since_incmark = 0;
 
 	if (qcgc_state.phase == GC_PAUSE) {
 
@@ -186,10 +186,16 @@
 	assert(qcgc_state.phase == GC_COLLECT);
 #endif
 	{
-		unsigned long arena_count;
-		arena_count = qcgc_allocator_state.arenas->count;
-		qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(arena_count),
-				(uint8_t *) &arena_count);
+		struct log_info_s {
+			size_t arenas;
+			size_t free_cells;
+		};
+		struct log_info_s log_info = {
+			qcgc_allocator_state.arenas->count,
+			qcgc_state.free_cells,
+		};
+		qcgc_event_logger_log(EVENT_SWEEP_START, sizeof(struct log_info_s),
+				(uint8_t *) &log_info);
 	}
 
 	qcgc_hbtable_sweep();
@@ -218,22 +224,75 @@
 	// Determine whether fragmentation is too high
 	// Fragmenation = 1 - (largest block / total free space)
 	// Use bump allocator when fragmentation < 50%
+#if CHECKED
+	size_t free_cells = 0;
+	size_t largest_free_block = 0;
+		for (size_t i = 0; i < QCGC_SMALL_FREE_LISTS; i++) {
+			if (qcgc_allocator_state.fit_state.small_free_list[i]->count > 0) {
+				largest_free_block = i + 1;
+			}
+			free_cells += qcgc_allocator_state.fit_state.small_free_list[i]
+				->count * (i + 1);
+		}
+		for (size_t i = 0; i < QCGC_LARGE_FREE_LISTS; i++) {
+			for (size_t j = 0; j < qcgc_allocator_state.fit_state.
+					large_free_list[i]->count; j++) {
+				free_cells += qcgc_allocator_state.fit_state.large_free_list[i]
+					->items[j].size;
+				largest_free_block = MAX(largest_free_block,
+					qcgc_allocator_state.fit_state.large_free_list[i]
+					->items[j].size);
+			}
+		}
+	assert(free_cells == qcgc_state.free_cells);
+	assert(largest_free_block == qcgc_state.largest_free_block);
+	assert(free_cells <= qcgc_allocator_state.arenas->count * (QCGC_ARENA_CELLS_COUNT - QCGC_ARENA_FIRST_CELL_INDEX));
+	assert(qcgc_allocator_state.arenas->count *
+			(QCGC_ARENA_CELLS_COUNT - QCGC_ARENA_FIRST_CELL_INDEX) >=
+			free_cells);
+#endif
 	qcgc_allocator_state.use_bump_allocator = qcgc_state.free_cells <
 		2 * qcgc_state.largest_free_block;
 
 	update_weakrefs();
 
+	qcgc_state.free_cells += qcgc_allocator_state.bump_state.remaining_cells;
 	{
 		struct log_info_s {
+			size_t arenas;
 			size_t free_cells;
 			size_t largest_free_block;
 		};
 		struct log_info_s log_info = {
+			qcgc_allocator_state.arenas->count,
 			qcgc_state.free_cells,
 			qcgc_state.largest_free_block
 		};
 		qcgc_event_logger_log(EVENT_SWEEP_DONE, sizeof(struct log_info_s),
 				(uint8_t *) &log_info);
 	}
+#if LOG_DUMP_FREELIST_STATS
+	{
+		struct log_info_s {
+			size_t class;
+			size_t items;
+		};
+		struct log_info_s log_info;
+
+		for (size_t i = 0; i < QCGC_SMALL_FREE_LISTS; i++) {
+			log_info = (struct log_info_s){ i + 1,
+				qcgc_allocator_state.fit_state.small_free_list[i]->count};
+			qcgc_event_logger_log(EVENT_FREELIST_DUMP,
+					sizeof(struct log_info_s), (uint8_t *) &log_info);
+		}
+		for (size_t i = 0; i < QCGC_LARGE_FREE_LISTS; i++) {
+			log_info = (struct log_info_s){
+				1<<(QCGC_LARGE_FREE_LIST_FIRST_EXP + i),
+				qcgc_allocator_state.fit_state.large_free_list[i]->count};
+			qcgc_event_logger_log(EVENT_FREELIST_DUMP,
+					sizeof(struct log_info_s), (uint8_t *) &log_info);
+		}
+	}
+#endif
 }
 
diff --git a/rpython/translator/c/src/qcgc/src/event_logger.h b/rpython/translator/c/src/qcgc/src/event_logger.h
--- a/rpython/translator/c/src/qcgc/src/event_logger.h
+++ b/rpython/translator/c/src/qcgc/src/event_logger.h
@@ -15,13 +15,14 @@
 	EVENT_SWEEP_START,
 	EVENT_SWEEP_DONE,
 
-	EVENT_ALLOCATE_START,
-	EVENT_ALLOCATE_DONE,		// = 5
+	EVENT_ALLOCATE,
 
-	EVENT_NEW_ARENA,
+	EVENT_NEW_ARENA,			// = 5
 
 	EVENT_MARK_START,
 	EVENT_MARK_DONE,
+
+	EVENT_FREELIST_DUMP,
 };
 
 /**
diff --git a/rpython/translator/c/src/qcgc/src/gc_state.h b/rpython/translator/c/src/qcgc/src/gc_state.h
--- a/rpython/translator/c/src/qcgc/src/gc_state.h
+++ b/rpython/translator/c/src/qcgc/src/gc_state.h
@@ -33,7 +33,8 @@
 	size_t gray_stack_size;
 	gc_phase_t phase;
 
-	size_t bytes_since_incmark;
+	size_t cells_since_incmark;
+	size_t cells_since_collect;
 	size_t incmark_since_sweep;
 	size_t incmark_threshold;
 	size_t incmark_to_sweep;


More information about the pypy-commit mailing list