LJ_TRACEPROFILE: Added jit.traceprofile.vmstats()

This function returns counters for total events tallied in each VM
state. Events during traces are aggregated into separate buckets for
non-loop code, loop code, and other code (FFI calls).

Can be used to print summaries like this:

    Interp   C (LJ)       GC     Exit   Record      Opt      ASM  Nonloop     Loop      FFI
    0.000%   0.150%   0.000%   0.000%   0.000%   0.000%   0.000%  23.802%  27.246%  48.802%
This commit is contained in:
Luke Gorrie 2016-10-17 22:37:50 +02:00
parent 606d270826
commit e3a442e6ec
4 changed files with 46 additions and 9 deletions

View File

@ -33,6 +33,7 @@
#include "lj_vm.h" #include "lj_vm.h"
#include "lj_vmevent.h" #include "lj_vmevent.h"
#include "lj_lib.h" #include "lj_lib.h"
#include "lj_def.h"
#include "luajit.h" #include "luajit.h"
@ -650,6 +651,27 @@ LJLIB_CF(jit_traceprofile_tracestats)
return 0; return 0;
} }
LJLIB_CF(jit_traceprofile_vmstats)
{
uint64_t *vmstats = luaJIT_traceprofile_vmstats(L);
if (vmstats == NULL) {
return 0;
} else {
setint64V(L->top++, vmstats[LJ_VMST_INTERP]);
setint64V(L->top++, vmstats[LJ_VMST_C]);
setint64V(L->top++, vmstats[LJ_VMST_GC]);
setint64V(L->top++, vmstats[LJ_VMST_EXIT]);
setint64V(L->top++, vmstats[LJ_VMST_RECORD]);
setint64V(L->top++, vmstats[LJ_VMST_OPT]);
setint64V(L->top++, vmstats[LJ_VMST_ASM]);
setint64V(L->top++, vmstats[LJ_TRACEPROF_VMST_TRACE_NONLOOP]);
setint64V(L->top++, vmstats[LJ_TRACEPROF_VMST_TRACE_LOOP]);
setint64V(L->top++, vmstats[LJ_TRACEPROF_VMST_TRACE_OTHER]);
setint64V(L->top++, vmstats[LJ_TRACEPROF_VMST_TOTAL]);
return 11;
}
}
LJLIB_CF(jit_traceprofile_start) LJLIB_CF(jit_traceprofile_start)
{ {
int interval = lj_lib_checkint(L, 1); int interval = lj_lib_checkint(L, 1);

View File

@ -23,16 +23,9 @@
#include "lj_trace.h" #include "lj_trace.h"
#include "lj_traceprofile.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 { typedef struct TraceProfileState {
global_State *g; /* VM state that started the profiler. */ global_State *g; /* VM state that started the profiler. */
struct sigaction oldsa; struct sigaction oldsa;
int events; /* Number of events (signals) handled. */
uint64_t vmstate[LJ_TRACEPROF_VMST__MAX]; /* Counter per VM state */ uint64_t vmstate[LJ_TRACEPROF_VMST__MAX]; /* Counter per VM state */
} TraceProfileState; } TraceProfileState;
@ -43,7 +36,7 @@ static void traceprofile_signal(int sig, siginfo_t *si, void *data)
global_State *g = state.g; global_State *g = state.g;
intptr_t ip = (intptr_t)((ucontext_t*)data)->uc_mcontext.gregs[REG_RIP]; intptr_t ip = (intptr_t)((ucontext_t*)data)->uc_mcontext.gregs[REG_RIP];
int st = g->vmstate; int st = g->vmstate;
state.events++; state.vmstate[LJ_TRACEPROF_VMST_TOTAL]++;
assert((st >= 0) || (~st < LJ_VMST__MAX)); assert((st >= 0) || (~st < LJ_VMST__MAX));
if (st >= 0) { if (st >= 0) {
lua_State *L = gco2th(gcref(g->cur_L)); lua_State *L = gco2th(gcref(g->cur_L));
@ -54,13 +47,15 @@ static void traceprofile_signal(int sig, siginfo_t *si, void *data)
if ((rel_ip >= 0) && (rel_ip < T->szmcode)) { if ((rel_ip >= 0) && (rel_ip < T->szmcode)) {
if (rel_ip < T->mcloop) { if (rel_ip < T->mcloop) {
T->prof.nonloop++; /* Sample is in non-loop mcode. */ T->prof.nonloop++; /* Sample is in non-loop mcode. */
state.vmstate[LJ_TRACEPROF_VMST_TRACE_NONLOOP]++;
} else { } else {
T->prof.loop++; /* Sample is in loop mcode. */ T->prof.loop++; /* Sample is in loop mcode. */
state.vmstate[LJ_TRACEPROF_VMST_TRACE_LOOP]++;
} }
} else { } else {
T->prof.other++; /* Sample is outside the trace mcode. */ T->prof.other++; /* Sample is outside the trace mcode. */
state.vmstate[LJ_TRACEPROF_VMST_TRACE_OTHER]++;
} }
state.vmstate[LJ_TRACEPROF_VMST_TRACE]++;
} else { } else {
state.vmstate[~st]++; state.vmstate[~st]++;
} }
@ -100,5 +95,14 @@ LUA_API void luaJIT_traceprofile_stop(lua_State *L)
traceprofile_stop_timer(); traceprofile_stop_timer();
} }
LUA_API uint64_t *luaJIT_traceprofile_vmstats(lua_State *L)
{
if (state.g && L == gco2th(gcref(state.g->cur_L))) {
return state.vmstate;
} else {
return NULL;
}
}
#endif #endif

View File

@ -6,6 +6,15 @@
#ifndef _LJ_TRACEPROFILE_H #ifndef _LJ_TRACEPROFILE_H
#define _LJ_TRACEPROFILE_H #define _LJ_TRACEPROFILE_H
/* vmstate extended to represent running in a trace (any one) */
typedef enum {
LJ_TRACEPROF_VMST_TRACE_NONLOOP = LJ_VMST__MAX,
LJ_TRACEPROF_VMST_TRACE_LOOP,
LJ_TRACEPROF_VMST_TRACE_OTHER,
LJ_TRACEPROF_VMST_TOTAL,
LJ_TRACEPROF_VMST__MAX
} TraceProfileVMState;
typedef struct TraceProfile { typedef struct TraceProfile {
uint64_t nonloop; /* Samples taken in non-loop mcode */ uint64_t nonloop; /* Samples taken in non-loop mcode */
uint64_t loop; /* Samples taken in loop mcode */ uint64_t loop; /* Samples taken in loop mcode */

View File

@ -29,6 +29,7 @@
#define _LUAJIT_H #define _LUAJIT_H
#include "lua.h" #include "lua.h"
#include "lj_def.h"
#define LUAJIT_VERSION "LuaJIT 2.1.0-beta2" #define LUAJIT_VERSION "LuaJIT 2.1.0-beta2"
#define LUAJIT_VERSION_NUM 20100 /* Version 2.1.0 = 02.01.00. */ #define LUAJIT_VERSION_NUM 20100 /* Version 2.1.0 = 02.01.00. */
@ -76,6 +77,7 @@ LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
/* Trace profiling API. */ /* Trace profiling API. */
LUA_API void luaJIT_traceprofile_start(lua_State *L, int interval); LUA_API void luaJIT_traceprofile_start(lua_State *L, int interval);
LUA_API void luaJIT_traceprofile_stop(lua_State *L); LUA_API void luaJIT_traceprofile_stop(lua_State *L);
LUA_API uint64_t *luaJIT_traceprofile_vmstats(lua_State *L);
/* Enforce (dynamic) linker error for version mismatches. Call from main. */ /* Enforce (dynamic) linker error for version mismatches. Call from main. */