1
+ /*
2
+ ** LuaProfiler
3
+ ** Copyright Kepler Project 2005.2007 (http://www.keplerproject.org/luaprofiler)
4
+ ** $Id: core_profiler.c,v 1.10 2009-01-29 12:39:28 jasonsantos Exp $
5
+ */
6
+
7
+ /* ****************************************************************************
8
+ core_profiler.c:
9
+ Lua version independent profiler interface.
10
+ Responsible for handling the "enter function" and "leave function" events
11
+ and for writing the log file.
12
+
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
+ *****************************************************************************/
18
+
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
+ *****************************************************************************/
36
+
37
+ #include < stdio.h>
38
+ #include < stdlib.h>
39
+ #include < string.h>
40
+ #include < stdarg.h>
41
+
42
+ #include " function_meter.h"
43
+
44
+ #include " core_profiler.h"
45
+
46
+ /* default log name (%s is used to place a random string) */
47
+ #define OUT_FILENAME " lprof_%s.out"
48
+
49
+ #define MAX_FUNCTION_NAME_LENGTH 20
50
+
51
+ /* for faster execution (??) */
52
+ static FILE *outf;
53
+ static lprofS_STACK_RECORD *info;
54
+ // static float function_call_time;
55
+
56
+
57
+ /* output a line to the log file, using 'printf()' syntax */
58
+ /* assume the timer is off */
59
+ static void output (const char *format, ...) {
60
+ va_list ap;
61
+ va_start (ap, format);
62
+ vfprintf (outf, format, ap);
63
+ va_end (ap);
64
+
65
+ /* write now to avoid delays when the timer is on */
66
+ fflush (outf);
67
+ }
68
+
69
+
70
+ /* do not allow a string with '\n' and '|' (log file format reserved chars) */
71
+ /* - replace them by ' ' */
72
+ static void formats (char *s) {
73
+ int i;
74
+ if (!s)
75
+ return ;
76
+ for (i = strlen (s); i >= 0 ; i--) {
77
+ if ((s[i] == ' |' ) || (s[i] == ' \n ' ))
78
+ s[i] = ' ' ;
79
+ }
80
+ }
81
+
82
+ int lprofP_output (lprofP_STATE* S){
83
+ if (S->stack_level == 0 ) {
84
+ return 0 ;
85
+ }
86
+
87
+ S->stack_level --;
88
+
89
+ info = &lprofS_pop (&(S->stack_top ));
90
+
91
+ char * name = info->function_name ;
92
+ if (strlen (name) > MAX_FUNCTION_NAME_LENGTH) {
93
+ name = (char *)malloc (MAX_FUNCTION_NAME_LENGTH + 10 );
94
+ name[0 ] = ' \" ' ;
95
+ strncpy (name + 1 , info->function_name , MAX_FUNCTION_NAME_LENGTH);
96
+ name[MAX_FUNCTION_NAME_LENGTH] = ' "' ;
97
+ name[MAX_FUNCTION_NAME_LENGTH + 1 ] = ' \0 ' ;
98
+ }
99
+ formats (name);
100
+
101
+ output (" %d\t %s\t %s\t %d\t %d\t %f\t %f\n " , info->stack_level , info->file_defined , name,
102
+ info->line_defined , info->current_line ,
103
+ info->local_time , info->total_time );
104
+
105
+ return 1 ;
106
+ }
107
+
108
+ /* computes new stack and new timer */
109
+ void lprofP_callhookIN (lprofP_STATE* S, char *func_name, char *file, int linedefined, int currentline) {
110
+ S->stack_level ++;
111
+ lprofM_enter_function (S, file, func_name, linedefined, currentline);
112
+ }
113
+
114
+ /* pauses all timers to write a log line and computes the new stack */
115
+ /* returns if there is another function in the stack */
116
+ int lprofP_callhookOUT (lprofP_STATE* S, lprofP_STATE* R) {
117
+ if (S->stack_level == 0 ) {
118
+ return 0 ;
119
+ }
120
+
121
+ S->stack_level --;
122
+
123
+ /* 0: do not resume the parent function's timer yet... */
124
+ info = lprofM_leave_function (S, 0 );
125
+
126
+ // for call stack level
127
+ R->stack_level ++;
128
+ info->stack_level = S->stack_level ;
129
+ lprofS_push (&(R->stack_top ), *info);
130
+
131
+ if (S->stack_level != 0 ) {
132
+ lprofM_resume_local_time (S);
133
+ }
134
+
135
+ // writing a log may take too long to be computed with the function's time ...
136
+ // lprofM_pause_total_time(S);
137
+
138
+ // if (info->local_time > 0.0000001 || info->total_time > 0.0000001)
139
+ // {
140
+ // char* source = info->file_defined;
141
+ // //if (source[0] != '@') {
142
+ // // source = "(string)";
143
+ // //}
144
+ // //else {
145
+ // // formats(source);
146
+ // //}
147
+ // char* name = info->function_name;
148
+
149
+ // if (strlen(name) > MAX_FUNCTION_NAME_LENGTH) {
150
+ // name = (char*)malloc(MAX_FUNCTION_NAME_LENGTH + 10);
151
+ // name[0] = '\"';
152
+ // strncpy(name + 1, info->function_name, MAX_FUNCTION_NAME_LENGTH);
153
+ // name[MAX_FUNCTION_NAME_LENGTH] = '"';
154
+ // name[MAX_FUNCTION_NAME_LENGTH + 1] = '\0';
155
+ // }
156
+ // formats(name);
157
+ // output("%d\t%s\t%s\t%d\t%d\t%f\t%f\n", S->stack_level, source, name,
158
+ // info->line_defined, info->current_line,
159
+ // info->local_time, info->total_time);
160
+ // }
161
+
162
+ // // ... now it's ok to resume the timer
163
+ // if (S->stack_level != 0) {
164
+ // lprofM_resume_function(S);
165
+ // }
166
+
167
+ return 1 ;
168
+
169
+ }
170
+
171
+
172
+ /* opens the log file */
173
+ /* returns true if the file could be opened */
174
+ lprofP_STATE* lprofP_init_core_profiler (const char *_out_filename, int isto_printheader, float _function_call_time) {
175
+ lprofP_STATE* S;
176
+ char auxs[256 ];
177
+ char *s;
178
+ char *randstr;
179
+ const char *out_filename;
180
+
181
+ // function_call_time = _function_call_time;
182
+ out_filename = (_out_filename) ? (_out_filename) : (OUT_FILENAME);
183
+
184
+ /* the random string to build the logname is extracted */
185
+ /* from 'tmpnam()' (the '/tmp/' part is deleted) */
186
+ randstr = tmpnam (NULL );
187
+ for (s = strtok (randstr, " /\\ " ); s; s = strtok (NULL , " /\\ " )) {
188
+ randstr = s;
189
+ }
190
+
191
+ if (randstr[strlen (randstr) - 1 ] == ' .' )
192
+ randstr[strlen (randstr) - 1 ] = ' \0 ' ;
193
+
194
+ sprintf (auxs, out_filename, randstr);
195
+ outf = fopen (auxs, " a" );
196
+ if (!outf) {
197
+ return 0 ;
198
+ }
199
+
200
+ if (isto_printheader) {
201
+ output (" stack_level\t file_defined\t function_name\t line_defined\t current_line\t local_time\t total_time\n " );
202
+ }
203
+
204
+ /* initialize the 'function_meter' */
205
+ S = lprofM_init ();
206
+ if (!S) {
207
+ fclose (outf);
208
+ return 0 ;
209
+ }
210
+
211
+ return S;
212
+ }
213
+
214
+ void lprofP_close_core_profiler (lprofP_STATE* S) {
215
+ if (outf) fclose (outf);
216
+ if (S) free (S);
217
+ }
0 commit comments