summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c')
-rw-r--r--Build/source/texk/web2c/luatexdir/luaprofiler/lua50_profiler.c230
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;
+}