Skip to content
Snippets Groups Projects
Commit ca5c4d6e authored by dg's avatar dg
Browse files

plop

git-svn-id: http://svn.net-core.org/repos/t-engine4@87 51575b47-30f0-44d4-a5cc-537603b46e54
parent f93e3bee
No related branches found
No related tags found
No related merge requests found
Showing
with 1127 additions and 25 deletions
......@@ -21,12 +21,17 @@ function _M:tick()
-- Give some energy to entities
if self.level then
for uid, e in pairs(self.level.entities) do
if e.energy and e.energy.value < self.energy_to_act then
e.energy.value = (e.energy.value or 0) + self.energy_per_tick * (e.energy.mod or 1)
end
if e.energy.value >= self.energy_to_act and e.act then
e:act(self)
local i, e
local arr = self.level.e_array
for i = 1, #arr do
e = arr[i]
if e then
if e.energy and e.energy.value < self.energy_to_act then
e.energy.value = (e.energy.value or 0) + self.energy_per_tick * (e.energy.mod or 1)
end
if e.energy.value >= self.energy_to_act and e.act then
e:act(self)
end
end
end
end
......
......@@ -19,6 +19,12 @@ function _M:tick()
if self.paused then
-- If we are paused do not get energy, but still process frames if needed
engine.Game.tick(self)
-- Run the level distancer
if self.level and self.level.distancer_co then
local ok, err = coroutine.resume(self.level.distancer_co)
if not ok and err then error(err) end
end
else
while not self.paused do
engine.GameEnergyBased.tick(self)
......
......@@ -7,7 +7,13 @@ module(..., package.seeall, class.make)
function _M:init(level, map)
self.level = level
self.map = map
self.e_array = {}
self.entities = {}
-- This stores the distance for each actors to each other actors
-- this is computed by either the "distancer" coroutine or manualy when needed if not available
self.e_distances = {}
self.distancer_co = self:createDistancer()
end
--- Adds an entity to the level
......@@ -15,12 +21,19 @@ end
function _M:addEntity(e)
if self.entities[e.uid] then error("Entity "..e.uid.." already present on the level") end
self.entities[e.uid] = e
table.insert(self.e_array, e)
end
--- Removes an entity from the level
function _M:removeEntity(e)
if not self.entities[e.uid] then error("Entity "..e.uid.." not present on the level") end
self.entities[e.uid] = nil
for i = 1, #self.e_array do
if self.e_array[i] == e then
table.remove(self.e_array, i)
break
end
end
-- Tells it to delete itself if needed
if e.deleteFromMap then e:deleteFromMap(self.map) end
end
......@@ -30,6 +43,15 @@ function _M:hasEntity(e)
return self.entities[e.uid]
end
--- Serialization
function _M:save()
return class.save(self, {
-- cant save a thread
distancer_co = true,
-- dont save the distances table either it will be recomputed on the fly
e_distances = true,
})
end
function _M:loaded()
-- Loading the game has defined new uids for entities, yet we hard referenced the old ones
-- So we fix it
......@@ -38,4 +60,52 @@ function _M:loaded()
nes[e.uid] = e
end
self.entities = nes
self.distancer_co = self:createDistancer()
end
--- Creates the distancer coroutine
-- The "distancer" is a coroutine that can be called everytime the game has nothing to do
-- it will compute distance and LOS between all actors and sort them by distance.<br/>
-- This will speed up AI code as it uses unused CPU cycles. The distancer
-- will be called by Game tick() method when there is not much to do (like when waiting
-- for player input)
function _M:createDistancer()
local co = coroutine.create(function()
-- Infinite coroutine
while true do
local arr = self.e_array
for i = 1, #arr do
local e = arr[i]
if e then
self:computeDistances(e)
-- print("distancer ran for", i, e.uid)
coroutine.yield()
end
end
end
end)
return co
end
local dist_sort = function(a, b) return a.dist < b.dist end
--- Compute distances to all other actors
function _M:computeDistances(e)
local arr = self.e_array
self.e_distances[e.uid] = {}
for j = 1, #arr do
local dst = arr[j]
if dst ~= e then
table.insert(self.e_distances[e.uid], {uid=dst.uid, dist=core.fov.distance(e.x, e.y, dst.x, dst.y)})
end
end
table.sort(self.e_distances[e.uid], dist_sort)
end
--- Get distances to all other actors
-- This eithers computes directly if not available or use data from the distancer coroutine
function _M:getDistances(e)
-- if not self.e_distances[e.uid] then self:computeDistances(e) end
return self.e_distances[e.uid]
end
......@@ -3,7 +3,8 @@
newAI("move_simple", function(self)
if self.ai_target.actor then
local l = line.new(self.x, self.y, self.ai_target.actor.x, self.ai_target.actor.y)
local act = __uids[self.ai_target.actor]
local l = line.new(self.x, self.y, act.x, act.y)
local lx, ly = l()
if lx and ly then
self:move(lx, ly)
......@@ -19,22 +20,24 @@ end)
newAI("target_simple", function(self)
-- Find new target every 10 +0speed turns or when no target exist
if self.ai_target.actor then return end
if self.got_target then return end
-- Find closer ennemy and target it
self.ai_target.actor = nil
for uid, act in pairs(game.level.entities) do
if act ~= self and self:reactionToward(act) < 0 then
-- if game.level.map:checkEntity(lx, ly, Map.TERRAIN, "block_sight") then return true end
-- if not self:canMove(lx, ly, true) then return end
-- If it is closer to the current target, target it
if not self.ai_target.actor then
self.ai_target.actor = act
elseif core.fov.distance(self.x, self.y, act.x, act.y) < core.fov.distance(self.x, self.y, self.ai_target.actor.x, self.ai_target.actor.y) then
self.ai_target.actor = act
end
-- Get list of actors ordered by distance
local arr = game.level:getDistances(self)
local act
if not arr or #arr == 0 then print("target abording, waiting on distancer") return end
for i = 1, #arr do
act = __uids[arr[i].uid]
-- find the closest ennemy
if self:reactionToward(act) < 0 then
self.ai_target.actor = act.uid
print("selected target", act.uid, "at dist", arr[i].dist)
break
end
end
self.got_target = true
--print("target=>", self.ai_target.actor)
end)
......
......@@ -28,3 +28,5 @@ game = false
local Menu = require("special.mainmenu.class.Game")
game = Menu.new()
game:run()
--profiler.start("/tmp/profiler.log")
......@@ -30,7 +30,7 @@ function _M:init(t)
self.ai_state = {}
self.ai_target = {}
-- Make the table with weak values, so that threat list does not prevent garbage collection
setmetatable(self.ai_target, {__mode='v'})
-- setmetatable(self.ai_target, {__mode='v'})
end
function _M:aiFindTarget()
......@@ -42,13 +42,41 @@ end
--- Main entry point for AIs
function _M:doAI()
if not self.ai then return end
-- if not self.ai then return end
-- If we have a target but it is dead (it was not yet garbage collected but it'll come)
-- we forget it
if self.ai_target.actor and self.ai_target.actor.dead then self.ai_target.actor = nil end
-- if self.ai_target.actor and self.ai_target.actor.dead then self.ai_target.actor = nil end
self:runAI(self.ai)
-- self:runAI(self.ai)
-- Find closer ennemy and target it
local tgt = nil
-- Get list of actors ordered by distance
local arr = game.level:getDistances(self)
local act
if not arr or #arr == 0 then
-- print("target abording, waiting on distancer")
return
end
for i = 1, #arr do
act = __uids[arr[i].uid]
-- find the closest ennemy
if self:reactionToward(act) < 0 then
tgt = act.uid
-- print("selected target", act.uid, "at dist", arr[i].dist)
break
end
end
if tgt then
local act = __uids[tgt]
local l = line.new(self.x, self.y, act.x, act.y)
local lx, ly = l()
if lx and ly then
self:move(lx, ly)
end
end
end
function _M:runAI(ai)
......
......@@ -17,7 +17,7 @@ return {
{
name = "baby dragon",
display = "d", color_r=128,
faction = "poorsods",
-- faction = "poorsods",
level_range = {1, 4}, exp_worth = 1,
autolevel = "caster",
ai = "simple",
......
......@@ -16,7 +16,7 @@ return {
},
actor = {
class = "engine.generator.actor.Random",
nb_npc = {100, 100},
nb_npc = {400, 400},
level_range = {5, 10},
adjust_level_to_player = {-2, 2},
},
......
......@@ -32,7 +32,7 @@ project "TEngine"
language "C"
targetname "t-engine"
files { "src/*.c", }
links { "physfs", "lua", "fov", "luasocket" }
links { "physfs", "lua", "fov", "luasocket", "luaprofiler" }
defines { "_DEFAULT_VIDEOMODE_FLAGS_='SDL_HWSURFACE|SDL_DOUBLEBUF'" }
defines { [[TENGINE_HOME_PATH='".t-engine"']] }
......@@ -120,3 +120,10 @@ project "fov"
targetname "fov"
files { "src/fov/*.c", }
project "luaprofiler"
kind "StaticLib"
language "C"
targetname "luaprofiler"
files { "src/luaprofiler/*.c", }
-- LuaProfiler
-- Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
-- $Id: summary.lua,v 1.5 2007/08/22 21:05:13 carregal Exp $
-- Function that reads one profile file
function ReadProfile(file)
local profile
-- Check if argument is a file handle or a filename
if io.type(file) == "file" then
profile = file
else
-- Open profile
profile = io.open(file)
end
-- Table for storing each profile's set of lines
line_buffer = {}
-- Get all profile lines
local i = 1
for line in profile:lines() do
line_buffer[i] = line
i = i + 1
end
-- Close file
profile:close()
return line_buffer
end
-- Function that creates the summary info
function CreateSummary(lines, summary)
local global_time = 0
-- Note: ignore first line
for i = 2, table.getn(lines) do
word = string.match(lines[i], "[^\t]+\t[^\t]+\t([^\t]+)")
local_time, total_time = string.match(lines[i], "[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t([^\t]+)\t([^\t]+)")
if not (local_time and total_time) then return global_time end
if summary[word] == nil then
summary[word] = {};
summary[word]["info"] = {}
summary[word]["info"]["calls"] = 1
summary[word]["info"]["total"] = local_time
summary[word]["info"]["func"] = word
else
summary[word]["info"]["calls"] = summary[word]["info"]["calls"] + 1
summary[word]["info"]["total"] = summary[word]["info"]["total"] + local_time;
end
global_time = global_time + local_time;
end
return global_time
end
-- Global time
global_t = 0
-- Summary table
profile_info = {}
-- Check file type
local verbose = false
local filename
if arg[1] == "-v" or arg[1] == "-V" then
verbose = true
filename = arg[2]
else
filename = arg[1]
end
if filename then
file = io.open(filename)
else
print("Usage")
print("-----")
print("lua summary.lua [-v] <profile_log>")
os.exit()
end
if not file then
print("File " .. filename .. " does not exist!")
os.exit()
end
firstline = file:read(11)
-- File is single profile
if firstline == "stack_level" then
-- Single profile
local lines = ReadProfile(file)
global_t = CreateSummary(lines, profile_info)
else
-- File is list of profiles
-- Reset position in file
file:seek("set")
-- Loop through profiles and create summary table
for line in file:lines() do
local profile_lines
-- Read current profile
profile_lines = ReadProfile(line)
-- Build a table with profile info
global_t = global_t + CreateSummary(profile_lines, profile_info)
end
file:close()
end
-- Sort table by total time
sorted = {}
for k, v in pairs(profile_info) do table.insert(sorted, v) end
table.sort(sorted, function (a, b) return tonumber(a["info"]["total"]) > tonumber(b["info"]["total"]) end)
-- Output summary
if verbose then
print("Node name\tCalls\tAverage per call\tTotal time\t%Time")
else
print("Node name\tTotal time")
end
for k, v in pairs(sorted) do
if v["info"]["func"] ~= "(null)" then
local average = v["info"]["total"] / v["info"]["calls"]
local percent = 100 * v["info"]["total"] / global_t
if verbose then
print(v["info"]["func"] .. "\t" .. v["info"]["calls"] .. "\t" .. average .. "\t" .. v["info"]["total"] .. "\t" .. percent)
else
print(v["info"]["func"] .. "\t" .. v["info"]["total"])
end
end
end
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: clocks.c,v 1.4 2007/08/22 19:23:53 carregal Exp $
*/
/*****************************************************************************
clocks.c:
Module to register the time (seconds) between two events
Design:
'lprofC_start_timer()' marks the first event
'lprofC_get_seconds()' gives you the seconds elapsed since the timer
was started
*****************************************************************************/
#include <stdio.h>
#include "clocks.h"
/*
Here you can choose what time function you are going to use.
These two defines ('TIMES' and 'CLOCK') correspond to the usage of
functions times() and clock() respectively.
Which one is better? It depends on your needs:
TIMES - returns the clock ticks since the system was up
(you may use it if you want to measure a system
delay for a task, like time spent to get input from keyboard)
CLOCK - returns the clock ticks dedicated to the program
(this should be prefered in a multithread system and is
the default choice)
note: I guess TIMES don't work for win32
*/
#ifdef TIMES
#include <sys/times.h>
static struct tms t;
#define times(t) times(t)
#else /* ifdef CLOCK */
#define times(t) clock()
#endif
void lprofC_start_timer(clock_t *time_marker) {
*time_marker = times(&t);
}
static clock_t get_clocks(clock_t time_marker) {
return times(&t) - time_marker;
}
float lprofC_get_seconds(clock_t time_marker) {
clock_t clocks;
clocks = get_clocks(time_marker);
return (float)clocks / (float)CLOCKS_PER_SEC;
}
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: clocks.h,v 1.4 2007/08/22 19:23:53 carregal Exp $
*/
/*****************************************************************************
clocks.h:
Module to register the time (seconds) between two events
Design:
'lprofC_start_timer()' marks the first event
'lprofC_get_seconds()' gives you the seconds elapsed since the timer
was started
*****************************************************************************/
#include <time.h>
void lprofC_start_timer(clock_t *time_marker);
float lprofC_get_seconds(clock_t time_marker);
/*
** LuaProfiler
** Copyright Kepler Project 2005.2007 (http://www.keplerproject.org/luaprofiler)
** $Id: core_profiler.c,v 1.9 2008/05/19 18:36:23 mascarenhas Exp $
*/
/*****************************************************************************
core_profiler.c:
Lua version independent profiler interface.
Responsible for handling the "enter function" and "leave function" events
and for writing the log file.
Design (using the Lua callhook mechanism) :
'lprofP_init_core_profiler' set up the profile service
'lprofP_callhookIN' called whenever Lua enters a function
'lprofP_callhookOUT' called whenever Lua leaves a function
*****************************************************************************/
/*****************************************************************************
The profiled program can be viewed as a graph with the following properties:
directed, multigraph, cyclic and connected. The log file generated by a
profiler section corresponds to a path on this graph.
There are several graphs for which this path fits on. Some times it is
easier to consider this path as being generated by a simpler graph without
properties like cyclic and multigraph.
The profiler log file can be viewed as a "reversed" depth-first search
(with the depth-first search number for each vertex) vertex listing of a graph
with the following properties: simple, acyclic, directed and connected, for
which each vertex appears as many times as needed to strip the cycles and
each vertex has an indegree of 1.
"reversed" depth-first search means that instead of being "printed" before
visiting the vertex's descendents (as done in a normal depth-first search),
the vertex is "printed" only after all his descendents have been processed (in
a depth-first search recursive algorithm).
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "function_meter.h"
#include "core_profiler.h"
/* default log name (%s is used to place a random string) */
#define OUT_FILENAME "lprof_%s.out"
/* for faster execution (??) */
static FILE *outf;
static lprofS_STACK_RECORD *info;
static float function_call_time;
/* output a line to the log file, using 'printf()' syntax */
/* assume the timer is off */
static void output(const char *format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(outf, format, ap);
va_end(ap);
/* write now to avoid delays when the timer is on */
fflush(outf);
}
/* do not allow a string with '\n' and '|' (log file format reserved chars) */
/* - replace them by ' ' */
static void formats(char *s) {
int i;
if (!s)
return;
for (i = strlen(s); i>=0; i--) {
if ((s[i] == '|') || (s[i] == '\n'))
s[i] = ' ';
}
}
/* computes new stack and new timer */
void lprofP_callhookIN(lprofP_STATE* S, char *func_name, char *file, int linedefined, int currentline) {
S->stack_level++;
lprofM_enter_function(S, file, func_name, linedefined, currentline);
}
/* pauses all timers to write a log line and computes the new stack */
/* returns if there is another function in the stack */
int lprofP_callhookOUT(lprofP_STATE* S) {
if (S->stack_level == 0) {
return 0;
}
S->stack_level--;
/* 0: do not resume the parent function's timer yet... */
info = lprofM_leave_function(S, 0);
/* writing a log may take too long to be computed with the function's time ...*/
lprofM_pause_total_time(S);
info->local_time += function_call_time;
info->total_time += function_call_time;
formats(info->file_defined);
formats(info->function_name);
output("%d\t%s\t%s\t%d\t%d\t%f\t%f\n", S->stack_level, info->file_defined,
info->function_name,
info->line_defined, info->current_line,
info->local_time, info->total_time);
/* ... now it's ok to resume the timer */
if (S->stack_level != 0) {
lprofM_resume_function(S);
}
return 1;
}
/* opens the log file */
/* returns true if the file could be opened */
lprofP_STATE* lprofP_init_core_profiler(const char *_out_filename, int isto_printheader, float _function_call_time) {
lprofP_STATE* S;
char auxs[256];
char *s;
char *randstr;
const char *out_filename;
function_call_time = _function_call_time;
out_filename = (_out_filename) ? (_out_filename):(OUT_FILENAME);
/* the random string to build the logname is extracted */
/* from 'tmpnam()' (the '/tmp/' part is deleted) */
randstr = tmpnam(NULL);
for (s = strtok(randstr, "/\\"); s; s = strtok(NULL, "/\\")) {
randstr = s;
}
if(randstr[strlen(randstr)-1]=='.')
randstr[strlen(randstr)-1]='\0';
sprintf(auxs, out_filename, randstr);
outf = fopen(auxs, "a");
if (!outf) {
return 0;
}
if (isto_printheader) {
output("stack_level\tfile_defined\tfunction_name\tline_defined\tcurrent_line\tlocal_time\ttotal_time\n");
}
/* initialize the 'function_meter' */
S = lprofM_init();
if(!S) {
fclose(outf);
return 0;
}
return S;
}
void lprofP_close_core_profiler(lprofP_STATE* S) {
if(outf) fclose(outf);
if(S) free(S);
}
lprofP_STATE* lprofP_create_profiler(float _function_call_time) {
lprofP_STATE* S;
function_call_time = _function_call_time;
/* initialize the 'function_meter' */
S = lprofM_init();
if(!S) {
return 0;
}
return S;
}
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: core_profiler.h,v 1.6 2007/08/22 19:23:53 carregal Exp $
*/
/*****************************************************************************
core_profiler.h:
Lua version independent profiler interface.
Responsible for handling the "enter function" and "leave function" events
and for writing the log file.
Design (using the Lua callhook mechanism) :
'lprofP_init_core_profiler' set up the profile service
'lprofP_callhookIN' called whenever Lua enters a function
'lprofP_callhookOUT' called whenever Lua leaves a function
*****************************************************************************/
#include "stack.h"
/* computes new stack and new timer */
void lprofP_callhookIN(lprofP_STATE* S, char *func_name, char *file, int linedefined, int currentline);
/* pauses all timers to write a log line and computes the new stack */
/* returns if there is another function in the stack */
int lprofP_callhookOUT(lprofP_STATE* S);
/* opens the log file */
/* returns true if the file could be opened */
lprofP_STATE* lprofP_init_core_profiler(const char *_out_filename, int isto_printheader, float _function_call_time);
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: function_meter.c,v 1.9 2008/05/19 18:36:23 mascarenhas Exp $
*/
/*****************************************************************************
function_meter.c:
Module to compute the times for functions (local times and total times)
Design:
'lprofM_init' set up the function times meter service
'lprofM_enter_function' called when the function stack increases one level
'lprofM_leave_function' called when the function stack decreases one level
'lprofM_resume_function' called when the profiler is returning from a time
consuming task
'lprofM_resume_total_time' idem
'lprofM_resume_local_time' called when a child function returns the execution
to it's caller (current function)
'lprofM_pause_function' called when the profiler need to do things that
may take too long (writing a log, for example)
'lprofM_pause_total_time' idem
'lprofM_pause_local_time' called when the current function has called
another one or when the function terminates
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "clocks.h"
/* #include "stack.h" is done by function_meter.h */
#include "function_meter.h"
#ifdef DEBUG
#include <stdlib.h>
#define ASSERT(e, msg) if (!e) { \
fprintf(stdout, \
"function_meter.c: assertion failed: %s\n", \
msg); \
exit(1); }
#else
#define ASSERT(e, msg)
#endif
/* structures to receive stack elements, declared globals */
/* in the hope they will perform faster */
static lprofS_STACK_RECORD newf; /* used in 'enter_function' */
static lprofS_STACK_RECORD leave_ret; /* used in 'leave_function' */
/* sum the seconds based on the time marker */
static void compute_local_time(lprofS_STACK_RECORD *e) {
ASSERT(e, "local time null");
e->local_time += lprofC_get_seconds(e->time_marker_function_local_time);
}
/* sum the seconds based on the time marker */
static void compute_total_time(lprofS_STACK_RECORD *e) {
ASSERT(e, "total time null");
e->total_time += lprofC_get_seconds(e->time_marker_function_total_time);
}
/* compute the local time for the current function */
void lprofM_pause_local_time(lprofP_STATE* S) {
compute_local_time(S->stack_top);
}
/* pause the total timer for all the functions that are in the stack */
void lprofM_pause_total_time(lprofP_STATE* S) {
lprofS_STACK aux;
ASSERT(S->stack_top, "pause_total_time: stack_top null");
/* auxiliary stack */
aux = S->stack_top;
/* pause */
while (aux) {
compute_total_time(aux);
aux = aux->next;
}
}
/* pause the local and total timers for all functions in the stack */
void lprofM_pause_function(lprofP_STATE* S) {
ASSERT(S->stack_top, "pause_function: stack_top null");
lprofM_pause_local_time(S);
lprofM_pause_total_time(S);
}
/* resume the local timer for the current function */
void lprofM_resume_local_time(lprofP_STATE* S) {
ASSERT(S->stack_top, "resume_local_time: stack_top null");
/* the function is in the top of the stack */
lprofC_start_timer(&(S->stack_top->time_marker_function_local_time));
}
/* resume the total timer for all the functions in the stack */
void lprofM_resume_total_time(lprofP_STATE* S) {
lprofS_STACK aux;
ASSERT(S->stack_top, "resume_total_time: stack_top null");
/* auxiliary stack */
aux = S->stack_top;
/* resume */
while (aux) {
lprofC_start_timer(&(aux->time_marker_function_total_time));
aux = aux->next;
}
}
/* resume the local and total timers for all functions in the stack */
void lprofM_resume_function(lprofP_STATE* S) {
ASSERT(S->stack_top, "resume_function: stack_top null");
lprofM_resume_local_time(S);
lprofM_resume_total_time(S);
}
/* the local time for the parent function is paused */
/* and the local and total time markers are started */
void lprofM_enter_function(lprofP_STATE* S, char *file_defined, char *fcn_name, long linedefined, long currentline) {
char* prev_name;
char* cur_name;
/* the flow has changed to another function: */
/* pause the parent's function timer timer */
if (S->stack_top) {
lprofM_pause_local_time(S);
prev_name = S->stack_top->function_name;
} else prev_name = "top level";
/* measure new function */
lprofC_start_timer(&(newf.time_marker_function_local_time));
lprofC_start_timer(&(newf.time_marker_function_total_time));
newf.file_defined = file_defined;
if(fcn_name != NULL) {
newf.function_name = fcn_name;
} else if(strcmp(file_defined, "=[C]") == 0) {
cur_name = (char*)malloc(sizeof(char)*(strlen("called from ")+strlen(prev_name)+1));
sprintf(cur_name, "called from %s", prev_name);
newf.function_name = cur_name;
} else {
cur_name = (char*)malloc(sizeof(char)*(strlen(file_defined)+12));
sprintf(cur_name, "%s:%li", file_defined, linedefined);
newf.function_name = cur_name;
}
newf.line_defined = linedefined;
newf.current_line = currentline;
newf.local_time = 0.0;
newf.total_time = 0.0;
lprofS_push(&(S->stack_top), newf);
}
/* computes times and remove the top of the stack */
/* 'isto_resume' specifies if the parent function's timer */
/* should be restarted automatically. If it's false, */
/* 'resume_local_time()' must be called when the resume */
/* should be done */
/* returns the funcinfo structure */
/* warning: use it before another call to this function, */
/* because the funcinfo will be overwritten */
lprofS_STACK_RECORD *lprofM_leave_function(lprofP_STATE* S, int isto_resume) {
ASSERT(S->stack_top, "leave_function: stack_top null");
leave_ret = lprofS_pop(&(S->stack_top));
compute_local_time(&leave_ret);
compute_total_time(&leave_ret);
/* resume the timer for the parent function ? */
if (isto_resume)
lprofM_resume_local_time(S);
return &leave_ret;
}
/* init stack */
lprofP_STATE* lprofM_init() {
lprofP_STATE *S;
S = (lprofP_STATE*)malloc(sizeof(lprofP_STATE));
if(S) {
S->stack_level = 0;
S->stack_top = NULL;
return S;
} else return NULL;
}
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: function_meter.h,v 1.5 2007/08/22 19:23:53 carregal Exp $
*/
/*****************************************************************************
function_meter.c:
Module to compute the times for functions (local times and total times)
Design:
'lprofM_init' set up the function times meter service
'lprofM_enter_function' called when the function stack increases one level
'lprofM_leave_function' called when the function stack decreases one level
'lprofM_resume_function' called when the profiler is returning from a time
consuming task
'lprofM_resume_total_time' idem
'lprofM_resume_local_time' called when a child function returns the execution
to it's caller (current function)
'lprofM_pause_function' called when the profiler need to do things that
may take too long (writing a log, for example)
'lprofM_pause_total_time' idem
'lprofM_pause_local_time' called when the current function has called
another one or when the function terminates
*****************************************************************************/
#include "stack.h"
/* compute the local time for the current function */
void lprofM_pause_local_time(lprofP_STATE* S);
/* pause the total timer for all the functions that are in the stack */
void lprofM_pause_total_time(lprofP_STATE* S);
/* pause the local and total timers for all functions in the stack */
void lprofM_pause_function(lprofP_STATE* S);
/* resume the local timer for the current function */
void lprofM_resume_local_time(lprofP_STATE* S);
/* resume the total timer for all the functions in the stack */
void lprofM_resume_total_time(lprofP_STATE* S);
/* resume the local and total timers for all functions in the stack */
void lprofM_resume_function(lprofP_STATE* S);
/* the local time for the parent function is paused */
/* and the local and total time markers are started */
void lprofM_enter_function(lprofP_STATE* S, char *file_defined, char *fcn_name, long linedefined, long currentline);
/* computes times and remove the top of the stack */
/* 'isto_resume' specifies if the parent function's timer */
/* should be restarted automatically. If it's false, */
/* 'resume_local_time()' must be called when the resume */
/* should be done */
/* returns the funcinfo structure */
/* warning: use it before another call to this function, */
/* because the funcinfo will be overwritten */
lprofS_STACK_RECORD *lprofM_leave_function(lprofP_STATE* S, int isto_resume);
/* init stack */
lprofP_STATE* lprofM_init();
/*
** 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;
}
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: luaprofiler.h,v 1.4 2007/08/22 19:23:53 carregal Exp $
*/
/*****************************************************************************
luaprofiler.h:
Must be included by your main module, in order to profile Lua programs
*****************************************************************************/
void init_profiler(void *);
EXPORTS
luaopen_profiler
/*
** LuaProfiler
** Copyright Kepler Project 2005-2007 (http://www.keplerproject.org/luaprofiler)
** $Id: stack.c,v 1.4 2007/08/22 19:23:53 carregal Exp $
*/
/*****************************************************************************
stack.c:
Simple stack manipulation
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
void lprofS_push(lprofS_STACK *p, lprofS_STACK_RECORD r) {
lprofS_STACK q;
q=(lprofS_STACK)malloc(sizeof(lprofS_STACK_RECORD));
*q=r;
q->next=*p;
*p=q;
}
lprofS_STACK_RECORD lprofS_pop(lprofS_STACK *p) {
lprofS_STACK_RECORD r;
lprofS_STACK q;
r=**p;
q=*p;
*p=(*p)->next;
free(q);
return r;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment