diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c b/Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c new file mode 100644 index 00000000000..54533425c3b --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c @@ -0,0 +1,230 @@ +/* +** LuaProfiler +** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler) +** $Id: lua50_profiler.c,v 1.13 2008/05/19 18:36:23 mascarenhas Exp $ +*/ + +/***************************************************************************** +lua50_profiler.c: + Lua version dependent profiler interface +*****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "clocks.h" +#include "core_profiler.h" +#include "function_meter.h" + +#include "lua.h" +#include "lauxlib.h" + +/* Indices for the main profiler stack and for the original exit function */ +static int exit_id; +static int profstate_id; + +/* Forward declaration */ +static float calcCallTime(lua_State *L); + +/* called by Lua (via the callhook mechanism) */ +static void callhook(lua_State *L, lua_Debug *ar) { + int currentline; + lua_Debug previous_ar; + lprofP_STATE* S; + lua_pushlightuserdata(L, &profstate_id); + lua_gettable(L, LUA_REGISTRYINDEX); + S = (lprofP_STATE*)lua_touserdata(L, -1); + + if (lua_getstack(L, 1, &previous_ar) == 0) { + currentline = -1; + } else { + lua_getinfo(L, "l", &previous_ar); + currentline = previous_ar.currentline; + } + + lua_getinfo(L, "nS", ar); + + if (!ar->event) { + /* entering a function */ + lprofP_callhookIN(S, (char *)ar->name, + (char *)ar->source, ar->linedefined, + currentline); + } + else { /* ar->event == "return" */ + lprofP_callhookOUT(S); + } +} + + +/* Lua function to exit politely the profiler */ +/* redefines the lua exit() function to not break the log file integrity */ +/* The log file is assumed to be valid if the last entry has a stack level */ +/* of 1 (meaning that the function 'main' has been exited) */ +static void exit_profiler(lua_State *L) { + lprofP_STATE* S; + lua_pushlightuserdata(L, &profstate_id); + lua_gettable(L, LUA_REGISTRYINDEX); + S = (lprofP_STATE*)lua_touserdata(L, -1); + /* leave all functions under execution */ + while (lprofP_callhookOUT(S)) ; + /* call the original Lua 'exit' function */ + lua_pushlightuserdata(L, &exit_id); + lua_gettable(L, LUA_REGISTRYINDEX); + lua_call(L, 0, 0); +} + +/* Our new coroutine.create function */ +/* Creates a new profile state for the coroutine */ +#if 0 +static int coroutine_create(lua_State *L) { + lprofP_STATE* S; + lua_State *NL = lua_newthread(L); + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + /* Inits profiler and sets profiler hook for this coroutine */ + S = lprofM_init(); + lua_pushlightuserdata(L, NL); + lua_pushlightuserdata(L, S); + lua_settable(L, LUA_REGISTRYINDEX); + lua_sethook(NL, (lua_Hook)callhook, LUA_MASKCALL | LUA_MASKRET, 0); + return 1; +} +#endif + +static int profiler_pause(lua_State *L) { + lprofP_STATE* S; + lua_pushlightuserdata(L, &profstate_id); + lua_gettable(L, LUA_REGISTRYINDEX); + S = (lprofP_STATE*)lua_touserdata(L, -1); + lprofM_pause_function(S); + return 0; +} + +static int profiler_resume(lua_State *L) { + lprofP_STATE* S; + lua_pushlightuserdata(L, &profstate_id); + lua_gettable(L, LUA_REGISTRYINDEX); + S = (lprofP_STATE*)lua_touserdata(L, -1); + lprofM_pause_function(S); + return 0; +} + +static int profiler_init(lua_State *L) { + lprofP_STATE* S; + const char* outfile; + float function_call_time; + + function_call_time = calcCallTime(L); + + outfile = NULL; + if(lua_gettop(L) == 1) + outfile = luaL_checkstring(L, -1); + + lua_sethook(L, (lua_Hook)callhook, LUA_MASKCALL | LUA_MASKRET, 0); + /* init with default file name and printing a header line */ + if (!(S=lprofP_init_core_profiler(outfile, 1, function_call_time))) { + luaL_error(L,"LuaProfiler error: output file could not be opened!"); + lua_pushnil(L); + return 1; + } + + lua_pushlightuserdata(L, &profstate_id); + lua_pushlightuserdata(L, S); + lua_settable(L, LUA_REGISTRYINDEX); + + /* use our own exit function instead */ + lua_getglobal(L, "os"); + lua_pushlightuserdata(L, &exit_id); + lua_pushstring(L, "exit"); + lua_gettable(L, -3); + lua_settable(L, LUA_REGISTRYINDEX); + lua_pushstring(L, "exit"); + lua_pushcfunction(L, (lua_CFunction)exit_profiler); + lua_settable(L, -3); + +#if 0 + /* use our own coroutine.create function instead */ + lua_getglobal(L, "coroutine"); + lua_pushstring(L, "create"); + lua_pushcfunction(L, (lua_CFunction)coroutine_create); + lua_settable(L, -3); +#endif + + /* the following statement is to simulate how the execution stack is */ + /* supposed to be by the time the profiler is activated when loaded */ + /* as a library. */ + + lprofP_callhookIN(S, "profiler_init", "(C)", -1, -1); + + lua_pushboolean(L, 1); + return 1; +} + +static int profiler_stop(lua_State *L) { + lprofP_STATE* S; + lua_sethook(L, (lua_Hook)callhook, 0, 0); + lua_pushlightuserdata(L, &profstate_id); + lua_gettable(L, LUA_REGISTRYINDEX); + if(!lua_isnil(L, -1)) { + S = (lprofP_STATE*)lua_touserdata(L, -1); + /* leave all functions under execution */ + while (lprofP_callhookOUT(S)); + lprofP_close_core_profiler(S); + lua_pushboolean(L, 1); + } else { lua_pushboolean(L, 0); } + return 1; +} + +/* calculates the approximate time Lua takes to call a function */ +static float calcCallTime(lua_State *L) { + clock_t timer; + char lua_code[] = " \ + function lprofT_mesure_function() \ + local i \ + \ + local t = function() \ + end \ + \ + i = 1 \ + while (i < 100000) do \ + t() \ + i = i + 1 \ + end \ + end \ + \ + lprofT_mesure_function() \ + lprofT_mesure_function = nil \ + "; + + lprofC_start_timer(&timer); + luaL_dostring(L, lua_code); + return lprofC_get_seconds(timer) / (float) 100000; +} + +static const luaL_reg prof_funcs[] = { + { "pause", profiler_pause }, + { "resume", profiler_resume }, + { "start", profiler_init }, + { "stop", profiler_stop }, + { NULL, NULL } +}; + +int luaopen_profiler(lua_State *L) { + luaL_openlib(L, "profiler", prof_funcs, 0); + lua_pushliteral (L, "_COPYRIGHT"); + lua_pushliteral (L, "Copyright (C) 2003-2007 Kepler Project"); + lua_settable (L, -3); + lua_pushliteral (L, "_DESCRIPTION"); + lua_pushliteral (L, "LuaProfiler is a time profiler designed to help finding bottlenecks in your Lua program."); + lua_settable (L, -3); + lua_pushliteral (L, "_NAME"); + lua_pushliteral (L, "LuaProfiler"); + lua_settable (L, -3); + lua_pushliteral (L, "_VERSION"); + lua_pushliteral (L, "2.0.1"); + lua_settable (L, -3); + return 1; +} |