Bläddra i källkod

Implement profiler for linux. (#490)

Zeta 3 år sedan
förälder
incheckning
faae470721
1 ändrade filer med 56 tillägg och 1 borttagningar
  1. 56 1
      src/profile.c

+ 56 - 1
src/profile.c

@@ -22,6 +22,12 @@
 #include <hl.h>
 #include <hl.h>
 #include <hlmodule.h>
 #include <hlmodule.h>
 
 
+#ifdef HL_LINUX
+#include <signal.h>
+#include <semaphore.h>
+#include <unistd.h>
+#endif
+
 #define MAX_STACK_SIZE (8 << 20)
 #define MAX_STACK_SIZE (8 << 20)
 #define MAX_STACK_COUNT 2048
 #define MAX_STACK_COUNT 2048
 
 
@@ -73,6 +79,25 @@ static struct {
 	profile_data *first_record;
 	profile_data *first_record;
 } data = {0};
 } data = {0};
 
 
+#ifdef HL_LINUX
+static struct
+{
+	sem_t msg2;
+	sem_t msg3;
+	sem_t msg4;
+	ucontext_t context;
+} shared_context;
+
+static void sigprof_handler(int sig, siginfo_t *info, void *ucontext)
+{
+	ucontext_t *ctx = ucontext;
+	shared_context.context = *ctx;
+	sem_post(&shared_context.msg2);
+	sem_wait(&shared_context.msg3);
+	sem_post(&shared_context.msg4);
+}
+#endif
+
 static void *get_thread_stackptr( thread_handle *t, void **eip ) {
 static void *get_thread_stackptr( thread_handle *t, void **eip ) {
 #ifdef HL_WIN_DESKTOP
 #ifdef HL_WIN_DESKTOP
 	CONTEXT c;
 	CONTEXT c;
@@ -85,6 +110,14 @@ static void *get_thread_stackptr( thread_handle *t, void **eip ) {
 	*eip = (void*)c.Eip;
 	*eip = (void*)c.Eip;
 	return (void*)c.Esp;
 	return (void*)c.Esp;
 #	endif
 #	endif
+#elif defined(HL_LINUX)
+#	ifdef HL_64
+	*eip = (void*)shared_context.context.uc_mcontext.gregs[REG_RIP];
+	return (void*)shared_context.context.uc_mcontext.gregs[REG_RSP];
+#	else
+	*eip = (void*)shared_context.context.uc_mcontext.gregs[REG_EIP];
+	return (void*)shared_context.context.uc_mcontext.gregs[REG_ESP];
+#	endif
 #else
 #else
 	return NULL;
 	return NULL;
 #endif
 #endif
@@ -110,6 +143,14 @@ static bool pause_thread( thread_handle *t, bool b ) {
 		ResumeThread(t->h);
 		ResumeThread(t->h);
 		return true;
 		return true;
 	}
 	}
+#elif defined(HL_LINUX)
+	if( b ) {
+		tgkill(getpid(), t->tid, SIGPROF);
+		return sem_wait(&shared_context.msg2) == 0;
+	} else {
+		sem_post(&shared_context.msg3);
+		return sem_wait(&shared_context.msg4) == 0;
+	}
 #else
 #else
 	return false;
 	return false;
 #endif
 #endif
@@ -144,6 +185,10 @@ static void read_thread_data( thread_handle *t ) {
 		return;
 		return;
 	}
 	}
 
 
+#ifdef HL_LINUX
+    int count = hl_module_capture_stack_range(t->inf->stack_top, stack, data.stackOut, MAX_STACK_COUNT);
+    pause_thread(t, false);
+#else
 	int size = (int)((unsigned char*)t->inf->stack_top - (unsigned char*)stack);
 	int size = (int)((unsigned char*)t->inf->stack_top - (unsigned char*)stack);
 	if( size > MAX_STACK_SIZE-32 ) size = MAX_STACK_SIZE-32;
 	if( size > MAX_STACK_SIZE-32 ) size = MAX_STACK_SIZE-32;
 	memcpy(data.tmpMemory + 2,stack,size);
 	memcpy(data.tmpMemory + 2,stack,size);
@@ -153,6 +198,7 @@ static void read_thread_data( thread_handle *t ) {
 	size += sizeof(void*) * 2;
 	size += sizeof(void*) * 2;
 
 
 	int count = hl_module_capture_stack_range((char*)data.tmpMemory+size, (void**)data.tmpMemory, data.stackOut, MAX_STACK_COUNT);
 	int count = hl_module_capture_stack_range((char*)data.tmpMemory+size, (void**)data.tmpMemory, data.stackOut, MAX_STACK_COUNT);
+#endif
 	int eventId = count | 0x80000000;
 	int eventId = count | 0x80000000;
 	double time = hl_sys_time();
 	double time = hl_sys_time();
 	record_data(&time,sizeof(double));
 	record_data(&time,sizeof(double));
@@ -211,7 +257,7 @@ static void hl_profile_loop( void *_ ) {
 static void profile_event( int code, vbyte *data, int dataLen );
 static void profile_event( int code, vbyte *data, int dataLen );
 
 
 void hl_profile_setup( int sample_count ) {
 void hl_profile_setup( int sample_count ) {
-#	if defined(HL_THREADS) && defined(HL_WIN_DESKTOP)
+#	if defined(HL_THREADS) && (defined(HL_WIN_DESKTOP) || defined(HL_LINUX))
 	hl_setup_profiler(profile_event,hl_profile_end);
 	hl_setup_profiler(profile_event,hl_profile_end);
 	if( data.sample_count ) return;
 	if( data.sample_count ) return;
 	if( sample_count < 0 ) {
 	if( sample_count < 0 ) {
@@ -220,6 +266,15 @@ void hl_profile_setup( int sample_count ) {
 		return;
 		return;
 	}
 	}
 	data.sample_count = sample_count;
 	data.sample_count = sample_count;
+#	ifdef HL_LINUX
+	sem_init(&shared_context.msg2, 0, 0);
+	sem_init(&shared_context.msg3, 0, 0);
+	sem_init(&shared_context.msg4, 0, 0);
+	struct sigaction action = {0};
+	action.sa_sigaction = sigprof_handler;
+	action.sa_flags = SA_SIGINFO;
+	sigaction(SIGPROF, &action, NULL);
+#	endif
 	hl_thread_start(hl_profile_loop,NULL,false);
 	hl_thread_start(hl_profile_loop,NULL,false);
 #	endif
 #	endif
 }
 }