beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luaprofiler / lua50_profiler.c
blob692d774c0c6d5aec6997838d3c7c5da2956b7079
1 /*
2 ** LuaProfiler
3 ** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
4 ** $Id: lua50_profiler.c,v 1.13 2008/05/19 18:36:23 mascarenhas Exp $
5 */
7 /*****************************************************************************
8 lua50_profiler.c:
9 Lua version dependent profiler interface
10 *****************************************************************************/
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
16 #include "clocks.h"
17 #include "core_profiler.h"
18 #include "function_meter.h"
20 #include "lua.h"
21 #include "lauxlib.h"
23 /* Indices for the main profiler stack and for the original exit function */
24 static int exit_id;
25 static int profstate_id;
27 /* Forward declaration */
28 static float calcCallTime(lua_State *L);
30 /* called by Lua (via the callhook mechanism) */
31 static void callhook(lua_State *L, lua_Debug *ar) {
32 int currentline;
33 lua_Debug previous_ar;
34 lprofP_STATE* S;
35 lua_pushlightuserdata(L, &profstate_id);
36 lua_gettable(L, LUA_REGISTRYINDEX);
37 S = (lprofP_STATE*)lua_touserdata(L, -1);
39 if (lua_getstack(L, 1, &previous_ar) == 0) {
40 currentline = -1;
41 } else {
42 lua_getinfo(L, "l", &previous_ar);
43 currentline = previous_ar.currentline;
46 lua_getinfo(L, "nS", ar);
48 if (!ar->event) {
49 /* entering a function */
50 lprofP_callhookIN(S, (char *)ar->name,
51 (char *)ar->source, ar->linedefined,
52 currentline);
54 else { /* ar->event == "return" */
55 lprofP_callhookOUT(S);
60 /* Lua function to exit politely the profiler */
61 /* redefines the lua exit() function to not break the log file integrity */
62 /* The log file is assumed to be valid if the last entry has a stack level */
63 /* of 1 (meaning that the function 'main' has been exited) */
64 static void exit_profiler(lua_State *L) {
65 lprofP_STATE* S;
66 lua_pushlightuserdata(L, &profstate_id);
67 lua_gettable(L, LUA_REGISTRYINDEX);
68 S = (lprofP_STATE*)lua_touserdata(L, -1);
69 /* leave all functions under execution */
70 while (lprofP_callhookOUT(S)) ;
71 /* call the original Lua 'exit' function */
72 lua_pushlightuserdata(L, &exit_id);
73 lua_gettable(L, LUA_REGISTRYINDEX);
74 lua_call(L, 0, 0);
77 /* Our new coroutine.create function */
78 /* Creates a new profile state for the coroutine */
79 #if 0
80 static int coroutine_create(lua_State *L) {
81 lprofP_STATE* S;
82 lua_State *NL = lua_newthread(L);
83 luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
84 "Lua function expected");
85 lua_pushvalue(L, 1); /* move function to top */
86 lua_xmove(L, NL, 1); /* move function from L to NL */
87 /* Inits profiler and sets profiler hook for this coroutine */
88 S = lprofM_init();
89 lua_pushlightuserdata(L, NL);
90 lua_pushlightuserdata(L, S);
91 lua_settable(L, LUA_REGISTRYINDEX);
92 lua_sethook(NL, (lua_Hook)callhook, LUA_MASKCALL | LUA_MASKRET, 0);
93 return 1;
95 #endif
97 static int profiler_pause(lua_State *L) {
98 lprofP_STATE* S;
99 lua_pushlightuserdata(L, &profstate_id);
100 lua_gettable(L, LUA_REGISTRYINDEX);
101 S = (lprofP_STATE*)lua_touserdata(L, -1);
102 lprofM_pause_function(S);
103 return 0;
106 static int profiler_resume(lua_State *L) {
107 lprofP_STATE* S;
108 lua_pushlightuserdata(L, &profstate_id);
109 lua_gettable(L, LUA_REGISTRYINDEX);
110 S = (lprofP_STATE*)lua_touserdata(L, -1);
111 lprofM_pause_function(S);
112 return 0;
115 static int profiler_init(lua_State *L) {
116 lprofP_STATE* S;
117 const char* outfile;
118 float function_call_time;
120 function_call_time = calcCallTime(L);
122 outfile = NULL;
123 if(lua_gettop(L) == 1)
124 outfile = luaL_checkstring(L, -1);
126 lua_sethook(L, (lua_Hook)callhook, LUA_MASKCALL | LUA_MASKRET, 0);
127 /* init with default file name and printing a header line */
128 if (!(S=lprofP_init_core_profiler(outfile, 1, function_call_time))) {
129 luaL_error(L,"LuaProfiler error: output file could not be opened!");
130 lua_pushnil(L);
131 return 1;
134 lua_pushlightuserdata(L, &profstate_id);
135 lua_pushlightuserdata(L, S);
136 lua_settable(L, LUA_REGISTRYINDEX);
138 /* use our own exit function instead */
139 lua_getglobal(L, "os");
140 lua_pushlightuserdata(L, &exit_id);
141 lua_pushstring(L, "exit");
142 lua_gettable(L, -3);
143 lua_settable(L, LUA_REGISTRYINDEX);
144 lua_pushstring(L, "exit");
145 lua_pushcfunction(L, (lua_CFunction)exit_profiler);
146 lua_settable(L, -3);
148 #if 0
149 /* use our own coroutine.create function instead */
150 lua_getglobal(L, "coroutine");
151 lua_pushstring(L, "create");
152 lua_pushcfunction(L, (lua_CFunction)coroutine_create);
153 lua_settable(L, -3);
154 #endif
156 /* the following statement is to simulate how the execution stack is */
157 /* supposed to be by the time the profiler is activated when loaded */
158 /* as a library. */
160 lprofP_callhookIN(S, "profiler_init", "(C)", -1, -1);
162 lua_pushboolean(L, 1);
163 return 1;
166 static int profiler_stop(lua_State *L) {
167 lprofP_STATE* S;
168 lua_sethook(L, (lua_Hook)callhook, 0, 0);
169 lua_pushlightuserdata(L, &profstate_id);
170 lua_gettable(L, LUA_REGISTRYINDEX);
171 if(!lua_isnil(L, -1)) {
172 S = (lprofP_STATE*)lua_touserdata(L, -1);
173 /* leave all functions under execution */
174 while (lprofP_callhookOUT(S));
175 lprofP_close_core_profiler(S);
176 lua_pushboolean(L, 1);
177 } else { lua_pushboolean(L, 0); }
178 return 1;
181 /* calculates the approximate time Lua takes to call a function */
182 static float calcCallTime(lua_State *L) {
183 clock_t timer;
184 char lua_code[] = " \
185 function lprofT_mesure_function() \
186 local i \
188 local t = function() \
189 end \
191 i = 1 \
192 while (i < 100000) do \
193 t() \
194 i = i + 1 \
195 end \
196 end \
198 lprofT_mesure_function() \
199 lprofT_mesure_function = nil \
202 lprofC_start_timer(&timer);
203 luaL_dostring(L, lua_code);
204 return lprofC_get_seconds(timer) / (float) 100000;
207 static const luaL_Reg prof_funcs[] = {
208 { "pause", profiler_pause },
209 { "resume", profiler_resume },
210 { "start", profiler_init },
211 { "stop", profiler_stop },
212 { NULL, NULL }
215 int luaopen_profiler(lua_State *L) {
216 luaL_openlib(L, "profiler", prof_funcs, 0);
217 lua_pushliteral (L, "_COPYRIGHT");
218 lua_pushliteral (L, "Copyright (C) 2003-2007 Kepler Project");
219 lua_settable (L, -3);
220 lua_pushliteral (L, "_DESCRIPTION");
221 lua_pushliteral (L, "LuaProfiler is a time profiler designed to help finding bottlenecks in your Lua program.");
222 lua_settable (L, -3);
223 lua_pushliteral (L, "_NAME");
224 lua_pushliteral (L, "LuaProfiler");
225 lua_settable (L, -3);
226 lua_pushliteral (L, "_VERSION");
227 lua_pushliteral (L, "2.0.1");
228 lua_settable (L, -3);
229 return 1;