Ver código fonte

allow runtime customization of marking threads

Nicolas Cannasse 2 anos atrás
pai
commit
6e547b3320
1 arquivos alterados com 24 adições e 13 exclusões
  1. 24 13
      src/gc.c

+ 24 - 13
src/gc.c

@@ -85,9 +85,9 @@ static int_val gc_hash( void *ptr ) {
 #define GC_PRECISE
 
 #ifndef HL_THREADS
-#	define GC_MARK_THREADS 1
+#	define GC_MAX_MARK_THREADS 1
 #else
-#	define GC_MARK_THREADS 4
+#	define GC_MAX_MARK_THREADS 4
 #endif
 
 #define out_of_memory(reason)		hl_fatal("Out of Memory (" reason ")")
@@ -575,7 +575,8 @@ static float gc_mark_threshold = 0.2f;
 static int mark_size = 0;
 static unsigned char *mark_data = NULL;
 static gc_mstack global_mark_stack = {0};
-static gc_mthread mark_threads[GC_MARK_THREADS] = {0};
+static int gc_mark_threads = GC_MAX_MARK_THREADS;
+static gc_mthread mark_threads[GC_MAX_MARK_THREADS] = {0};
 static unsigned char mark_threads_active = 0;
 static hl_semaphore *mark_threads_done;
 
@@ -616,7 +617,7 @@ HL_PRIM void **hl_gc_mark_grow( gc_mstack *stack ) {
 }
 
 static bool atomic_bit_unset( unsigned char *addr, unsigned char bitmask ) {
-	if( GC_MARK_THREADS <= 1 ) {
+	if( GC_MAX_MARK_THREADS <= 1 ) {
 		unsigned char v = *addr;
 		bool b = (v & bitmask) != 0;
 		if( b ) *addr = v & ~bitmask;
@@ -633,7 +634,7 @@ static bool atomic_bit_unset( unsigned char *addr, unsigned char bitmask ) {
 }
 
 static bool atomic_bit_set( unsigned char *addr, unsigned char bitmask ) {
-	if( GC_MARK_THREADS <= 1 ) {
+	if( GC_MAX_MARK_THREADS <= 1 ) {
 		unsigned char v = *addr;
 		bool b = (v & bitmask) == 0;
 		if( b ) *addr = v | bitmask;
@@ -652,11 +653,15 @@ static bool atomic_bit_set( unsigned char *addr, unsigned char bitmask ) {
 static void gc_dispatch_mark( gc_mstack *st ) {
 	int nthreads = 0;
 	int i;
-	for(i=0;i<GC_MARK_THREADS;i++)
+	if( mark_threads_active == (1<<gc_mark_threads) - 1 )
+		return;
+	for(i=0;i<gc_mark_threads;i++)
 		if( (mark_threads_active&(1<<i)) == 0 )
 			nthreads++;
+	if( nthreads == 0 )
+		return;
 	int count = GC_STACK_COUNT(st) / (nthreads + 1);
-	for(i=0;i<GC_MARK_THREADS;i++) {
+	for(i=0;i<gc_mark_threads;i++) {
 		gc_mthread *t = &mark_threads[i];
 		if( !atomic_bit_set(&mark_threads_active,1<<i) )
 			continue;
@@ -693,7 +698,7 @@ static int gc_flush_mark( gc_mstack *stack ) {
 			__current_stack++;
 			break;
 		}
-		if( (count++ & (1 << REGULAR_BITS)) != regular_mask && GC_MARK_THREADS > 1 ) {
+		if( (count++ & (1 << REGULAR_BITS)) != regular_mask && GC_MAX_MARK_THREADS > 1 && gc_mark_threads > 1 ) {
 			regular_mask = regular_mask ? 0 : 1 << REGULAR_BITS;
 			GC_STACK_END();
 			gc_dispatch_mark(stack);
@@ -810,7 +815,7 @@ static void gc_mark() {
 	}
 
 	gc_mstack *st = &global_mark_stack;
-	if( GC_MARK_THREADS <= 1 )
+	if( gc_mark_threads <= 1 )
 		gc_flush_mark(st);
 	else {
 		gc_dispatch_mark(st);
@@ -818,7 +823,7 @@ static void gc_mark() {
 		// wait threads to finish
 		while( mark_threads_active )
 			hl_semaphore_acquire(mark_threads_done);
-		for(i=0;i<GC_MARK_THREADS;i++) {
+		for(i=0;i<gc_mark_threads;i++) {
 			gc_mthread *t = &mark_threads[i];
 			if( GC_STACK_COUNT(&t->stack) != 0 )
 				hl_fatal("assert");
@@ -915,8 +920,14 @@ static void hl_gc_init() {
 	hl_add_root(&gc_threads.exclusive_lock);
 	hl_add_root(&mark_threads_done);
 	mark_threads_done = hl_semaphore_alloc(0);
-	if( GC_MARK_THREADS > 1 ) {
-		for(int i=0;i<GC_MARK_THREADS;i++) {
+	char *nthreads = getenv("HL_GC_THREADS");
+	if( nthreads ) {
+		gc_mark_threads = atoi(nthreads);
+		if( gc_mark_threads < 1 ) gc_mark_threads = 1;
+		if( gc_mark_threads > GC_MAX_MARK_THREADS ) gc_mark_threads = GC_MAX_MARK_THREADS;
+	}
+	if( gc_mark_threads > 1 ) {
+		for(int i=0;i<gc_mark_threads;i++) {
 			gc_mthread *t = &mark_threads[i];
 			hl_add_root(&t->ready);
 			t->ready = hl_semaphore_alloc(0);
@@ -1328,7 +1339,7 @@ HL_API void hl_gc_dump_memory( const char *filename ) {
 
 	fdump_i(private_data);
 	int msize = global_mark_stack.size;
-	for(i=0;i<GC_MARK_THREADS;i++)
+	for(i=0;i<GC_MAX_MARK_THREADS;i++)
 		msize += mark_threads[i].stack.size;
 	fdump_i(msize); // keep separate
 	fdump_i(page_count);