mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-08 07:34:07 +00:00
Added LUAJIT_VMPROFILE: new profiler backend
This commit is contained in:
parent
bd7e42e574
commit
6a66f5d0a6
@ -481,7 +481,7 @@ LJLIB_C= $(LJLIB_O:.o=.c)
|
|||||||
LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
|
LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
|
||||||
lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
|
lj_str.o lj_tab.o lj_func.o lj_udata.o lj_meta.o lj_debug.o \
|
||||||
lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \
|
lj_state.o lj_dispatch.o lj_vmevent.o lj_vmmath.o lj_strscan.o \
|
||||||
lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o \
|
lj_strfmt.o lj_strfmt_num.o lj_api.o lj_profile.o lj_vmprofile.o \
|
||||||
lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
|
lj_lex.o lj_parse.o lj_bcread.o lj_bcwrite.o lj_load.o \
|
||||||
lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
|
lj_ir.o lj_opt_mem.o lj_opt_fold.o lj_opt_narrow.o \
|
||||||
lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
|
lj_opt_dce.o lj_opt_loop.o lj_opt_split.o lj_opt_sink.o \
|
||||||
|
@ -630,6 +630,34 @@ static int luaopen_jit_profile(lua_State *L)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* -- jit.vmprofile module ----------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef LUAJIT_VMPROFILE
|
||||||
|
|
||||||
|
#define LJLIB_MODULE_jit_vmprofile
|
||||||
|
|
||||||
|
LJLIB_CF(jit_vmprofile_start)
|
||||||
|
{
|
||||||
|
luaJIT_vmprofile_start(L);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LJLIB_CF(jit_vmprofile_stop)
|
||||||
|
{
|
||||||
|
luaJIT_vmprofile_stop(L);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "lj_libdef.h"
|
||||||
|
|
||||||
|
static int luaopen_jit_vmprofile(lua_State *L)
|
||||||
|
{
|
||||||
|
LJ_LIB_REG(L, NULL, jit_vmprofile);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* -- JIT compiler initialization ----------------------------------------- */
|
/* -- JIT compiler initialization ----------------------------------------- */
|
||||||
|
|
||||||
#if LJ_HASJIT
|
#if LJ_HASJIT
|
||||||
@ -765,6 +793,10 @@ LUALIB_API int luaopen_jit(lua_State *L)
|
|||||||
lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile,
|
lj_lib_prereg(L, LUA_JITLIBNAME ".profile", luaopen_jit_profile,
|
||||||
tabref(L->env));
|
tabref(L->env));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LUAJIT_VMPROFILE
|
||||||
|
lj_lib_prereg(L, LUA_JITLIBNAME ".vmprofile", luaopen_jit_vmprofile,
|
||||||
|
tabref(L->env));
|
||||||
|
#endif
|
||||||
#ifndef LUAJIT_DISABLE_JITUTIL
|
#ifndef LUAJIT_DISABLE_JITUTIL
|
||||||
lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env));
|
lj_lib_prereg(L, LUA_JITLIBNAME ".util", luaopen_jit_util, tabref(L->env));
|
||||||
#endif
|
#endif
|
||||||
|
113
src/lj_vmprofile.c
Normal file
113
src/lj_vmprofile.c
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
** VM profiling.
|
||||||
|
** Copyright (C) 2016 Luke Gorrie. See Copyright Notice in luajit.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define lj_vmprofile_c
|
||||||
|
#define LUA_CORE
|
||||||
|
|
||||||
|
#ifdef LUAJIT_VMPROFILE
|
||||||
|
|
||||||
|
#define _GNU_SOURCE 1
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <ucontext.h>
|
||||||
|
#undef _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "lj_obj.h"
|
||||||
|
#include "lj_dispatch.h"
|
||||||
|
#include "lj_jit.h"
|
||||||
|
#include "lj_trace.h"
|
||||||
|
#include "lj_vmprofile.h"
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
global_State *g;
|
||||||
|
struct sigaction oldsa;
|
||||||
|
} state;
|
||||||
|
|
||||||
|
/* -- State that the application can manage via FFI ----------------------- */
|
||||||
|
|
||||||
|
static VMProfile *profile; /* Current counters */
|
||||||
|
|
||||||
|
/* How much memory to allocate for profiler counters. */
|
||||||
|
int vmprofile_get_profile_size() {
|
||||||
|
return sizeof(VMProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the memory where the next samples will be counted.
|
||||||
|
Size of the memory must match vmprofile_get_profile_size(). */
|
||||||
|
void vmprofile_set_profile(void *counters) {
|
||||||
|
profile = (VMProfile*)counters;
|
||||||
|
profile->magic = 0x1d50f007;
|
||||||
|
profile->major = 1;
|
||||||
|
profile->minor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Signal handler ------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* Signal handler: bumps one counter. */
|
||||||
|
static void vmprofile_signal(int sig, siginfo_t *si, void *data)
|
||||||
|
{
|
||||||
|
if (profile != NULL) {
|
||||||
|
lua_State *L = gco2th(gcref(state.g->cur_L));
|
||||||
|
int vmstate = state.g->vmstate;
|
||||||
|
/* Not in a trace */
|
||||||
|
if (vmstate < 0) {
|
||||||
|
profile->vm[~vmstate]++;
|
||||||
|
} else {
|
||||||
|
int bucket = vmstate > LJ_VMPROFILE_TRACE_MAX ? 0 : vmstate;
|
||||||
|
VMProfileTraceCount *count = &profile->trace[bucket];
|
||||||
|
GCtrace *T = traceref(L2J(L), (TraceNo)vmstate);
|
||||||
|
intptr_t ip = (intptr_t)((ucontext_t*)data)->uc_mcontext.gregs[REG_RIP];
|
||||||
|
ptrdiff_t mcposition = ip - (intptr_t)T->mcode;
|
||||||
|
if ((mcposition < 0) || (mcposition >= T->szmcode)) {
|
||||||
|
count->other++;
|
||||||
|
} else if ((T->mcloop != 0) && (mcposition >= T->mcloop)) {
|
||||||
|
count->loop++;
|
||||||
|
} else {
|
||||||
|
count->head++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_timer(int 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_SIGINFO | SA_RESTART;
|
||||||
|
sa.sa_sigaction = vmprofile_signal;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(SIGPROF, &sa, &state.oldsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop_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, NULL, &state.oldsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- Lua API ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
LUA_API void luaJIT_vmprofile_start(lua_State *L)
|
||||||
|
{
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
state.g = G(L);
|
||||||
|
start_timer(1); /* Sample every 1ms */
|
||||||
|
}
|
||||||
|
|
||||||
|
LUA_API void luaJIT_vmprofile_stop(lua_State *L)
|
||||||
|
{
|
||||||
|
stop_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
37
src/lj_vmprofile.h
Normal file
37
src/lj_vmprofile.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
** Virtual machine profiling.
|
||||||
|
** Copyright (C) 2017 Luke Gorrie. See Copyright Notice in luajit.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LJ_VMPROFILE_H
|
||||||
|
#define _LJ_VMPROFILE_H
|
||||||
|
|
||||||
|
|
||||||
|
/* Counters are 64-bit to avoid overflow even in long running processes. */
|
||||||
|
typedef uint64_t VMProfileCount;
|
||||||
|
|
||||||
|
/* Maximum trace number for distinct counter buckets. Traces with
|
||||||
|
higher numbers will be counted together in bucket zero. */
|
||||||
|
#define LJ_VMPROFILE_TRACE_MAX 4096
|
||||||
|
|
||||||
|
/* Traces have separate counters for different machine code regions. */
|
||||||
|
typedef struct VMProfileTraceCount {
|
||||||
|
VMProfileCount head; /* Head of the trace (non-looping part) */
|
||||||
|
VMProfileCount loop; /* Loop of the trace */
|
||||||
|
VMProfileCount other; /* Outside the trace mcode (unidentified) */
|
||||||
|
} VMProfileTraceCount;
|
||||||
|
|
||||||
|
/* Complete set of counters for VM and traces. */
|
||||||
|
typedef struct VMProfile {
|
||||||
|
uint32_t magic; /* 0x1d50f007 */
|
||||||
|
uint16_t major, minor; /* 1, 0 */
|
||||||
|
VMProfileCount vm[LJ_VMST__MAX];
|
||||||
|
VMProfileTraceCount trace[LJ_VMPROFILE_TRACE_MAX+1];
|
||||||
|
} VMProfile;
|
||||||
|
|
||||||
|
/* Functions that should be accessed via FFI. */
|
||||||
|
|
||||||
|
void vmprofile_set_profile(void *counters);
|
||||||
|
int vmprofile_get_profile_size();
|
||||||
|
|
||||||
|
#endif
|
@ -73,6 +73,10 @@ LUA_API void luaJIT_profile_stop(lua_State *L);
|
|||||||
LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
|
LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
|
||||||
int depth, size_t *len);
|
int depth, size_t *len);
|
||||||
|
|
||||||
|
/* VM profiling API. */
|
||||||
|
LUA_API void luaJIT_vmprofile_start(lua_State *L);
|
||||||
|
LUA_API void luaJIT_vmprofile_stop(lua_State *L);
|
||||||
|
|
||||||
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
|
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
|
||||||
LUA_API void LUAJIT_VERSION_SYM(void);
|
LUA_API void LUAJIT_VERSION_SYM(void);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user