1 /* Why the hell is XEmacs so fucking slow?
2 Copyright (C) 1996 Ben Wing.
3 Copyright (C) 1998 Free Software Foundation, Inc.
5 This file is part of XEmacs.
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
25 #include "backtrace.h"
30 #include "syssignal.h"
33 /* We implement our own profiling scheme so that we can determine
34 things like which Lisp functions are occupying the most time. Any
35 standard OS-provided profiling works on C functions, which is
38 The basic idea is simple. We set a profiling timer using setitimer
39 (ITIMER_PROF), which generates a SIGPROF every so often. (This
40 runs not in real time but rather when the process is executing or
41 the system is running on behalf of the process.) When the signal
42 goes off, we see what we're in, and add 1 to the count associated
45 It would be nice to use the Lisp allocation mechanism etc. to keep
46 track of the profiling information, but we can't because that's not
47 safe, and trying to make it safe would be much more work than it's
51 Jan 1998: In addition to this, I have added code to remember call
52 counts of Lisp funcalls. The profile_increase_call_count()
53 function is called from Ffuncall(), and serves to add data to
54 Vcall_count_profile_table. This mechanism is much simpler and
55 independent of the SIGPROF-driven one. It uses the Lisp allocation
56 mechanism normally, since it is not called from a handler. It may
57 even be useful to provide a way to turn on only one profiling
58 mechanism, but I haven't done so yet. --hniksic */
60 static struct hash_table *big_profile_table;
61 Lisp_Object Vcall_count_profile_table;
63 int default_profiling_interval;
67 /* The normal flag in_display is used as a critical-section flag
68 and is not set the whole time we're in redisplay. */
69 int profiling_redisplay_flag;
71 static Lisp_Object QSin_redisplay;
72 static Lisp_Object QSin_garbage_collection;
73 static Lisp_Object QSprocessing_events_at_top_level;
74 static Lisp_Object QSunknown;
76 /* We use inside_profiling to prevent the handler from writing to
77 the table while another routine is operating on it. We also set
78 inside_profiling in case the timeout between signal calls is short
79 enough to catch us while we're already in there. */
80 static volatile int inside_profiling;
82 /* Increase the value of OBJ in Vcall_count_profile_table hash table.
83 If the hash table is nil, create it first. */
85 profile_increase_call_count (Lisp_Object obj)
89 if (NILP (Vcall_count_profile_table))
90 Vcall_count_profile_table =
91 make_lisp_hash_table (100, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
93 count = Fgethash (obj, Vcall_count_profile_table, Qzero);
96 Fputhash (obj, make_int (1 + XINT (count)), Vcall_count_profile_table);
100 sigprof_handler (int signo)
102 /* Don't do anything if we are shutting down, or are doing a maphash
103 or clrhash on the table. */
104 if (!inside_profiling && !preparing_for_armageddon)
108 /* If something below causes an error to be signaled, we'll
109 not correctly reset this flag. But we'll be in worse shape
110 than that anyways, since we'll longjmp back to the last
112 inside_profiling = 1;
114 if (profiling_redisplay_flag)
115 fun = QSin_redisplay;
116 else if (gc_in_progress)
117 fun = QSin_garbage_collection;
118 else if (backtrace_list)
120 fun = *backtrace_list->function;
123 && !COMPILED_FUNCTIONP (fun)
129 fun = QSprocessing_events_at_top_level;
132 /* #### see comment about memory allocation in start-profiling.
133 Allocating memory in a signal handler is BAD BAD BAD.
134 If you are using the non-mmap rel-alloc code, you might
135 lose because of this. Even worse, if the memory allocation
136 fails, the `error' generated whacks everything hard. */
140 if (gethash (LISP_TO_VOID (fun), big_profile_table, &vval))
145 vval = (CONST void *) count;
146 puthash (LISP_TO_VOID (fun), (void *) vval, big_profile_table);
149 inside_profiling = 0;
153 DEFUN ("start-profiling", Fstart_profiling, 0, 1, 0, /*
154 Start profiling, with profile queries every MICROSECS.
155 If MICROSECS is nil or omitted, the value of `default-profiling-interval'
158 You can retrieve the recorded profiling info using `get-profiling-info'.
160 Starting and stopping profiling does not clear the currently recorded
161 info. Thus you can start and stop as many times as you want and everything
162 will be properly accumulated.
166 /* This function can GC */
168 struct itimerval foo;
170 /* #### The hash code can safely be called from a signal handler
171 except when it has to grow the hash table. In this case, it calls
172 realloc(), which is not (in general) re-entrant. We'll just be
173 sleazy and make the table large enough that it (hopefully) won't
174 need to be realloc()ed. */
175 if (!big_profile_table)
176 big_profile_table = make_hash_table (10000);
178 if (NILP (microsecs))
179 msecs = default_profiling_interval;
182 CHECK_NATNUM (microsecs);
183 msecs = XINT (microsecs);
188 signal (SIGPROF, sigprof_handler);
189 foo.it_value.tv_sec = 0;
190 foo.it_value.tv_usec = msecs;
191 EMACS_NORMALIZE_TIME (foo.it_value);
192 foo.it_interval = foo.it_value;
193 profiling_active = 1;
194 inside_profiling = 0;
195 setitimer (ITIMER_PROF, &foo, 0);
199 DEFUN ("stop-profiling", Fstop_profiling, 0, 0, 0, /*
204 /* This function does not GC */
205 struct itimerval foo;
207 foo.it_value.tv_sec = 0;
208 foo.it_value.tv_usec = 0;
209 foo.it_interval = foo.it_value;
210 setitimer (ITIMER_PROF, &foo, 0);
211 profiling_active = 0;
212 signal (SIGPROF, fatal_error_signal);
217 profile_lock_unwind (Lisp_Object ignore)
219 inside_profiling = 0;
223 struct get_profiling_info_closure
229 get_profiling_info_maphash (CONST void *void_key,
233 /* This function does not GC */
235 struct get_profiling_info_closure *closure
236 = (struct get_profiling_info_closure *) void_closure;
239 CVOID_TO_LISP (key, void_key);
240 val = (EMACS_INT) void_val;
242 closure->accum = Fcons (Fcons (key, make_int (val)), closure->accum);
246 DEFUN ("get-profiling-info", Fget_profiling_info, 0, 0, 0, /*
247 Return the profiling info as an alist.
251 /* This function does not GC */
252 struct get_profiling_info_closure closure;
254 closure.accum = Qnil;
255 if (big_profile_table)
257 int count = specpdl_depth ();
258 record_unwind_protect (profile_lock_unwind, Qnil);
259 inside_profiling = 1;
260 maphash (get_profiling_info_maphash, big_profile_table, &closure);
261 unbind_to (count, Qnil);
263 return closure.accum;
267 mark_profiling_info_maphash (CONST void *void_key,
273 CVOID_TO_LISP (key, void_key);
279 mark_profiling_info (void)
281 /* This function does not GC */
282 if (big_profile_table)
284 inside_profiling = 1;
285 maphash (mark_profiling_info_maphash, big_profile_table, 0);
286 inside_profiling = 0;
290 DEFUN ("clear-profiling-info", Fclear_profiling_info, 0, 0, "", /*
291 Clear out the recorded profiling info.
295 /* This function does not GC */
296 if (big_profile_table)
298 inside_profiling = 1;
299 clrhash (big_profile_table);
300 inside_profiling = 0;
302 if (!NILP (Vcall_count_profile_table))
303 Fclrhash (Vcall_count_profile_table);
307 DEFUN ("profiling-active-p", Fprofiling_active_p, 0, 0, 0, /*
308 Return non-nil if profiling information is currently being recorded.
312 return profiling_active ? Qt : Qnil;
316 syms_of_profile (void)
318 DEFSUBR (Fstart_profiling);
319 DEFSUBR (Fstop_profiling);
320 DEFSUBR (Fget_profiling_info);
321 DEFSUBR (Fclear_profiling_info);
322 DEFSUBR (Fprofiling_active_p);
326 vars_of_profile (void)
328 DEFVAR_INT ("default-profiling-interval", &default_profiling_interval /*
329 Default CPU time in microseconds between profiling sampling.
330 Used when the argument to `start-profiling' is nil or omitted.
331 Note that the time in question is CPU time (when the program is executing
332 or the kernel is executing on behalf of the program) and not real time.
334 default_profiling_interval = 1000;
336 DEFVAR_LISP ("call-count-profile-table", &Vcall_count_profile_table /*
337 The table where call-count information is stored by the profiling primitives.
338 This is a hash table whose keys are funcallable objects, and whose
339 values are their call counts (integers).
341 Vcall_count_profile_table = Qnil;
343 inside_profiling = 0;
345 QSin_redisplay = build_string ("(in redisplay)");
346 staticpro (&QSin_redisplay);
347 QSin_garbage_collection = build_string ("(in garbage collection)");
348 staticpro (&QSin_garbage_collection);
349 QSunknown = build_string ("(unknown)");
350 staticpro (&QSunknown);
351 QSprocessing_events_at_top_level =
352 build_string ("(processing events at top level)");
353 staticpro (&QSprocessing_events_at_top_level);