3 ** Copyright Kepler Project 2005.2007 (http://www.keplerproject.org/luaprofiler)
4 ** $Id: core_profiler.c,v 1.9 2008/05/19 18:36:23 mascarenhas Exp $
7 /*****************************************************************************
9 Lua version independent profiler interface.
10 Responsible for handling the "enter function" and "leave function" events
11 and for writing the log file.
13 Design (using the Lua callhook mechanism) :
14 'lprofP_init_core_profiler' set up the profile service
15 'lprofP_callhookIN' called whenever Lua enters a function
16 'lprofP_callhookOUT' called whenever Lua leaves a function
17 *****************************************************************************/
19 /*****************************************************************************
20 The profiled program can be viewed as a graph with the following properties:
21 directed, multigraph, cyclic and connected. The log file generated by a
22 profiler section corresponds to a path on this graph.
23 There are several graphs for which this path fits on. Some times it is
24 easier to consider this path as being generated by a simpler graph without
25 properties like cyclic and multigraph.
26 The profiler log file can be viewed as a "reversed" depth-first search
27 (with the depth-first search number for each vertex) vertex listing of a graph
28 with the following properties: simple, acyclic, directed and connected, for
29 which each vertex appears as many times as needed to strip the cycles and
30 each vertex has an indegree of 1.
31 "reversed" depth-first search means that instead of being "printed" before
32 visiting the vertex's descendents (as done in a normal depth-first search),
33 the vertex is "printed" only after all his descendents have been processed (in
34 a depth-first search recursive algorithm).
35 *****************************************************************************/
42 #include "function_meter.h"
44 #include "core_profiler.h"
46 /* default log name (%s is used to place a random string) */
47 #define OUT_FILENAME "lprof_%s.out"
49 /* for faster execution (??) */
51 static lprofS_STACK_RECORD
*info
;
52 static float function_call_time
;
55 /* output a line to the log file, using 'printf()' syntax */
56 /* assume the timer is off */
57 static void output(const char *format
, ...) {
60 vfprintf(outf
, format
, ap
);
63 /* write now to avoid delays when the timer is on */
68 /* do not allow a string with '\n' and '|' (log file format reserved chars) */
69 /* - replace them by ' ' */
70 static void formats(char *s
) {
74 for (i
= strlen(s
); i
>=0; i
--) {
75 if ((s
[i
] == '|') || (s
[i
] == '\n'))
81 /* computes new stack and new timer */
82 void lprofP_callhookIN(lprofP_STATE
* S
, char *func_name
, char *file
, int linedefined
, int currentline
) {
84 lprofM_enter_function(S
, file
, func_name
, linedefined
, currentline
);
88 /* pauses all timers to write a log line and computes the new stack */
89 /* returns if there is another function in the stack */
90 int lprofP_callhookOUT(lprofP_STATE
* S
) {
92 if (S
->stack_level
== 0) {
98 /* 0: do not resume the parent function's timer yet... */
99 info
= lprofM_leave_function(S
, 0);
100 /* writing a log may take too long to be computed with the function's time ...*/
101 lprofM_pause_total_time(S
);
102 info
->local_time
+= function_call_time
;
103 info
->total_time
+= function_call_time
;
104 formats(info
->file_defined
);
105 formats(info
->function_name
);
106 output("%d\t%s\t%s\t%d\t%d\t%f\t%f\n", S
->stack_level
, info
->file_defined
,
108 info
->line_defined
, info
->current_line
,
109 info
->local_time
, info
->total_time
);
110 /* ... now it's ok to resume the timer */
111 if (S
->stack_level
!= 0) {
112 lprofM_resume_function(S
);
120 /* opens the log file */
121 /* returns true if the file could be opened */
122 lprofP_STATE
* lprofP_init_core_profiler(const char *_out_filename
, int isto_printheader
, float _function_call_time
) {
129 const char *out_filename
;
131 function_call_time
= _function_call_time
;
132 out_filename
= (_out_filename
) ? (_out_filename
):(OUT_FILENAME
);
134 /* the random string to build the logname is extracted */
135 /* from 'tmpnam()' (the '/tmp/' part is deleted) */
137 randstr
= tmpnam(NULL
);
138 for (s
= strtok(randstr
, "/\\"); s
; s
= strtok(NULL
, "/\\")) {
142 if(randstr
[strlen(randstr
)-1]=='.')
143 randstr
[strlen(randstr
)-1]='\0';
145 sprintf(auxs
, out_filename
, randstr
);
146 outf
= fopen(auxs
, "a");
148 sprintf(auxs
,"lprof_XXXXXX");
149 outf
= fdopen(mkstemp(auxs
), "a");
155 if (isto_printheader
) {
156 output("stack_level\tfile_defined\tfunction_name\tline_defined\tcurrent_line\tlocal_time\ttotal_time\n");
159 /* initialize the 'function_meter' */
169 void lprofP_close_core_profiler(lprofP_STATE
* S
) {
170 if(outf
) fclose(outf
);
174 lprofP_STATE
* lprofP_create_profiler(float _function_call_time
) {
177 function_call_time
= _function_call_time
;
179 /* initialize the 'function_meter' */