From 8cd8f7e2fd4645b30caa6e94804e7680519cb0a9 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Thu, 27 Jul 2017 09:38:55 +0000 Subject: [PATCH] vmprofile: Extend Lua API and add test cases Extend the "Lua C API" for vmprofile to support allocating multiple profiles and switching between them. This makes it easier to use. Previously the expectation was that this functionality would be implemented in Lua code using ljsyscall to allocate file-backed shared memory for profiles and then the FFI to switch between them. (This is still possible, too, and it works the same as it did before.) Added test coverage to the test suite. --- src/lib_jit.c | 35 +++++++++++++++++--- src/lj_vmprofile.c | 44 ++++++++++++++++++++++++-- src/luajit.h | 7 ++-- testsuite/test/index | 1 + testsuite/test/raptorjit/index | 1 + testsuite/test/raptorjit/vmprofile.lua | 34 ++++++++++++++++++++ 6 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 testsuite/test/raptorjit/index create mode 100644 testsuite/test/raptorjit/vmprofile.lua diff --git a/src/lib_jit.c b/src/lib_jit.c index d019b252d0..7411328970 100644 --- a/src/lib_jit.c +++ b/src/lib_jit.c @@ -204,16 +204,42 @@ LJLIB_CF(jit_opt_start) #define LJLIB_MODULE_jit_vmprofile +LJLIB_CF(jit_vmprofile_open) +{ + if (L->base < L->top && tvisstr(L->base)) { + return luaJIT_vmprofile_open(L, strdata(lj_lib_checkstr(L, 1))); + } else { + lj_err_argtype(L, 1, "filename"); + return 0; + } +} + +LJLIB_CF(jit_vmprofile_close) +{ + if (L->base < L->top && tvislightud(L->base)) { + return luaJIT_vmprofile_close(L, lightudV(L->base)); + } else { + lj_err_argtype(L, 1, "vmprofile"); + } +} + +LJLIB_CF(jit_vmprofile_select) +{ + if (L->base < L->top && tvislightud(L->base)) { + return luaJIT_vmprofile_select(L, lightudV(L->base)); + } else { + lj_err_argtype(L, 1, "vmprofile"); + } +} + LJLIB_CF(jit_vmprofile_start) { - luaJIT_vmprofile_start(L); - return 0; + return luaJIT_vmprofile_start(L); } LJLIB_CF(jit_vmprofile_stop) { - luaJIT_vmprofile_stop(L); - return 0; + return luaJIT_vmprofile_stop(L); } #include "lj_libdef.h" @@ -234,7 +260,6 @@ JIT_PARAMDEF(JIT_PARAMINIT) 0 }; - /* Arch-dependent CPU detection. */ static uint32_t jit_cpudetect(lua_State *L) { diff --git a/src/lj_vmprofile.c b/src/lj_vmprofile.c index 3f625761e7..bb35e9bc54 100644 --- a/src/lj_vmprofile.c +++ b/src/lj_vmprofile.c @@ -9,12 +9,18 @@ #define _GNU_SOURCE 1 #include #include +#include +#include #include +#include +#include +#include #include #include #include #undef _GNU_SOURCE +#include "lj_err.h" #include "lj_obj.h" #include "lj_dispatch.h" #include "lj_jit.h" @@ -99,15 +105,49 @@ static void stop_timer() /* -- Lua API ------------------------------------------------------------- */ -LUA_API void luaJIT_vmprofile_start(lua_State *L) +LUA_API int luaJIT_vmprofile_open(lua_State *L, const char *str) +{ + int fd; + void *ptr; + if (((fd = open(str, O_RDWR|O_CREAT, 0666)) != -1) && + ((ftruncate(fd, sizeof(VMProfile))) != -1) && + ((ptr = mmap(NULL, sizeof(VMProfile), PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0)) != MAP_FAILED)) { + memset(ptr, 0, sizeof(VMProfile)); + setlightudV(L->base, checklightudptr(L, ptr)); + } else { + setnilV(L->base); + } + if (fd != -1) { + close(fd); + } + return 1; +} + +LUA_API int luaJIT_vmprofile_close(lua_State *L, void *ud) +{ + munmap(ud, sizeof(VMProfile)); + return 0; +} + +LUA_API int luaJIT_vmprofile_select(lua_State *L, void *ud) +{ + setlightudV(L->base, checklightudptr(L, profile)); + profile = (VMProfile *)ud; + return 1; +} + +LUA_API int luaJIT_vmprofile_start(lua_State *L) { memset(&state, 0, sizeof(state)); state.g = G(L); start_timer(1); /* Sample every 1ms */ + return 0; } -LUA_API void luaJIT_vmprofile_stop(lua_State *L) +LUA_API int luaJIT_vmprofile_stop(lua_State *L) { stop_timer(); + return 0; } diff --git a/src/luajit.h b/src/luajit.h index 597b3e1f27..30baabb2a9 100644 --- a/src/luajit.h +++ b/src/luajit.h @@ -65,8 +65,11 @@ enum { LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode); /* VM profiling API. */ -LUA_API void luaJIT_vmprofile_start(lua_State *L); -LUA_API void luaJIT_vmprofile_stop(lua_State *L); +LUA_API int luaJIT_vmprofile_start(lua_State *L); +LUA_API int luaJIT_vmprofile_open(lua_State *L, const char *str); +LUA_API int luaJIT_vmprofile_select(lua_State *L, void *ud); +LUA_API int luaJIT_vmprofile_close(lua_State *L, void *ud); +LUA_API int luaJIT_vmprofile_stop(lua_State *L); /* Enforce (dynamic) linker error for version mismatches. Call from main. */ LUA_API void LUAJIT_VERSION_SYM(void); diff --git a/testsuite/test/index b/testsuite/test/index index bd4081e39e..41afbcf99c 100644 --- a/testsuite/test/index +++ b/testsuite/test/index @@ -4,3 +4,4 @@ bc +luajit>=2 computations.lua trace +jit opt +jit +raptorjit diff --git a/testsuite/test/raptorjit/index b/testsuite/test/raptorjit/index new file mode 100644 index 0000000000..1a3dcd3271 --- /dev/null +++ b/testsuite/test/raptorjit/index @@ -0,0 +1 @@ +vmprofile.lua diff --git a/testsuite/test/raptorjit/vmprofile.lua b/testsuite/test/raptorjit/vmprofile.lua new file mode 100644 index 0000000000..ae9bb30a41 --- /dev/null +++ b/testsuite/test/raptorjit/vmprofile.lua @@ -0,0 +1,34 @@ +local vmprofile = require("jit.vmprofile") + +do --- vmprofile start and stop + vmprofile.start() + vmprofile.stop() +end + + +do --- vmprofile multiple starts + for i = 1, 1000 do vmprofile.start() end + vmprofile.stop() +end + +do --- vmprofile multiple profiles + vmprofile.start() + local a = vmprofile.open("a.vmprofile") + local b = vmprofile.open("b.vmprofile") + vmprofile.select(a) + for i = 1, 1e8 do end + vmprofile.select(b) + for i = 1, 1e8 do end + vmprofile.select(a) + for i = 1, 1e8 do end + vmprofile.stop() + vmprofile.close(a) + vmprofile.close(b) + -- simple sanity check that the profiles have different contents. + -- e.g. to make sure there was at least one sample taken somewhere. + assert(io.open("a.vmprofile", "r"):read("*a") ~= + io.open("b.vmprofile", "r"):read("*a"), + "check that profiles have different contents") + os.remove("a.vmprofile") + os.remove("b.vmprofile") +end