Add low-overhead profiler. Part 1: interpreter, low-level C API.

This commit is contained in:
Mike Pall
2013-09-02 01:49:19 +02:00
parent 19c2dd17db
commit 4dce22c40d
18 changed files with 558 additions and 33 deletions

View File

@@ -27,6 +27,9 @@
#endif
#include "lj_trace.h"
#include "lj_dispatch.h"
#if LJ_HASPROFILE
#include "lj_profile.h"
#endif
#include "lj_vm.h"
#include "luajit.h"
@@ -84,11 +87,12 @@ void lj_dispatch_init_hotcount(global_State *g)
#endif
/* Internal dispatch mode bits. */
#define DISPMODE_JIT 0x01 /* JIT compiler on. */
#define DISPMODE_REC 0x02 /* Recording active. */
#define DISPMODE_CALL 0x01 /* Override call dispatch. */
#define DISPMODE_RET 0x02 /* Override return dispatch. */
#define DISPMODE_INS 0x04 /* Override instruction dispatch. */
#define DISPMODE_CALL 0x08 /* Override call dispatch. */
#define DISPMODE_RET 0x10 /* Override return dispatch. */
#define DISPMODE_JIT 0x10 /* JIT compiler on. */
#define DISPMODE_REC 0x20 /* Recording active. */
#define DISPMODE_PROF 0x40 /* Profiling active. */
/* Update dispatch table depending on various flags. */
void lj_dispatch_update(global_State *g)
@@ -99,6 +103,9 @@ void lj_dispatch_update(global_State *g)
mode |= (G2J(g)->flags & JIT_F_ON) ? DISPMODE_JIT : 0;
mode |= G2J(g)->state != LJ_TRACE_IDLE ?
(DISPMODE_REC|DISPMODE_INS|DISPMODE_CALL) : 0;
#endif
#if LJ_HASPROFILE
mode |= (g->hookmask & HOOK_PROFILE) ? (DISPMODE_PROF|DISPMODE_INS) : 0;
#endif
mode |= (g->hookmask & (LUA_MASKLINE|LUA_MASKCOUNT)) ? DISPMODE_INS : 0;
mode |= (g->hookmask & LUA_MASKCALL) ? DISPMODE_CALL : 0;
@@ -128,9 +135,9 @@ void lj_dispatch_update(global_State *g)
disp[GG_LEN_DDISP+BC_LOOP] = f_loop;
/* Set dynamic instruction dispatch. */
if ((oldmode ^ mode) & (DISPMODE_REC|DISPMODE_INS)) {
if ((oldmode ^ mode) & (DISPMODE_PROF|DISPMODE_REC|DISPMODE_INS)) {
/* Need to update the whole table. */
if (!(mode & (DISPMODE_REC|DISPMODE_INS))) { /* No ins dispatch? */
if (!(mode & DISPMODE_INS)) { /* No ins dispatch? */
/* Copy static dispatch table to dynamic dispatch table. */
memcpy(&disp[0], &disp[GG_LEN_DDISP], GG_LEN_SDISP*sizeof(ASMFunction));
/* Overwrite with dynamic return dispatch. */
@@ -142,12 +149,13 @@ void lj_dispatch_update(global_State *g)
}
} else {
/* The recording dispatch also checks for hooks. */
ASMFunction f = (mode & DISPMODE_REC) ? lj_vm_record : lj_vm_inshook;
ASMFunction f = (mode & DISPMODE_PROF) ? lj_vm_profhook :
(mode & DISPMODE_REC) ? lj_vm_record : lj_vm_inshook;
uint32_t i;
for (i = 0; i < GG_LEN_SDISP; i++)
disp[i] = f;
}
} else if (!(mode & (DISPMODE_REC|DISPMODE_INS))) {
} else if (!(mode & DISPMODE_INS)) {
/* Otherwise set dynamic counting ins. */
disp[BC_FORL] = f_forl;
disp[BC_ITERL] = f_iterl;
@@ -495,3 +503,34 @@ out:
return makeasmfunc(lj_bc_ofs[op]); /* Return static dispatch target. */
}
#if LJ_HASPROFILE
/* Profile dispatch. */
void LJ_FASTCALL lj_dispatch_profile(lua_State *L, const BCIns *pc)
{
ERRNO_SAVE
global_State *g = G(L);
uint8_t mask = g->hookmask;
g->hookmask = (mask & ~HOOK_PROFILE);
lj_dispatch_update(g);
if (!(mask & HOOK_VMEVENT)) {
GCfunc *fn = curr_func(L);
GCproto *pt = funcproto(fn);
void *cf = cframe_raw(L->cframe);
const BCIns *oldpc = cframe_pc(cf);
uint8_t oldh = hook_save(g);
BCReg slots;
hook_vmevent(g);
setcframe_pc(cf, pc);
slots = cur_topslot(pt, pc, cframe_multres_n(cf));
L->top = L->base + slots; /* Fix top. */
lj_profile_interpreter(L);
setgcref(g->cur_L, obj2gco(L));
setcframe_pc(cf, oldpc);
hook_restore(g, oldh);
lj_trace_abort(g);
setvmstate(g, INTERP);
}
ERRNO_RESTORE
}
#endif