Przeglądaj źródła

fixed static thread var, added spinlock (windows only) and threads alloc benchmark

Nicolas Cannasse 7 lat temu
rodzic
commit
96b269fba2
4 zmienionych plików z 133 dodań i 10 usunięć
  1. 51 0
      other/tests/Threads.hx
  2. 13 10
      src/alloc.c
  3. 10 0
      src/hl.h
  4. 59 0
      src/std/thread.c

+ 51 - 0
other/tests/Threads.hx

@@ -0,0 +1,51 @@
+class Threads {
+
+	static var WAIT = [];
+	
+	@:hlNative("std","thread_create") static function thread_create( f : Void -> Void ) : hl.Abstract<"hl_thread"> {
+		return null;
+	}
+
+	static function run(i,k) {
+		for( i in 0...Math.ceil(10000000/k) )
+			new hl.Bytes(1);
+		if( i>=0 ) WAIT[i] = false; 
+	}
+	
+    public static function main() {
+
+		hl.Gc.enable(false); // disable major gc
+
+		var flags = hl.Gc.flags;
+		flags.set(NoThreads);
+		hl.Gc.flags = flags;
+		
+		var t0 = Sys.time();
+		run(-1,1);
+		trace("Threads disable "+(Sys.time() - t0));
+		
+		flags.unset(NoThreads);
+		hl.Gc.flags = flags;
+	
+		var t0 = Sys.time();
+		run(-1,1);
+		trace("Single thread "+(Sys.time() - t0));
+		
+		for( COUNT in [2,4,10] ) {
+			for( i in 0...COUNT ) 
+				WAIT[i] = true;
+			t0 = Sys.time();
+			for( i in 0...COUNT ) 			
+				thread_create(run.bind(i,COUNT));
+			var i = 0;
+			while( i < COUNT ) {
+				if( WAIT[i] ) {
+					i = 0;
+					Sys.sleep(0);
+				} else i++;
+			}
+			trace(COUNT+" threads "+(Sys.time() - t0));
+		}
+    }
+	
+}

+ 13 - 10
src/alloc.c

@@ -137,6 +137,7 @@ static const int GC_SIZES[GC_PARTITIONS] = {4,8,12,16,20,	8,64,1<<14,1<<22};
 #define GC_PROFILE		1
 #define GC_DUMP_MEM		2
 #define GC_TRACK		4
+#define GC_NO_THREADS	8
 
 static int gc_flags = 0;
 static gc_pheader *gc_pages[GC_ALL_PAGES] = {NULL};
@@ -150,10 +151,10 @@ static struct {
 	int count;
 	bool stopping_world;
 	hl_thread_info **threads;
-	hl_mutex *global_lock;
+	hl_spinlock *global_lock;
 } gc_threads;
 
-HL_THREAD_VAR static hl_thread_info *current_thread;
+HL_THREAD_STATIC_VAR hl_thread_info *current_thread;
 
 static struct {
 	int64 total_requested;
@@ -203,15 +204,17 @@ static void gc_save_context(hl_thread_info *t ) {
 #else
 static void gc_global_lock( bool lock ) {
 	hl_thread_info *t = current_thread;
+	bool mt = (gc_flags & GC_NO_THREADS) == 0;
 	if( lock ) {
 		if( t->gc_blocking )
 			hl_fatal("Can't lock GC in hl_blocking section");
-		gc_save_context(t);
+		if( mt ) gc_save_context(t);
 		t->gc_blocking++;
-		hl_mutex_acquire(gc_threads.global_lock);
+		while ( mt && !hl_spinlock_acquire(gc_threads.global_lock, t, 100000))
+			hl_thread_yield();
 	} else {
 		t->gc_blocking--;
-		hl_mutex_release(gc_threads.global_lock);
+		if( mt ) hl_spinlock_release(gc_threads.global_lock);
 	}
 }
 #endif
@@ -284,6 +287,8 @@ HL_API void hl_unregister_thread() {
 	hl_thread_info *t = hl_get_thread();
 	if( !t )
 		hl_fatal("Thread not registered");
+	hl_remove_root(&t->exc_value);
+	hl_remove_root(&t->exc_handler);
 	gc_global_lock(true);
 	for(i=0;i<gc_threads.count;i++)
 		if( gc_threads.threads[i] == t ) {
@@ -291,12 +296,10 @@ HL_API void hl_unregister_thread() {
 			gc_threads.count--;
 			break;
 		}
-	hl_remove_root(&t->exc_value);
-	hl_remove_root(&t->exc_handler);
 	free(t);
 	current_thread = NULL;
 	// don't use gc_global_lock(false)
-	hl_mutex_release(gc_threads.global_lock);
+	hl_spinlock_release(gc_threads.global_lock);
 }
 
 HL_API void *hl_gc_threads_info() {
@@ -1028,7 +1031,7 @@ static void hl_gc_init() {
 		gc_flags |= GC_DUMP_MEM;
 #	endif
 	memset(&gc_threads,0,sizeof(gc_threads));
-	gc_threads.global_lock = hl_mutex_alloc();
+	gc_threads.global_lock = hl_spinlock_alloc();
 }
 
 // ---- UTILITIES ----------------------
@@ -1374,4 +1377,4 @@ DEFINE_PRIM(_VOID, gc_dump_memory, _BYTES);
 DEFINE_PRIM(_I32, gc_get_flags, _NO_ARG);
 DEFINE_PRIM(_VOID, gc_set_flags, _I32);
 DEFINE_PRIM(_DYN, debug_call, _I32 _DYN);
-
+DEFINE_PRIM(_VOID, blocking, _BOOL);

+ 10 - 0
src/hl.h

@@ -131,11 +131,14 @@
 #	define HL_THREADS
 #	ifdef HL_VCC
 #		define HL_THREAD_VAR __declspec( thread )
+#		define HL_THREAD_STATIC_VAR HL_THREAD_VAR static
 #	else
 #		define HL_THREAD_VAR __thread
+#		define HL_THREAD_STATIC_VAR static HL_THREAD_VAR
 #	endif
 #else
 #	define HL_THREAD_VAR
+#	define HL_THREAD_STATIC_VAR static
 #endif
 
 #include <stddef.h>
@@ -628,12 +631,15 @@ HL_API vdynamic *hl_dyn_call_safe( vclosure *c, vdynamic **args, int nargs, bool
 struct _hl_thread;
 struct _hl_mutex;
 struct _hl_tls;
+struct _hl_spinlock;
 typedef struct _hl_thread hl_thread;
 typedef struct _hl_mutex hl_mutex;
 typedef struct _hl_tls hl_tls;
+typedef struct _hl_spinlock hl_spinlock;
 
 HL_API hl_thread *hl_thread_start( void *callback, void *param, bool withGC );
 HL_API hl_thread *hl_thread_current( void );
+HL_API void hl_thread_yield(void);
 HL_API void hl_register_thread( void *stack_top );
 HL_API void hl_unregister_thread( void );
 
@@ -648,6 +654,10 @@ HL_API void hl_tls_set( hl_tls *l, void *value );
 HL_API void *hl_tls_get( hl_tls *l );
 HL_API void hl_tls_free( hl_tls *l );
 
+HL_API hl_spinlock *hl_spinlock_alloc(void);
+HL_API bool hl_spinlock_acquire( hl_spinlock *s, void *value, int count );
+HL_API void hl_spinlock_release( hl_spinlock *s );
+
 // ----------------------- ALLOC --------------------------------------------------
 
 #define MEM_HAS_PTR(kind)	(!((kind)&2))

+ 59 - 0
src/std/thread.c

@@ -31,6 +31,9 @@ struct _hl_tls {
 	void *value;
 };
 
+struct _hl_spinlock {
+	void *value;
+};
 
 #elif defined(HL_WIN)
 
@@ -38,6 +41,10 @@ struct _hl_mutex {
 	CRITICAL_SECTION cs;
 };
 
+struct _hl_spinlock {
+	void *value;
+};
+
 #else
 
 #	include <pthread.h>
@@ -51,6 +58,12 @@ struct _hl_mutex {
 struct _hl_tls {
 	pthread_key_t key;
 };
+
+struct _hl_spinlock {
+	pthread_mutex_t lock;
+	void *value;
+};
+
 #endif
 
 // ----------------- ALLOC
@@ -161,6 +174,41 @@ HL_PRIM void *hl_tls_get( hl_tls *l ) {
 #	endif
 }
 
+// ----------------- SPINLOCK
+
+HL_PRIM hl_spinlock *hl_spinlock_alloc() {
+#	if !defined(HL_THREADS)
+	return NULL;
+#	elif defined(HL_WIN)
+	hl_spinlock *s = _aligned_malloc(sizeof(hl_spinlock),32);
+	s->value = NULL;
+	return s;
+#	else
+#	endif
+}
+
+HL_PRIM bool hl_spinlock_acquire( hl_spinlock *s, void *value, int count ) {
+#	if !defined(HL_THREADS)
+	return true;
+#	elif defined(HL_WIN)
+	while (s->value != value) {
+		if (count-- == 0) return false;
+		InterlockedCompareExchangePointer(&s->value, value, NULL);
+	}
+	return true;
+#	else
+#	endif
+}
+
+HL_PRIM void hl_spinlock_release( hl_spinlock *s ) {
+#	if !defined(HL_THREADS)
+	return true;
+#	elif defined(HL_WIN)
+	s->value = NULL;
+#	else
+#	endif
+}
+
 // ----------------- THREAD
 
 HL_PRIM hl_thread *hl_thread_current() {
@@ -173,6 +221,17 @@ HL_PRIM hl_thread *hl_thread_current() {
 #endif
 }
 
+HL_PRIM void hl_thread_yield() {
+#if !defined(Hl_THREADS)
+	// nothing
+#elif defined(HL_WIN)
+	Sleep(0);
+#else
+	pthread_yield();
+#endif
+}
+
+
 HL_PRIM int hl_thread_id() {
 #if !defined(HL_THREADS)
 	return 0;