mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-08 07:34:07 +00:00
Added LUAJIT_TRACEPROFILE
Trace profiling takes regular samples of the program counter and uses them to maintain three new counters for each trace: nonloop: Samples taken when running the non-loop part of the trace loop: Samples taken when running the loop part of the trace other: Samples taken outside the trace mcode (e.g. FFI calls) Trace profiling can be enabled and disabled with: jit.traceprofile.start(interval) jit.traceprofile.stop() The current counter values for a trace can be queried via an extension to the JIT introspection API: jit.util.tracestats(tr) => nonloop, loop, other The overall intention of these counters is to enable development of trace-oriented profiling tools, including self-profiling programs that can identify suspicious traces to flush (e.g. traces that are biased away from the root trace).
This commit is contained in:
parent
3f43f09413
commit
1e213ff3c0
@ -478,7 +478,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_traceprofile.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 \
|
||||||
|
@ -299,6 +299,9 @@ LJLIB_CF(jit_util_traceinfo)
|
|||||||
setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
|
setintfield(L, t, "nk", REF_BIAS - (int32_t)T->nk);
|
||||||
setintfield(L, t, "link", T->link);
|
setintfield(L, t, "link", T->link);
|
||||||
setintfield(L, t, "nexit", T->nsnap);
|
setintfield(L, t, "nexit", T->nsnap);
|
||||||
|
setintfield(L, t, "szmcode", T->szmcode);
|
||||||
|
setintfield(L, t, "mcode", (int32_t)(intptr_t)T->mcode);
|
||||||
|
setintfield(L, t, "mcloop", T->mcloop);
|
||||||
setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype]));
|
setstrV(L, L->top++, lj_str_newz(L, jit_trlinkname[T->linktype]));
|
||||||
lua_setfield(L, -2, "linktype");
|
lua_setfield(L, -2, "linktype");
|
||||||
/* There are many more fields. Add them only when needed. */
|
/* There are many more fields. Add them only when needed. */
|
||||||
@ -629,6 +632,47 @@ static int luaopen_jit_profile(lua_State *L)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* -- Trace profiling ----------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef LUAJIT_TRACEPROFILE
|
||||||
|
|
||||||
|
#define LJLIB_MODULE_jit_traceprofile
|
||||||
|
|
||||||
|
LJLIB_CF(jit_traceprofile_tracestats)
|
||||||
|
{
|
||||||
|
GCtrace *T = jit_checktrace(L);
|
||||||
|
if (T) {
|
||||||
|
setint64V(L->top-1, T->prof.nonloop);
|
||||||
|
setint64V(L->top++, T->prof.loop);
|
||||||
|
setint64V(L->top++, T->prof.other);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LJLIB_CF(jit_traceprofile_start)
|
||||||
|
{
|
||||||
|
int interval = lj_lib_checkint(L, 1);
|
||||||
|
luaJIT_traceprofile_start(L, interval);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LJLIB_CF(jit_traceprofile_stop)
|
||||||
|
{
|
||||||
|
luaJIT_traceprofile_stop(L);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "lj_libdef.h"
|
||||||
|
|
||||||
|
static int luaopen_jit_traceprofile(lua_State *L)
|
||||||
|
{
|
||||||
|
LJ_LIB_REG(L, NULL, jit_traceprofile);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* -- JIT compiler initialization ----------------------------------------- */
|
/* -- JIT compiler initialization ----------------------------------------- */
|
||||||
|
|
||||||
#if LJ_HASJIT
|
#if LJ_HASJIT
|
||||||
@ -764,6 +808,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_TRACEPROFILE
|
||||||
|
lj_lib_prereg(L, LUA_JITLIBNAME ".traceprofile", luaopen_jit_traceprofile,
|
||||||
|
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
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include "lj_obj.h"
|
#include "lj_obj.h"
|
||||||
#include "lj_ir.h"
|
#include "lj_ir.h"
|
||||||
|
#ifdef LUAJIT_TRACEPROFILE
|
||||||
|
#include "lj_traceprofile.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* JIT engine flags. */
|
/* JIT engine flags. */
|
||||||
#define JIT_F_ON 0x00000001
|
#define JIT_F_ON 0x00000001
|
||||||
@ -255,6 +258,9 @@ typedef struct GCtrace {
|
|||||||
TraceNo1 nextside; /* Next side trace of same root trace. */
|
TraceNo1 nextside; /* Next side trace of same root trace. */
|
||||||
uint8_t sinktags; /* Trace has SINK tags. */
|
uint8_t sinktags; /* Trace has SINK tags. */
|
||||||
uint8_t unused1;
|
uint8_t unused1;
|
||||||
|
#ifdef LUAJIT_TRACEPROFILE
|
||||||
|
TraceProfile prof; /* Samples of where the trace spends execution time */
|
||||||
|
#endif
|
||||||
#ifdef LUAJIT_USE_GDBJIT
|
#ifdef LUAJIT_USE_GDBJIT
|
||||||
void *gdbjit_entry; /* GDB JIT entry. */
|
void *gdbjit_entry; /* GDB JIT entry. */
|
||||||
#endif
|
#endif
|
||||||
|
104
src/lj_traceprofile.c
Normal file
104
src/lj_traceprofile.c
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
** Trace profiling.
|
||||||
|
** Copyright (C) 2016 Luke Gorrie. See Copyright Notice in luajit.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define lj_traceprofile_c
|
||||||
|
#define LUA_CORE
|
||||||
|
|
||||||
|
#ifdef LUAJIT_TRACEPROFILE
|
||||||
|
|
||||||
|
#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_traceprofile.h"
|
||||||
|
|
||||||
|
/* vmstate extended to represent running in a trace (any one) */
|
||||||
|
enum {
|
||||||
|
LJ_TRACEPROF_VMST_TRACE = LJ_VMST__MAX,
|
||||||
|
LJ_TRACEPROF_VMST__MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TraceProfileState {
|
||||||
|
global_State *g; /* VM state that started the profiler. */
|
||||||
|
struct sigaction oldsa;
|
||||||
|
int events; /* Number of events (signals) handled. */
|
||||||
|
uint64_t vmstate[LJ_TRACEPROF_VMST__MAX]; /* Counter per VM state */
|
||||||
|
} TraceProfileState;
|
||||||
|
|
||||||
|
static TraceProfileState state;
|
||||||
|
|
||||||
|
static void traceprofile_signal(int sig, siginfo_t *si, void *data)
|
||||||
|
{
|
||||||
|
global_State *g = state.g;
|
||||||
|
intptr_t ip = (intptr_t)((ucontext_t*)data)->uc_mcontext.gregs[REG_RIP];
|
||||||
|
int st = g->vmstate;
|
||||||
|
state.events++;
|
||||||
|
assert((st >= 0) || (~st < LJ_VMST__MAX));
|
||||||
|
if (st >= 0) {
|
||||||
|
lua_State *L = gco2th(gcref(g->cur_L));
|
||||||
|
TraceNo tr = (TraceNo)st;
|
||||||
|
jit_State *J = L2J(L);
|
||||||
|
GCtrace *T = traceref(J, tr);
|
||||||
|
ptrdiff_t rel_ip = ip - (intptr_t)T->mcode;
|
||||||
|
if ((rel_ip >= 0) && (rel_ip < T->szmcode)) {
|
||||||
|
if (rel_ip < T->mcloop) {
|
||||||
|
T->prof.nonloop++; /* Sample is in non-loop mcode. */
|
||||||
|
} else {
|
||||||
|
T->prof.loop++; /* Sample is in loop mcode. */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
T->prof.other++; /* Sample is outside the trace mcode. */
|
||||||
|
}
|
||||||
|
state.vmstate[LJ_TRACEPROF_VMST_TRACE]++;
|
||||||
|
} else {
|
||||||
|
state.vmstate[~st]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void traceprofile_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 = traceprofile_signal;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(SIGPROF, &sa, &state.oldsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void traceprofile_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 void luaJIT_traceprofile_start(lua_State *L, int interval)
|
||||||
|
{
|
||||||
|
memset(&state, sizeof(state), 0);
|
||||||
|
state.g = G(L);
|
||||||
|
traceprofile_start_timer(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
LUA_API void luaJIT_traceprofile_stop(lua_State *L)
|
||||||
|
{
|
||||||
|
traceprofile_stop_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
15
src/lj_traceprofile.h
Normal file
15
src/lj_traceprofile.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
** Trace profiling.
|
||||||
|
** Copyright (C) 2016 Luke Gorrie. See Copyright Notice in luajit.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LJ_TRACEPROFILE_H
|
||||||
|
#define _LJ_TRACEPROFILE_H
|
||||||
|
|
||||||
|
typedef struct TraceProfile {
|
||||||
|
uint64_t nonloop; /* Samples taken in non-loop mcode */
|
||||||
|
uint64_t loop; /* Samples taken in loop mcode */
|
||||||
|
uint64_t other; /* Samples taken outside trace mcode */
|
||||||
|
} TraceProfile;
|
||||||
|
|
||||||
|
#endif
|
@ -73,6 +73,11 @@ 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);
|
||||||
|
|
||||||
|
/* Trace profiling API. */
|
||||||
|
LUA_API void luaJIT_traceprofile_start(lua_State *L, int interval);
|
||||||
|
LUA_API void luaJIT_traceprofile_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