comparison src/profile.c @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents c0965ff3b039
children 9f59509498e1
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
61 Lisp_Object QSin_redisplay; 61 Lisp_Object QSin_redisplay;
62 Lisp_Object QSin_garbage_collection; 62 Lisp_Object QSin_garbage_collection;
63 Lisp_Object QSprocessing_events_at_top_level; 63 Lisp_Object QSprocessing_events_at_top_level;
64 Lisp_Object QSunknown; 64 Lisp_Object QSunknown;
65 65
66 /* We use inside_profiling to prevent the handler from writing to
67 the table while another routine is operating on it. We also set
68 inside_profiling in case the timeout between signal calls is short
69 enough to catch us while we're already in there. */
70 static volatile int inside_profiling;
71
72 static SIGTYPE 66 static SIGTYPE
73 sigprof_handler (int signo) 67 sigprof_handler (int signo)
74 { 68 {
75 /* Don't do anything if we are shutting down, or are doing a maphash 69 Lisp_Object fun;
76 or clrhash on the table. */ 70
77 if (!inside_profiling && !preparing_for_armageddon) 71 if (profiling_redisplay_flag)
72 fun = QSin_redisplay;
73 else if (gc_in_progress)
74 fun = QSin_garbage_collection;
75 else if (backtrace_list)
78 { 76 {
79 Lisp_Object fun; 77 fun = *backtrace_list->function;
80 78
81 /* If something below causes an error to be signaled, we'll 79 XUNMARK (fun);
82 not correctly reset this flag. But we'll be in worse shape 80 if (!GC_SYMBOLP (fun) && !GC_COMPILED_FUNCTIONP (fun))
83 than that anyways, since we'll longjmp back to the last 81 fun = QSunknown;
84 condition case. */ 82 }
85 inside_profiling = 1; 83 else
86 84 fun = QSprocessing_events_at_top_level;
87 if (profiling_redisplay_flag) 85
88 fun = QSin_redisplay; 86 {
89 else if (gc_in_progress) 87 long count;
90 fun = QSin_garbage_collection; 88 CONST void *vval;
91 else if (backtrace_list)
92 {
93 fun = *backtrace_list->function;
94
95 /* #### dmoore - why do we need to unmark it, we aren't in GC. */
96 XUNMARK (fun);
97 if (!GC_SYMBOLP (fun) && !GC_COMPILED_FUNCTIONP (fun))
98 fun = QSunknown;
99 }
100 else
101 fun = QSprocessing_events_at_top_level;
102
103 {
104 /* #### see comment about memory allocation in start-profiling.
105 Allocating memory in a signal handler is BAD BAD BAD.
106 If you are using the non-mmap rel-alloc code, you might
107 lose because of this. Even worse, if the memory allocation
108 fails, the `error' generated whacks everything hard. */
109 long count;
110 CONST void *vval;
111 89
112 if (gethash (LISP_TO_VOID (fun), big_profile_table, &vval)) 90 if (gethash (LISP_TO_VOID (fun), big_profile_table, &vval))
113 count = (long) vval; 91 count = (long) vval;
114 else 92 else
115 count = 0; 93 count = 0;
116 count++; 94 count++;
117 vval = (CONST void *) count; 95 vval = (CONST void *) count;
118 puthash (LISP_TO_VOID (fun), (void *) vval, big_profile_table); 96 puthash (LISP_TO_VOID (fun), (void *) vval, big_profile_table);
119 } 97 }
120
121 inside_profiling = 0;
122 }
123 } 98 }
124 99
125 DEFUN ("start-profiling", Fstart_profiling, 0, 1, 0, /* 100 DEFUN ("start-profiling", Fstart_profiling, 0, 1, 0, /*
126 Start profiling, with profile queries every MICROSECS. 101 Start profiling, with profile queries every MICROSECS.
127 If MICROSECS is nil or omitted, the value of `default-profiling-interval' 102 If MICROSECS is nil or omitted, the value of `default-profiling-interval'
133 info. Thus you can start and stop as many times as you want and everything 108 info. Thus you can start and stop as many times as you want and everything
134 will be properly accumulated. 109 will be properly accumulated.
135 */ 110 */
136 (microsecs)) 111 (microsecs))
137 { 112 {
138 /* This function can GC */
139 int msecs; 113 int msecs;
140 struct itimerval foo; 114 struct itimerval foo;
141 115
142 /* #### The hash code can safely be called from a signal handler 116 /* #### The hash code can safely be called from a signal handler
143 except when it has to grow the hashtable. In this case, it calls 117 except when it has to grow the hashtable. In this case, it calls
160 foo.it_value.tv_sec = 0; 134 foo.it_value.tv_sec = 0;
161 foo.it_value.tv_usec = msecs; 135 foo.it_value.tv_usec = msecs;
162 EMACS_NORMALIZE_TIME (foo.it_value); 136 EMACS_NORMALIZE_TIME (foo.it_value);
163 foo.it_interval = foo.it_value; 137 foo.it_interval = foo.it_value;
164 profiling_active = 1; 138 profiling_active = 1;
165 inside_profiling = 0;
166 setitimer (ITIMER_PROF, &foo, 0); 139 setitimer (ITIMER_PROF, &foo, 0);
167 return Qnil; 140 return Qnil;
168 } 141 }
169 142
170 DEFUN ("stop-profiling", Fstop_profiling, 0, 0, 0, /* 143 DEFUN ("stop-profiling", Fstop_profiling, 0, 0, 0, /*
171 Stop profiling. 144 Stop profiling.
172 */ 145 */
173 ()) 146 ())
174 { 147 {
175 /* This function does not GC */
176 struct itimerval foo; 148 struct itimerval foo;
177 149
178 foo.it_value.tv_sec = 0; 150 foo.it_value.tv_sec = 0;
179 foo.it_value.tv_usec = 0; 151 foo.it_value.tv_usec = 0;
180 foo.it_interval = foo.it_value; 152 foo.it_interval = foo.it_value;
182 profiling_active = 0; 154 profiling_active = 0;
183 signal (SIGPROF, fatal_error_signal); 155 signal (SIGPROF, fatal_error_signal);
184 return Qnil; 156 return Qnil;
185 } 157 }
186 158
187 static Lisp_Object
188 profile_lock_unwind (Lisp_Object ignore)
189 {
190 inside_profiling = 0;
191 return Qnil;
192 }
193
194 struct get_profiling_info_closure 159 struct get_profiling_info_closure
195 { 160 {
196 Lisp_Object accum; 161 Lisp_Object accum;
197 }; 162 };
198 163
199 static void 164 static void
200 get_profiling_info_maphash (CONST void *void_key, 165 get_profiling_info_maphash (CONST void *void_key,
201 void *void_val, 166 void *void_val,
202 void *void_closure) 167 void *void_closure)
203 { 168 {
204 /* This function does not GC */ 169 /* This function can GC */
205 Lisp_Object key; 170 Lisp_Object key;
206 struct get_profiling_info_closure *closure = void_closure; 171 struct get_profiling_info_closure *closure = void_closure;
207 EMACS_INT val; 172 EMACS_INT val;
208 173
209 CVOID_TO_LISP (key, void_key); 174 CVOID_TO_LISP (key, void_key);
216 DEFUN ("get-profiling-info", Fget_profiling_info, 0, 0, 0, /* 181 DEFUN ("get-profiling-info", Fget_profiling_info, 0, 0, 0, /*
217 Return the profiling info as an alist. 182 Return the profiling info as an alist.
218 */ 183 */
219 ()) 184 ())
220 { 185 {
221 /* This function does not GC */
222 struct get_profiling_info_closure closure; 186 struct get_profiling_info_closure closure;
223 187
224 closure.accum = Qnil; 188 closure.accum = Qnil;
225 if (big_profile_table) 189 if (big_profile_table)
226 { 190 maphash (get_profiling_info_maphash, big_profile_table, &closure);
227 int count = specpdl_depth ();
228 record_unwind_protect (profile_lock_unwind, Qnil);
229 inside_profiling = 1;
230 maphash (get_profiling_info_maphash, big_profile_table, &closure);
231 unbind_to (count, Qnil);
232 }
233 return closure.accum; 191 return closure.accum;
234 } 192 }
235 193
236 struct mark_profiling_info_closure 194 struct mark_profiling_info_closure
237 { 195 {
241 static void 199 static void
242 mark_profiling_info_maphash (CONST void *void_key, 200 mark_profiling_info_maphash (CONST void *void_key,
243 void *void_val, 201 void *void_val,
244 void *void_closure) 202 void *void_closure)
245 { 203 {
204 /* This function can GC */
246 Lisp_Object key; 205 Lisp_Object key;
247 struct mark_profiling_info_closure *closure = void_closure; 206 struct mark_profiling_info_closure *closure = void_closure;
248 207
249 CVOID_TO_LISP (key, void_key); 208 CVOID_TO_LISP (key, void_key);
250 (closure->markfun) (key); 209 (closure->markfun) (key);
251 } 210 }
252 211
253 void 212 void
254 mark_profiling_info (void (*markfun) (Lisp_Object)) 213 mark_profiling_info (void (*markfun) (Lisp_Object))
255 { 214 {
256 /* This function does not GC (if markfun doesn't) */
257 struct mark_profiling_info_closure closure; 215 struct mark_profiling_info_closure closure;
258 216
259 closure.markfun = markfun; 217 closure.markfun = markfun;
260 if (big_profile_table) 218 if (big_profile_table)
261 { 219 maphash (mark_profiling_info_maphash, big_profile_table, &closure);
262 inside_profiling = 1;
263 maphash (mark_profiling_info_maphash, big_profile_table, &closure);
264 inside_profiling = 0;
265 }
266 } 220 }
267 221
268 DEFUN ("clear-profiling-info", Fclear_profiling_info, 0, 0, 0, /* 222 DEFUN ("clear-profiling-info", Fclear_profiling_info, 0, 0, 0, /*
269 Clear out the recorded profiling info. 223 Clear out the recorded profiling info.
270 */ 224 */
271 ()) 225 ())
272 { 226 {
273 /* This function does not GC */
274 if (big_profile_table) 227 if (big_profile_table)
275 { 228 clrhash (big_profile_table);
276 inside_profiling = 1;
277 clrhash (big_profile_table);
278 inside_profiling = 0;
279 }
280 return Qnil; 229 return Qnil;
281 } 230 }
282 231
283 DEFUN ("profiling-active-p", Fprofiling_active_p, 0, 0, 0, /* 232 DEFUN ("profiling-active-p", Fprofiling_active_p, 0, 0, 0, /*
284 Return non-nil if profiling information is currently being recorded. 233 Return non-nil if profiling information is currently being recorded.
306 Used when the argument to `start-profiling' is nil or omitted. 255 Used when the argument to `start-profiling' is nil or omitted.
307 Note that the time in question is CPU time (when the program is executing 256 Note that the time in question is CPU time (when the program is executing
308 or the kernel is executing on behalf of the program) and not real time. 257 or the kernel is executing on behalf of the program) and not real time.
309 */ ); 258 */ );
310 default_profiling_interval = 1000; 259 default_profiling_interval = 1000;
311
312 inside_profiling = 0;
313 260
314 QSin_redisplay = build_string ("(in redisplay)"); 261 QSin_redisplay = build_string ("(in redisplay)");
315 staticpro (&QSin_redisplay); 262 staticpro (&QSin_redisplay);
316 QSin_garbage_collection = build_string ("(in garbage collection)"); 263 QSin_garbage_collection = build_string ("(in garbage collection)");
317 staticpro (&QSin_garbage_collection); 264 staticpro (&QSin_garbage_collection);