mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 23:24:09 +00:00
Low-overhead profiler, part 4: JIT compiler support.
This commit is contained in:
parent
d3d30d389b
commit
d1194a82eb
@ -170,12 +170,12 @@ 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_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_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_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_profile.h luajit.h
|
lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h
|
||||||
lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.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_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_ir.h lj_jit.h lj_ircall.h \
|
lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \
|
||||||
lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h lj_record.h \
|
lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \
|
||||||
lj_ffrecord.h lj_snap.h lj_vm.h
|
lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h
|
||||||
lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
lj_snap.o: lj_snap.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
|
||||||
lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
|
lj_tab.h lj_state.h lj_frame.h lj_bc.h lj_ir.h lj_jit.h lj_iropt.h \
|
||||||
lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
|
lj_trace.h lj_dispatch.h lj_traceerr.h lj_snap.h lj_target.h \
|
||||||
|
@ -1565,6 +1565,7 @@ static void asm_ir(ASMState *as, IRIns *ir)
|
|||||||
case IR_PHI: asm_phi(as, ir); break;
|
case IR_PHI: asm_phi(as, ir); break;
|
||||||
case IR_HIOP: asm_hiop(as, ir); break;
|
case IR_HIOP: asm_hiop(as, ir); break;
|
||||||
case IR_GCSTEP: asm_gcstep(as, ir); break;
|
case IR_GCSTEP: asm_gcstep(as, ir); break;
|
||||||
|
case IR_PROF: asm_prof(as, ir); break;
|
||||||
|
|
||||||
/* Guarded assertions. */
|
/* Guarded assertions. */
|
||||||
case IR_LT: case IR_GE: case IR_LE: case IR_GT:
|
case IR_LT: case IR_GE: case IR_LE: case IR_GT:
|
||||||
|
@ -1915,6 +1915,16 @@ static void asm_hiop(ASMState *as, IRIns *ir)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Profiling ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void asm_prof(ASMState *as, IRIns *ir)
|
||||||
|
{
|
||||||
|
UNUSED(ir);
|
||||||
|
asm_guardcc(as, CC_NE);
|
||||||
|
emit_n(as, ARMI_TST|ARMI_K12|HOOK_PROFILE, RID_TMP);
|
||||||
|
emit_lsptr(as, ARMI_LDRB, RID_TMP, (void *)&J2G(as->J)->hookmask);
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Stack handling ------------------------------------------------------ */
|
/* -- Stack handling ------------------------------------------------------ */
|
||||||
|
|
||||||
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
||||||
|
@ -1562,6 +1562,17 @@ static void asm_hiop(ASMState *as, IRIns *ir)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Profiling ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void asm_prof(ASMState *as, IRIns *ir)
|
||||||
|
{
|
||||||
|
UNUSED(ir);
|
||||||
|
asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO);
|
||||||
|
emit_tsi(as, MIPSI_ANDI, RID_TMP, RID_TMP, HOOK_PROFILE);
|
||||||
|
emit_lsglptr(as, MIPSI_LBU, RID_TMP,
|
||||||
|
(int32_t)offsetof(global_State, hookmask));
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Stack handling ------------------------------------------------------ */
|
/* -- Stack handling ------------------------------------------------------ */
|
||||||
|
|
||||||
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
||||||
|
@ -1738,6 +1738,17 @@ static void asm_hiop(ASMState *as, IRIns *ir)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Profiling ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void asm_prof(ASMState *as, IRIns *ir)
|
||||||
|
{
|
||||||
|
UNUSED(ir);
|
||||||
|
asm_guardcc(as, CC_NE);
|
||||||
|
emit_asi(as, PPCI_ANDIDOT, RID_TMP, RID_TMP, HOOK_PROFILE);
|
||||||
|
emit_lsglptr(as, PPCI_LBZ, RID_TMP,
|
||||||
|
(int32_t)offsetof(global_State, hookmask));
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Stack handling ------------------------------------------------------ */
|
/* -- Stack handling ------------------------------------------------------ */
|
||||||
|
|
||||||
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
||||||
|
@ -2348,6 +2348,16 @@ static void asm_hiop(ASMState *as, IRIns *ir)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Profiling ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void asm_prof(ASMState *as, IRIns *ir)
|
||||||
|
{
|
||||||
|
UNUSED(ir);
|
||||||
|
asm_guardcc(as, CC_NE);
|
||||||
|
emit_i8(as, HOOK_PROFILE);
|
||||||
|
emit_rma(as, XO_GROUP3b, XOg_TEST, &J2G(as->J)->hookmask);
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Stack handling ------------------------------------------------------ */
|
/* -- Stack handling ------------------------------------------------------ */
|
||||||
|
|
||||||
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
/* Check Lua stack size for overflow. Use exit handler as fallback. */
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
_(USE, S , ref, ___) \
|
_(USE, S , ref, ___) \
|
||||||
_(PHI, S , ref, ref) \
|
_(PHI, S , ref, ref) \
|
||||||
_(RENAME, S , ref, lit) \
|
_(RENAME, S , ref, lit) \
|
||||||
|
_(PROF, S , ___, ___) \
|
||||||
\
|
\
|
||||||
/* Constants. */ \
|
/* Constants. */ \
|
||||||
_(KPRI, N , ___, ___) \
|
_(KPRI, N , ___, ___) \
|
||||||
|
@ -396,6 +396,12 @@ typedef struct jit_State {
|
|||||||
size_t szallmcarea; /* Total size of all allocated mcode areas. */
|
size_t szallmcarea; /* Total size of all allocated mcode areas. */
|
||||||
|
|
||||||
TValue errinfo; /* Additional info element for trace errors. */
|
TValue errinfo; /* Additional info element for trace errors. */
|
||||||
|
|
||||||
|
#if LJ_HASPROFILE
|
||||||
|
GCproto *prev_pt; /* Previous prototype. */
|
||||||
|
BCLine prev_line; /* Previous line. */
|
||||||
|
int prof_mode; /* Profiling mode: 0, 'f', 'l'. */
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#if LJ_TARGET_ARM
|
#if LJ_TARGET_ARM
|
||||||
LJ_ALIGN(16) /* For DISPATCH-relative addresses in assembler part. */
|
LJ_ALIGN(16) /* For DISPATCH-relative addresses in assembler part. */
|
||||||
|
@ -2285,6 +2285,17 @@ LJFOLDF(barrier_tnew_tdup)
|
|||||||
return DROPFOLD;
|
return DROPFOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Profiling ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
LJFOLD(PROF any any)
|
||||||
|
LJFOLDF(prof)
|
||||||
|
{
|
||||||
|
IRRef ref = J->chain[IR_PROF];
|
||||||
|
if (ref+1 == J->cur.nins) /* Drop neighbouring IR_PROF. */
|
||||||
|
return ref;
|
||||||
|
return EMITFOLD;
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Stores and allocations ---------------------------------------------- */
|
/* -- Stores and allocations ---------------------------------------------- */
|
||||||
|
|
||||||
/* Stores and allocations cannot be folded or passed on to CSE in general.
|
/* Stores and allocations cannot be folded or passed on to CSE in general.
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
#include "lj_frame.h"
|
#include "lj_frame.h"
|
||||||
#include "lj_debug.h"
|
#include "lj_debug.h"
|
||||||
#include "lj_dispatch.h"
|
#include "lj_dispatch.h"
|
||||||
|
#if LJ_HASJIT
|
||||||
|
#include "lj_jit.h"
|
||||||
|
#include "lj_trace.h"
|
||||||
|
#endif
|
||||||
#include "lj_profile.h"
|
#include "lj_profile.h"
|
||||||
|
|
||||||
#include "luajit.h"
|
#include "luajit.h"
|
||||||
@ -218,13 +222,20 @@ LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
|
|||||||
ProfileState *ps = &profile_state;
|
ProfileState *ps = &profile_state;
|
||||||
int interval = LJ_PROFILE_INTERVAL_DEFAULT;
|
int interval = LJ_PROFILE_INTERVAL_DEFAULT;
|
||||||
while (*mode) {
|
while (*mode) {
|
||||||
switch (*mode++) {
|
int m = *mode++;
|
||||||
|
switch (m) {
|
||||||
case 'i':
|
case 'i':
|
||||||
interval = 0;
|
interval = 0;
|
||||||
while (*mode >= '0' && *mode <= '9')
|
while (*mode >= '0' && *mode <= '9')
|
||||||
interval = interval * 10 + (*mode++ - '0');
|
interval = interval * 10 + (*mode++ - '0');
|
||||||
if (interval <= 0) interval = 1;
|
if (interval <= 0) interval = 1;
|
||||||
break;
|
break;
|
||||||
|
#if LJ_HASJIT
|
||||||
|
case 'l': case 'f':
|
||||||
|
L2J(L)->prof_mode = m;
|
||||||
|
lj_trace_flushall(L);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default: /* Ignore unknown mode chars. */
|
default: /* Ignore unknown mode chars. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -251,6 +262,10 @@ LUA_API void luaJIT_profile_stop(lua_State *L)
|
|||||||
profile_timer_stop(ps);
|
profile_timer_stop(ps);
|
||||||
g->hookmask &= ~HOOK_PROFILE;
|
g->hookmask &= ~HOOK_PROFILE;
|
||||||
lj_dispatch_update(g);
|
lj_dispatch_update(g);
|
||||||
|
#if LJ_HASJIT
|
||||||
|
G2J(g)->prof_mode = 0;
|
||||||
|
lj_trace_flushall(L);
|
||||||
|
#endif
|
||||||
lj_buf_free(g, &ps->sb);
|
lj_buf_free(g, &ps->sb);
|
||||||
setmref(ps->sb.b, NULL);
|
setmref(ps->sb.b, NULL);
|
||||||
setmref(ps->sb.e, NULL);
|
setmref(ps->sb.e, NULL);
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "lj_bc.h"
|
#include "lj_bc.h"
|
||||||
#include "lj_ff.h"
|
#include "lj_ff.h"
|
||||||
|
#if LJ_HASPROFILE
|
||||||
|
#include "lj_debug.h"
|
||||||
|
#endif
|
||||||
#include "lj_ir.h"
|
#include "lj_ir.h"
|
||||||
#include "lj_jit.h"
|
#include "lj_jit.h"
|
||||||
#include "lj_ircall.h"
|
#include "lj_ircall.h"
|
||||||
@ -579,6 +582,52 @@ static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev)
|
|||||||
} /* Side trace continues across a loop that's left or not entered. */
|
} /* Side trace continues across a loop that's left or not entered. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -- Record profiler hook checks ----------------------------------------- */
|
||||||
|
|
||||||
|
#if LJ_HASPROFILE
|
||||||
|
|
||||||
|
/* Need to insert profiler hook check? */
|
||||||
|
static int rec_profile_need(jit_State *J, GCproto *pt, const BCIns *pc)
|
||||||
|
{
|
||||||
|
GCproto *ppt;
|
||||||
|
lua_assert(J->prof_mode == 'f' || J->prof_mode == 'l');
|
||||||
|
if (!pt)
|
||||||
|
return 0;
|
||||||
|
ppt = J->prev_pt;
|
||||||
|
J->prev_pt = pt;
|
||||||
|
if (pt != ppt && ppt) {
|
||||||
|
J->prev_line = -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (J->prof_mode == 'l') {
|
||||||
|
BCLine line = lj_debug_line(pt, proto_bcpos(pt, pc));
|
||||||
|
BCLine pline = J->prev_line;
|
||||||
|
J->prev_line = line;
|
||||||
|
if (pline != line)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rec_profile_ins(jit_State *J, const BCIns *pc)
|
||||||
|
{
|
||||||
|
if (J->prof_mode && rec_profile_need(J, J->pt, pc)) {
|
||||||
|
emitir(IRTG(IR_PROF, IRT_NIL), 0, 0);
|
||||||
|
lj_snap_add(J);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rec_profile_ret(jit_State *J)
|
||||||
|
{
|
||||||
|
if (J->prof_mode == 'f') {
|
||||||
|
emitir(IRTG(IR_PROF, IRT_NIL), 0, 0);
|
||||||
|
J->prev_pt = NULL;
|
||||||
|
lj_snap_add(J);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* -- Record calls and returns -------------------------------------------- */
|
/* -- Record calls and returns -------------------------------------------- */
|
||||||
|
|
||||||
/* Specialize to the runtime value of the called function or its prototype. */
|
/* Specialize to the runtime value of the called function or its prototype. */
|
||||||
@ -1770,6 +1819,10 @@ void lj_record_ins(jit_State *J)
|
|||||||
rec_check_ir(J);
|
rec_check_ir(J);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LJ_HASPROFILE
|
||||||
|
rec_profile_ins(J, pc);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Keep a copy of the runtime values of var/num/str operands. */
|
/* Keep a copy of the runtime values of var/num/str operands. */
|
||||||
#define rav (&ix.valv)
|
#define rav (&ix.valv)
|
||||||
#define rbv (&ix.tabv)
|
#define rbv (&ix.tabv)
|
||||||
@ -2074,6 +2127,9 @@ void lj_record_ins(jit_State *J)
|
|||||||
rc = (BCReg)(J->L->top - J->L->base) - ra + 1;
|
rc = (BCReg)(J->L->top - J->L->base) - ra + 1;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case BC_RET: case BC_RET0: case BC_RET1:
|
case BC_RET: case BC_RET0: case BC_RET1:
|
||||||
|
#if LJ_HASPROFILE
|
||||||
|
rec_profile_ret(J);
|
||||||
|
#endif
|
||||||
lj_record_ret(J, ra, (ptrdiff_t)rc-1);
|
lj_record_ret(J, ra, (ptrdiff_t)rc-1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2303,6 +2359,10 @@ void lj_record_setup(jit_State *J)
|
|||||||
if (1 + J->pt->framesize >= LJ_MAX_JSLOTS)
|
if (1 + J->pt->framesize >= LJ_MAX_JSLOTS)
|
||||||
lj_trace_err(J, LJ_TRERR_STACKOV);
|
lj_trace_err(J, LJ_TRERR_STACKOV);
|
||||||
}
|
}
|
||||||
|
#if LJ_HASPROFILE
|
||||||
|
J->prev_pt = NULL;
|
||||||
|
J->prev_line = -1;
|
||||||
|
#endif
|
||||||
#ifdef LUAJIT_ENABLE_CHECKHOOK
|
#ifdef LUAJIT_ENABLE_CHECKHOOK
|
||||||
/* Regularly check for instruction/line hooks from compiled code and
|
/* Regularly check for instruction/line hooks from compiled code and
|
||||||
** exit to the interpreter if the hooks are set.
|
** exit to the interpreter if the hooks are set.
|
||||||
|
@ -766,17 +766,20 @@ int LJ_FASTCALL lj_trace_exit(jit_State *J, void *exptr)
|
|||||||
if (errcode)
|
if (errcode)
|
||||||
return -errcode; /* Return negated error code. */
|
return -errcode; /* Return negated error code. */
|
||||||
|
|
||||||
lj_vmevent_send(L, TEXIT,
|
if (!(LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE)))
|
||||||
lj_state_checkstack(L, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK);
|
lj_vmevent_send(L, TEXIT,
|
||||||
setintV(L->top++, J->parent);
|
lj_state_checkstack(L, 4+RID_NUM_GPR+RID_NUM_FPR+LUA_MINSTACK);
|
||||||
setintV(L->top++, J->exitno);
|
setintV(L->top++, J->parent);
|
||||||
trace_exit_regs(L, ex);
|
setintV(L->top++, J->exitno);
|
||||||
);
|
trace_exit_regs(L, ex);
|
||||||
|
);
|
||||||
|
|
||||||
pc = exd.pc;
|
pc = exd.pc;
|
||||||
cf = cframe_raw(L->cframe);
|
cf = cframe_raw(L->cframe);
|
||||||
setcframe_pc(cf, pc);
|
setcframe_pc(cf, pc);
|
||||||
if (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize) {
|
if (LJ_HASPROFILE && (G(L)->hookmask & HOOK_PROFILE)) {
|
||||||
|
/* Just exit to interpreter. */
|
||||||
|
} else if (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize) {
|
||||||
if (!(G(L)->hookmask & HOOK_GC))
|
if (!(G(L)->hookmask & HOOK_GC))
|
||||||
lj_gc_step(L); /* Exited because of GC: drive GC forward. */
|
lj_gc_step(L); /* Exited because of GC: drive GC forward. */
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user