beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luaprofiler / core_profiler.c
blob8e94271038e855d0ccafcb8616d9f54b09855757
1 /*
2 ** LuaProfiler
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 $
5 */
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.
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 *****************************************************************************/
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <stdarg.h>
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 (??) */
50 static FILE *outf;
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, ...) {
58 va_list ap;
59 va_start(ap, format);
60 vfprintf(outf, format, ap);
61 va_end(ap);
63 /* write now to avoid delays when the timer is on */
64 fflush(outf);
68 /* do not allow a string with '\n' and '|' (log file format reserved chars) */
69 /* - replace them by ' ' */
70 static void formats(char *s) {
71 int i;
72 if (!s)
73 return;
74 for (i = strlen(s); i>=0; i--) {
75 if ((s[i] == '|') || (s[i] == '\n'))
76 s[i] = ' ';
81 /* computes new stack and new timer */
82 void lprofP_callhookIN(lprofP_STATE* S, char *func_name, char *file, int linedefined, int currentline) {
83 S->stack_level++;
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) {
93 return 0;
96 S->stack_level--;
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,
107 info->function_name,
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);
115 return 1;
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) {
123 lprofP_STATE* S;
124 char auxs[256];
125 #ifdef WIN32
126 char *s;
127 char *randstr;
128 #endif
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) */
136 #ifdef WIN32
137 randstr = tmpnam(NULL);
138 for (s = strtok(randstr, "/\\"); s; s = strtok(NULL, "/\\")) {
139 randstr = s;
142 if(randstr[strlen(randstr)-1]=='.')
143 randstr[strlen(randstr)-1]='\0';
145 sprintf(auxs, out_filename, randstr);
146 outf = fopen(auxs, "a");
147 #else
148 sprintf(auxs,"lprof_XXXXXX");
149 outf = fdopen(mkstemp(auxs), "a");
150 #endif
151 if (!outf) {
152 return 0;
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' */
160 S = lprofM_init();
161 if(!S) {
162 fclose(outf);
163 return 0;
166 return S;
169 void lprofP_close_core_profiler(lprofP_STATE* S) {
170 if(outf) fclose(outf);
171 if(S) free(S);
174 lprofP_STATE* lprofP_create_profiler(float _function_call_time) {
175 lprofP_STATE* S;
177 function_call_time = _function_call_time;
179 /* initialize the 'function_meter' */
180 S = lprofM_init();
181 if(!S) {
182 return 0;
185 return S;