[Tarantool-patches] [PATCH luajit 2/7] core: separate the profiling timer from lj_profile
Maxim Kokryashkin
max.kokryashkin at gmail.com
Wed Sep 8 20:50:45 MSK 2021
From: Mikhail Shishatskiy <m.shishatskiy at tarantool.org>
This patch makes timer machinery in lj_profile self-reliant by
introducing lj_profile_timer structure and start/stop interface
for it. This makes the timer useful for other sampling profiling
features.
Part of tarantool/tarantool#781
---
src/CMakeLists.txt | 1 +
src/Makefile.dep.original | 5 +-
src/lj_profile.c | 178 +++-----------------------------------
src/lj_profile_timer.c | 126 +++++++++++++++++++++++++++
src/lj_profile_timer.h | 83 ++++++++++++++++++
5 files changed, 227 insertions(+), 166 deletions(-)
create mode 100644 src/lj_profile_timer.c
create mode 100644 src/lj_profile_timer.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 809aac68..50c23cae 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -68,6 +68,7 @@ make_source_list(SOURCES_UTILS
make_source_list(SOURCES_PROFILER
SOURCES
lj_memprof.c
+ lj_profile_timer.c
lj_profile.c
)
diff --git a/src/Makefile.dep.original b/src/Makefile.dep.original
index f3672413..da5abf0d 100644
--- a/src/Makefile.dep.original
+++ b/src/Makefile.dep.original
@@ -177,7 +177,10 @@ lj_parse.o: lj_parse.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_vm.h lj_vmevent.h
lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_buf.h lj_gc.h lj_str.h lj_frame.h lj_bc.h lj_debug.h lj_dispatch.h \
- lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
+ lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h \
+ lj_profile_timer.h luajit.h
+lj_profile_timer.o: lj_profile_timer.c lj_profile_timer.h lj_arch.h lua.h \
+ luaconf.h
lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \
lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
diff --git a/src/lj_profile.c b/src/lj_profile.c
index 7b09a63a..e7e1a303 100644
--- a/src/lj_profile.c
+++ b/src/lj_profile.c
@@ -19,66 +19,19 @@
#include "lj_trace.h"
#endif
#include "lj_profile.h"
+#include "lj_profile_timer.h"
#include "luajit.h"
-#if LJ_PROFILE_SIGPROF
-
-#include <sys/time.h>
-#include <signal.h>
-#define profile_lock(ps) UNUSED(ps)
-#define profile_unlock(ps) UNUSED(ps)
-
-#elif LJ_PROFILE_PTHREAD
-
-#include <pthread.h>
-#include <time.h>
-#if LJ_TARGET_PS3
-#include <sys/timer.h>
-#endif
-#define profile_lock(ps) pthread_mutex_lock(&ps->lock)
-#define profile_unlock(ps) pthread_mutex_unlock(&ps->lock)
-
-#elif LJ_PROFILE_WTHREAD
-
-#define WIN32_LEAN_AND_MEAN
-#if LJ_TARGET_XBOX360
-#include <xtl.h>
-#include <xbox.h>
-#else
-#include <windows.h>
-#endif
-typedef unsigned int (WINAPI *WMM_TPFUNC)(unsigned int);
-#define profile_lock(ps) EnterCriticalSection(&ps->lock)
-#define profile_unlock(ps) LeaveCriticalSection(&ps->lock)
-
-#endif
-
/* Profiler state. */
typedef struct ProfileState {
global_State *g; /* VM state that started the profiler. */
luaJIT_profile_callback cb; /* Profiler callback. */
void *data; /* Profiler callback data. */
SBuf sb; /* String buffer for stack dumps. */
- int interval; /* Sample interval in milliseconds. */
int samples; /* Number of samples for next callback. */
int vmstate; /* VM state when profile timer triggered. */
-#if LJ_PROFILE_SIGPROF
- struct sigaction oldsa; /* Previous SIGPROF state. */
-#elif LJ_PROFILE_PTHREAD
- pthread_mutex_t lock; /* g->hookmask update lock. */
- pthread_t thread; /* Timer thread. */
- int abort; /* Abort timer thread. */
-#elif LJ_PROFILE_WTHREAD
-#if LJ_TARGET_WINDOWS
- HINSTANCE wmm; /* WinMM library handle. */
- WMM_TPFUNC wmm_tbp; /* WinMM timeBeginPeriod function. */
- WMM_TPFUNC wmm_tep; /* WinMM timeEndPeriod function. */
-#endif
- CRITICAL_SECTION lock; /* g->hookmask update lock. */
- HANDLE thread; /* Timer thread. */
- int abort; /* Abort timer thread. */
-#endif
+ lj_profile_timer timer; /* Profiling timer */
} ProfileState;
/* Sadly, we have to use a static profiler state.
@@ -145,6 +98,7 @@ void LJ_FASTCALL lj_profile_interpreter(lua_State *L)
profile_unlock(ps);
}
+
/* Trigger profile hook. Asynchronous call from OS-specific profile timer. */
static void profile_trigger(ProfileState *ps)
{
@@ -168,129 +122,21 @@ static void profile_trigger(ProfileState *ps)
profile_unlock(ps);
}
-/* -- OS-specific profile timer handling ---------------------------------- */
-
#if LJ_PROFILE_SIGPROF
-/* SIGPROF handler. */
-static void profile_signal(int sig)
+static void profile_handler(int sig, siginfo_t *info, void* ctx)
{
UNUSED(sig);
+ UNUSED(info);
+ UNUSED(ctx);
profile_trigger(&profile_state);
}
-/* Start profiling timer. */
-static void profile_timer_start(ProfileState *ps)
-{
- int interval = ps->interval;
- struct itimerval tm;
- struct sigaction sa;
- tm.it_value.tv_sec = tm.it_interval.tv_sec = interval / 1000;
- tm.it_value.tv_usec = tm.it_interval.tv_usec = (interval % 1000) * 1000;
- setitimer(ITIMER_PROF, &tm, NULL);
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = profile_signal;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGPROF, &sa, &ps->oldsa);
-}
-
-/* Stop profiling timer. */
-static void profile_timer_stop(ProfileState *ps)
-{
- struct itimerval tm;
- tm.it_value.tv_sec = tm.it_interval.tv_sec = 0;
- tm.it_value.tv_usec = tm.it_interval.tv_usec = 0;
- setitimer(ITIMER_PROF, &tm, NULL);
- sigaction(SIGPROF, &ps->oldsa, NULL);
-}
-
-#elif LJ_PROFILE_PTHREAD
-
-/* POSIX timer thread. */
-static void *profile_thread(ProfileState *ps)
-{
- int interval = ps->interval;
-#if !LJ_TARGET_PS3
- struct timespec ts;
- ts.tv_sec = interval / 1000;
- ts.tv_nsec = (interval % 1000) * 1000000;
-#endif
- while (1) {
-#if LJ_TARGET_PS3
- sys_timer_usleep(interval * 1000);
#else
- nanosleep(&ts, NULL);
-#endif
- if (ps->abort) break;
- profile_trigger(ps);
- }
- return NULL;
-}
-
-/* Start profiling timer thread. */
-static void profile_timer_start(ProfileState *ps)
-{
- pthread_mutex_init(&ps->lock, 0);
- ps->abort = 0;
- pthread_create(&ps->thread, NULL, (void *(*)(void *))profile_thread, ps);
-}
-/* Stop profiling timer thread. */
-static void profile_timer_stop(ProfileState *ps)
+static void profile_handler()
{
- ps->abort = 1;
- pthread_join(ps->thread, NULL);
- pthread_mutex_destroy(&ps->lock);
-}
-
-#elif LJ_PROFILE_WTHREAD
-
-/* Windows timer thread. */
-static DWORD WINAPI profile_thread(void *psx)
-{
- ProfileState *ps = (ProfileState *)psx;
- int interval = ps->interval;
-#if LJ_TARGET_WINDOWS
- ps->wmm_tbp(interval);
-#endif
- while (1) {
- Sleep(interval);
- if (ps->abort) break;
- profile_trigger(ps);
- }
-#if LJ_TARGET_WINDOWS
- ps->wmm_tep(interval);
-#endif
- return 0;
-}
-
-/* Start profiling timer thread. */
-static void profile_timer_start(ProfileState *ps)
-{
-#if LJ_TARGET_WINDOWS
- if (!ps->wmm) { /* Load WinMM library on-demand. */
- ps->wmm = LoadLibraryExA("winmm.dll", NULL, 0);
- if (ps->wmm) {
- ps->wmm_tbp = (WMM_TPFUNC)GetProcAddress(ps->wmm, "timeBeginPeriod");
- ps->wmm_tep = (WMM_TPFUNC)GetProcAddress(ps->wmm, "timeEndPeriod");
- if (!ps->wmm_tbp || !ps->wmm_tep) {
- ps->wmm = NULL;
- return;
- }
- }
- }
-#endif
- InitializeCriticalSection(&ps->lock);
- ps->abort = 0;
- ps->thread = CreateThread(NULL, 0, profile_thread, ps, 0, NULL);
-}
-
-/* Stop profiling timer thread. */
-static void profile_timer_stop(ProfileState *ps)
-{
- ps->abort = 1;
- WaitForSingleObject(ps->thread, INFINITE);
- DeleteCriticalSection(&ps->lock);
+ profile_trigger(&profile_state);
}
#endif
@@ -327,12 +173,14 @@ LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
if (ps->g) return; /* Profiler in use by another VM. */
}
ps->g = G(L);
- ps->interval = interval;
ps->cb = cb;
ps->data = data;
ps->samples = 0;
lj_buf_init(L, &ps->sb);
- profile_timer_start(ps);
+
+ ps->timer.opt.interval_msec = interval;
+ ps->timer.opt.handler = profile_handler;
+ lj_profile_timer_start(&ps->timer);
}
/* Stop profiling. */
@@ -341,7 +189,7 @@ LUA_API void luaJIT_profile_stop(lua_State *L)
ProfileState *ps = &profile_state;
global_State *g = ps->g;
if (G(L) == g) { /* Only stop profiler if started by this VM. */
- profile_timer_stop(ps);
+ lj_profile_timer_stop(&ps->timer);
g->hookmask &= ~HOOK_PROFILE;
lj_dispatch_update(g);
#if LJ_HASJIT
diff --git a/src/lj_profile_timer.c b/src/lj_profile_timer.c
new file mode 100644
index 00000000..ce420a85
--- /dev/null
+++ b/src/lj_profile_timer.c
@@ -0,0 +1,126 @@
+/*
+** Simple profiling timer extracted from inbuilt luajit profiler
+*/
+
+#define lj_profile_timer_c
+#define LUA_CORE
+
+#include "lj_profile_timer.h"
+
+#if LJ_HASPROFILE
+
+#if LJ_PROFILE_SIGPROF
+
+/* Start profiling timer. */
+void lj_profile_timer_start(lj_profile_timer *timer) {
+ int interval = timer->opt.interval_msec;
+ struct itimerval tm;
+ struct sigaction sa;
+ tm.it_value.tv_sec = tm.it_interval.tv_sec = interval / 1000;
+ tm.it_value.tv_usec = tm.it_interval.tv_usec = (interval % 1000) * 1000;
+ setitimer(ITIMER_PROF, &tm, NULL);
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ sa.sa_sigaction = timer->opt.handler;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGPROF, &sa, &timer->oldsa);
+}
+
+/* Stop profiling timer. */
+void lj_profile_timer_stop(lj_profile_timer *timer) {
+ struct itimerval tm;
+ tm.it_value.tv_sec = tm.it_interval.tv_sec = 0;
+ tm.it_value.tv_usec = tm.it_interval.tv_usec = 0;
+ setitimer(ITIMER_PROF, &tm, NULL);
+ sigaction(SIGPROF, &timer->oldsa, NULL);
+}
+
+#elif LJ_PROFILE_PTHREAD
+
+/* POSIX timer thread. */
+static void *profile_thread(lj_timer *timer) {
+ int interval = timer->opt.interval_msec;
+#if !LJ_TARGET_PS3
+ struct timespec ts;
+ ts.tv_sec = interval / 1000;
+ ts.tv_nsec = (interval % 1000) * 1000000;
+#endif
+ while (1) {
+#if LJ_TARGET_PS3
+ sys_timer_usleep(interval * 1000);
+#else
+ nanosleep(&ts, NULL);
+#endif
+ if (timer->abort)
+ break;
+ timer->opt.handler();
+ }
+ return NULL;
+}
+
+/* Start profiling timer thread. */
+void lj_profile_timer_start(lj_profile_timer *timer) {
+ pthread_mutex_init(&timer->lock, 0);
+ timer->abort = 0;
+ pthread_create(&timer->thread, NULL, (void *(*)(void *))profile_thread,
+ timer);
+}
+
+/* Stop profiling timer thread. */
+void lj_profile_timer_stop(lj_profile_timer *timer) {
+ timer->abort = 1;
+ pthread_join(timer->thread, NULL);
+ pthread_mutex_destroy(&timer->lock);
+}
+
+#elif LJ_PROFILE_WTHREAD
+
+/* Windows timer thread. */
+static DWORD WINAPI profile_thread(void *timerx) {
+ lj_profile_timer *timer = (lj_profile_timer *)timerx;
+ int interval = timer->opt.interval_msec;
+#if LJ_TARGET_WINDOWS
+ timer->wmm_tbp(interval);
+#endif
+ while (1) {
+ Sleep(interval);
+ if (timer->abort)
+ break;
+ timer->opt.handler();
+ }
+#if LJ_TARGET_WINDOWS
+ timer->wmm_tep(interval);
+#endif
+ return 0;
+}
+
+/* Start profiling timer thread. */
+void lj_profile_timer_start(lj_profile_timer *timer) {
+#if LJ_TARGET_WINDOWS
+ if (!timer->wmm) { /* Load WinMM library on-demand. */
+ timer->wmm = LoadLibraryExA("winmm.dll", NULL, 0);
+ if (timer->wmm) {
+ timer->wmm_tbp =
+ (WMM_TPFUNC)GetProcAddress(timer->wmm, "timeBeginPeriod");
+ timer->wmm_tep = (WMM_TPFUNC)GetProcAddress(timer->wmm, "timeEndPeriod");
+ if (!timer->wmm_tbp || !timer->wmm_tep) {
+ timer->wmm = NULL;
+ return;
+ }
+ }
+ }
+#endif
+ InitializeCriticalSection(&timer->lock);
+ timer->abort = 0;
+ timer->thread = CreateThread(NULL, 0, profile_thread, timer, 0, NULL);
+}
+
+/* Stop profiling timer thread. */
+void lj_profile_timer_stop(lj_profile_timer *timer) {
+ timer->abort = 1;
+ WaitForSingleObject(timer->thread, INFINITE);
+ DeleteCriticalSection(&timer->lock);
+}
+
+#endif
+
+#endif /* LJ_HASPROFILE */
diff --git a/src/lj_profile_timer.h b/src/lj_profile_timer.h
new file mode 100644
index 00000000..af9eabce
--- /dev/null
+++ b/src/lj_profile_timer.h
@@ -0,0 +1,83 @@
+/*
+** Simple profiling timer extracted from inbuilt luajit profiler
+*/
+
+#ifndef _LJ_PROFILE_TIMER_H
+#define _LJ_PROFILE_TIMER_H
+
+#include <stdint.h>
+
+#include "lj_arch.h"
+
+#if LJ_HASPROFILE
+
+#if LJ_PROFILE_SIGPROF
+
+#include <sys/time.h>
+#include <signal.h>
+#define profile_lock(ps) UNUSED(ps)
+#define profile_unlock(ps) UNUSED(ps)
+
+#elif LJ_PROFILE_PTHREAD
+
+#include <pthread.h>
+#include <time.h>
+#if LJ_TARGET_PS3
+#include <sys/timer.h>
+#endif
+#define profile_lock(ps) pthread_mutex_lock(&ps->lock)
+#define profile_unlock(ps) pthread_mutex_unlock(&ps->lock)
+
+#elif LJ_PROFILE_WTHREAD
+
+#define WIN32_LEAN_AND_MEAN
+#if LJ_TARGET_XBOX360
+#include <xtl.h>
+#include <xbox.h>
+#else
+#include <windows.h>
+#endif
+typedef unsigned int (WINAPI *WMM_TPFUNC)(unsigned int);
+#define profile_lock(ps) EnterCriticalSection(&ps->lock)
+#define profile_unlock(ps) LeaveCriticalSection(&ps->lock)
+
+#endif
+
+typedef struct {
+#if LJ_PROFILE_SIGPROF
+ void (*handler)(int, siginfo_t*, void*);
+#else
+ void (*handler)(void);
+#endif
+ uint32_t interval_msec;
+} lj_profile_timer_opt;
+
+typedef struct {
+ lj_profile_timer_opt opt;
+#if LJ_PROFILE_SIGPROF
+ struct sigaction oldsa; /* Previous SIGPROF state. */
+#elif LJ_PROFILE_PTHREAD
+ pthread_mutex_t lock; /* g->hookmask update lock. */
+ pthread_t thread; /* Timer thread. */
+ int abort; /* Abort timer thread. */
+#elif LJ_PROFILE_WTHREAD
+#if LJ_TARGET_WINDOWS
+ HINSTANCE wmm; /* WinMM library handle. */
+ WMM_TPFUNC wmm_tbp; /* WinMM timeBeginPeriod function. */
+ WMM_TPFUNC wmm_tep; /* WinMM timeEndPeriod function. */
+#endif
+ CRITICAL_SECTION lock; /* g->hookmask update lock. */
+ HANDLE thread; /* Timer thread. */
+ int abort; /* Abort timer thread. */
+#endif
+} lj_profile_timer;
+
+/* Start profiling timer */
+void lj_profile_timer_start(lj_profile_timer *timer);
+
+/* Stop profiling timer */
+void lj_profile_timer_stop(lj_profile_timer *timer);
+
+#endif /* LJ_HASPROFILE */
+
+#endif
--
2.33.0
More information about the Tarantool-patches
mailing list