aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTomohiro Matsuyama2012-08-22 15:38:59 +0900
committerTomohiro Matsuyama2012-08-22 15:38:59 +0900
commitc2d7786e1272a10c62de7bd1c2d8810e510b3ab1 (patch)
tree4dc621ccee2315e7c2af7fcb1e153175b7e7519b /src
parent37219830c704441dad626b2e555e27a7f4676d87 (diff)
downloademacs-c2d7786e1272a10c62de7bd1c2d8810e510b3ab1.tar.gz
emacs-c2d7786e1272a10c62de7bd1c2d8810e510b3ab1.zip
Add emacs native profiler.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in1
-rw-r--r--src/alloc.c10
-rw-r--r--src/emacs.c2
-rw-r--r--src/eval.c16
-rw-r--r--src/fns.c7
-rw-r--r--src/lisp.h29
-rw-r--r--src/profiler.c965
7 files changed, 1010 insertions, 20 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 1d89af31401..02b702bc055 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -338,6 +338,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
338 process.o gnutls.o callproc.o \ 338 process.o gnutls.o callproc.o \
339 region-cache.o sound.o atimer.o \ 339 region-cache.o sound.o atimer.o \
340 doprnt.o intervals.o textprop.o composite.o xml.o \ 340 doprnt.o intervals.o textprop.o composite.o xml.o \
341 profiler.o \
341 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) 342 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
342obj = $(base_obj) $(NS_OBJC_OBJ) 343obj = $(base_obj) $(NS_OBJC_OBJ)
343 344
diff --git a/src/alloc.c b/src/alloc.c
index f0da9416ece..3a4a8de90f5 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -727,6 +727,7 @@ xmalloc (size_t size)
727 727
728 if (!val && size) 728 if (!val && size)
729 memory_full (size); 729 memory_full (size);
730 MALLOC_PROBE (size);
730 return val; 731 return val;
731} 732}
732 733
@@ -744,6 +745,7 @@ xzalloc (size_t size)
744 if (!val && size) 745 if (!val && size)
745 memory_full (size); 746 memory_full (size);
746 memset (val, 0, size); 747 memset (val, 0, size);
748 MALLOC_PROBE (size);
747 return val; 749 return val;
748} 750}
749 751
@@ -765,6 +767,7 @@ xrealloc (void *block, size_t size)
765 767
766 if (!val && size) 768 if (!val && size)
767 memory_full (size); 769 memory_full (size);
770 MALLOC_PROBE (size);
768 return val; 771 return val;
769} 772}
770 773
@@ -955,6 +958,7 @@ lisp_malloc (size_t nbytes, enum mem_type type)
955 MALLOC_UNBLOCK_INPUT; 958 MALLOC_UNBLOCK_INPUT;
956 if (!val && nbytes) 959 if (!val && nbytes)
957 memory_full (nbytes); 960 memory_full (nbytes);
961 MALLOC_PROBE (nbytes);
958 return val; 962 return val;
959} 963}
960 964
@@ -1160,6 +1164,8 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
1160 1164
1161 MALLOC_UNBLOCK_INPUT; 1165 MALLOC_UNBLOCK_INPUT;
1162 1166
1167 MALLOC_PROBE (nbytes);
1168
1163 eassert (0 == ((uintptr_t) val) % BLOCK_ALIGN); 1169 eassert (0 == ((uintptr_t) val) % BLOCK_ALIGN);
1164 return val; 1170 return val;
1165} 1171}
@@ -1340,6 +1346,8 @@ emacs_blocked_malloc (size_t size, const void *ptr)
1340 __malloc_hook = emacs_blocked_malloc; 1346 __malloc_hook = emacs_blocked_malloc;
1341 UNBLOCK_INPUT_ALLOC; 1347 UNBLOCK_INPUT_ALLOC;
1342 1348
1349 MALLOC_PROBE (size);
1350
1343 /* fprintf (stderr, "%p malloc\n", value); */ 1351 /* fprintf (stderr, "%p malloc\n", value); */
1344 return value; 1352 return value;
1345} 1353}
@@ -5510,6 +5518,8 @@ See Info node `(elisp)Garbage Collection'. */)
5510 mark_backtrace (); 5518 mark_backtrace ();
5511#endif 5519#endif
5512 5520
5521 mark_profiler ();
5522
5513#ifdef HAVE_WINDOW_SYSTEM 5523#ifdef HAVE_WINDOW_SYSTEM
5514 mark_fringe_data (); 5524 mark_fringe_data ();
5515#endif 5525#endif
diff --git a/src/emacs.c b/src/emacs.c
index 9e7efcabbf7..19d5f55c9c6 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1557,6 +1557,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1557 syms_of_ntterm (); 1557 syms_of_ntterm ();
1558#endif /* WINDOWSNT */ 1558#endif /* WINDOWSNT */
1559 1559
1560 syms_of_profiler ();
1561
1560 keys_of_casefiddle (); 1562 keys_of_casefiddle ();
1561 keys_of_cmds (); 1563 keys_of_cmds ();
1562 keys_of_buffer (); 1564 keys_of_buffer ();
diff --git a/src/eval.c b/src/eval.c
index c41e3f54d4d..b2e49364b52 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -32,17 +32,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
32#include "xterm.h" 32#include "xterm.h"
33#endif 33#endif
34 34
35struct backtrace 35struct backtrace *backtrace_list;
36{
37 struct backtrace *next;
38 Lisp_Object *function;
39 Lisp_Object *args; /* Points to vector of args. */
40 ptrdiff_t nargs; /* Length of vector. */
41 /* Nonzero means call value of debugger when done with this operation. */
42 unsigned int debug_on_exit : 1;
43};
44
45static struct backtrace *backtrace_list;
46 36
47#if !BYTE_MARK_STACK 37#if !BYTE_MARK_STACK
48static 38static
@@ -2081,11 +2071,11 @@ eval_sub (Lisp_Object form)
2081 original_args = XCDR (form); 2071 original_args = XCDR (form);
2082 2072
2083 backtrace.next = backtrace_list; 2073 backtrace.next = backtrace_list;
2084 backtrace_list = &backtrace;
2085 backtrace.function = &original_fun; /* This also protects them from gc. */ 2074 backtrace.function = &original_fun; /* This also protects them from gc. */
2086 backtrace.args = &original_args; 2075 backtrace.args = &original_args;
2087 backtrace.nargs = UNEVALLED; 2076 backtrace.nargs = UNEVALLED;
2088 backtrace.debug_on_exit = 0; 2077 backtrace.debug_on_exit = 0;
2078 backtrace_list = &backtrace;
2089 2079
2090 if (debug_on_next_call) 2080 if (debug_on_next_call)
2091 do_debug_on_call (Qt); 2081 do_debug_on_call (Qt);
@@ -2778,11 +2768,11 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
2778 } 2768 }
2779 2769
2780 backtrace.next = backtrace_list; 2770 backtrace.next = backtrace_list;
2781 backtrace_list = &backtrace;
2782 backtrace.function = &args[0]; 2771 backtrace.function = &args[0];
2783 backtrace.args = &args[1]; /* This also GCPROs them. */ 2772 backtrace.args = &args[1]; /* This also GCPROs them. */
2784 backtrace.nargs = nargs - 1; 2773 backtrace.nargs = nargs - 1;
2785 backtrace.debug_on_exit = 0; 2774 backtrace.debug_on_exit = 0;
2775 backtrace_list = &backtrace;
2786 2776
2787 /* Call GC after setting up the backtrace, so the latter GCPROs the args. */ 2777 /* Call GC after setting up the backtrace, so the latter GCPROs the args. */
2788 maybe_gc (); 2778 maybe_gc ();
diff --git a/src/fns.c b/src/fns.c
index 3225fefc5e3..3cb66534e0c 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -4096,13 +4096,6 @@ sweep_weak_hash_tables (void)
4096 4096
4097#define SXHASH_MAX_LEN 7 4097#define SXHASH_MAX_LEN 7
4098 4098
4099/* Combine two integers X and Y for hashing. The result might not fit
4100 into a Lisp integer. */
4101
4102#define SXHASH_COMBINE(X, Y) \
4103 ((((EMACS_UINT) (X) << 4) + ((EMACS_UINT) (X) >> (BITS_PER_EMACS_INT - 4))) \
4104 + (EMACS_UINT) (Y))
4105
4106/* Hash X, returning a value that fits into a Lisp integer. */ 4099/* Hash X, returning a value that fits into a Lisp integer. */
4107#define SXHASH_REDUCE(X) \ 4100#define SXHASH_REDUCE(X) \
4108 ((((X) ^ (X) >> (BITS_PER_EMACS_INT - FIXNUM_BITS))) & INTMASK) 4101 ((((X) ^ (X) >> (BITS_PER_EMACS_INT - FIXNUM_BITS))) & INTMASK)
diff --git a/src/lisp.h b/src/lisp.h
index d9a7c9d0bdc..b4cead003c2 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2015,6 +2015,18 @@ extern ptrdiff_t specpdl_size;
2015 2015
2016#define SPECPDL_INDEX() (specpdl_ptr - specpdl) 2016#define SPECPDL_INDEX() (specpdl_ptr - specpdl)
2017 2017
2018struct backtrace
2019{
2020 struct backtrace *next;
2021 Lisp_Object *function;
2022 Lisp_Object *args; /* Points to vector of args. */
2023 ptrdiff_t nargs; /* Length of vector. */
2024 /* Nonzero means call value of debugger when done with this operation. */
2025 unsigned int debug_on_exit : 1;
2026};
2027
2028extern struct backtrace *backtrace_list;
2029
2018/* Everything needed to describe an active condition case. */ 2030/* Everything needed to describe an active condition case. */
2019struct handler 2031struct handler
2020 { 2032 {
@@ -2667,6 +2679,11 @@ extern void init_syntax_once (void);
2667extern void syms_of_syntax (void); 2679extern void syms_of_syntax (void);
2668 2680
2669/* Defined in fns.c */ 2681/* Defined in fns.c */
2682/* Combine two integers X and Y for hashing. The result might not fit
2683 into a Lisp integer. */
2684#define SXHASH_COMBINE(X, Y) \
2685 ((((EMACS_UINT) (X) << 4) + ((EMACS_UINT) (X) >> (BITS_PER_EMACS_INT - 4))) \
2686 + (EMACS_UINT) (Y))
2670extern Lisp_Object QCrehash_size, QCrehash_threshold; 2687extern Lisp_Object QCrehash_size, QCrehash_threshold;
2671enum { NEXT_ALMOST_PRIME_LIMIT = 11 }; 2688enum { NEXT_ALMOST_PRIME_LIMIT = 11 };
2672EXFUN (Fidentity, 1) ATTRIBUTE_CONST; 2689EXFUN (Fidentity, 1) ATTRIBUTE_CONST;
@@ -3512,6 +3529,18 @@ extern int have_menus_p (void);
3512void syms_of_dbusbind (void); 3529void syms_of_dbusbind (void);
3513#endif 3530#endif
3514 3531
3532/* Defined in profiler.c */
3533extern int sample_profiler_running;
3534extern int memory_profiler_running;
3535extern void malloc_probe (size_t);
3536#define MALLOC_PROBE(size) \
3537 do { \
3538 if (memory_profiler_running) \
3539 malloc_probe (size); \
3540 } while (0)
3541extern void mark_profiler (void);
3542extern void syms_of_profiler (void);
3543
3515#ifdef DOS_NT 3544#ifdef DOS_NT
3516/* Defined in msdos.c, w32.c */ 3545/* Defined in msdos.c, w32.c */
3517extern char *emacs_root_dir (void); 3546extern char *emacs_root_dir (void);
diff --git a/src/profiler.c b/src/profiler.c
new file mode 100644
index 00000000000..56458c64b85
--- /dev/null
+++ b/src/profiler.c
@@ -0,0 +1,965 @@
1/* GNU Emacs profiler implementation.
2
3Copyright (C) 2012 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20#include <config.h>
21#include <stdio.h>
22#include <limits.h>
23#include <sys/time.h>
24#include <signal.h>
25#include <setjmp.h>
26#include "lisp.h"
27
28static void sigprof_handler (int, siginfo_t *, void *);
29static void block_sigprof (void);
30static void unblock_sigprof (void);
31
32int sample_profiler_running;
33int memory_profiler_running;
34
35
36
37/* Filters */
38
39enum pattern_type
40{
41 pattern_exact, /* foo */
42 pattern_body_exact, /* *foo* */
43 pattern_pre_any, /* *foo */
44 pattern_post_any, /* foo* */
45 pattern_body_any /* foo*bar */
46};
47
48struct pattern
49{
50 enum pattern_type type;
51 char *exact;
52 char *extra;
53 int exact_length;
54 int extra_length;
55};
56
57static struct pattern *
58parse_pattern (const char *pattern)
59{
60 int length = strlen (pattern);
61 enum pattern_type type;
62 char *exact;
63 char *extra = 0;
64 struct pattern *pat =
65 (struct pattern *) xmalloc (sizeof (struct pattern));
66
67 if (length > 1
68 && *pattern == '*'
69 && pattern[length - 1] == '*')
70 {
71 type = pattern_body_exact;
72 exact = xstrdup (pattern + 1);
73 exact[length - 2] = 0;
74 }
75 else if (*pattern == '*')
76 {
77 type = pattern_pre_any;
78 exact = xstrdup (pattern + 1);
79 }
80 else if (pattern[length - 1] == '*')
81 {
82 type = pattern_post_any;
83 exact = xstrdup (pattern);
84 exact[length - 1] = 0;
85 }
86 else if (strchr (pattern, '*'))
87 {
88 type = pattern_body_any;
89 exact = xstrdup (pattern);
90 extra = strchr (exact, '*');
91 *extra++ = 0;
92 }
93 else
94 {
95 type = pattern_exact;
96 exact = xstrdup (pattern);
97 }
98
99 pat->type = type;
100 pat->exact = exact;
101 pat->extra = extra;
102 pat->exact_length = strlen (exact);
103 pat->extra_length = extra ? strlen (extra) : 0;
104
105 return pat;
106}
107
108static void
109free_pattern (struct pattern *pattern)
110{
111 xfree (pattern->exact);
112 xfree (pattern);
113}
114
115static int
116pattern_match_1 (enum pattern_type type,
117 const char *exact,
118 int exact_length,
119 const char *string,
120 int length)
121{
122 if (exact_length > length)
123 return 0;
124 switch (type)
125 {
126 case pattern_exact:
127 return exact_length == length && !strncmp (exact, string, length);
128 case pattern_body_exact:
129 return strstr (string, exact) != 0;
130 case pattern_pre_any:
131 return !strncmp (exact, string + (length - exact_length), exact_length);
132 case pattern_post_any:
133 return !strncmp (exact, string, exact_length);
134 case pattern_body_any:
135 return 0;
136 }
137}
138
139static int
140pattern_match (struct pattern *pattern, const char *string)
141{
142 int length = strlen (string);
143 switch (pattern->type)
144 {
145 case pattern_body_any:
146 if (pattern->exact_length + pattern->extra_length > length)
147 return 0;
148 return pattern_match_1 (pattern_post_any,
149 pattern->exact,
150 pattern->exact_length,
151 string, length)
152 && pattern_match_1 (pattern_pre_any,
153 pattern->extra,
154 pattern->extra_length,
155 string, length);
156 default:
157 return pattern_match_1 (pattern->type,
158 pattern->exact,
159 pattern->exact_length,
160 string, length);
161 }
162}
163
164static int
165match (const char *pattern, const char *string)
166{
167 int res;
168 struct pattern *pat = parse_pattern (pattern);
169 res = pattern_match (pat, string);
170 free_pattern (pat);
171 return res;
172}
173
174#if 0
175static void
176should_match (const char *pattern, const char *string)
177{
178 putchar (match (pattern, string) ? '.' : 'F');
179}
180
181static void
182should_not_match (const char *pattern, const char *string)
183{
184 putchar (match (pattern, string) ? 'F' : '.');
185}
186
187static void
188pattern_match_tests (void)
189{
190 should_match ("", "");
191 should_not_match ("", "a");
192 should_match ("a", "a");
193 should_not_match ("a", "ab");
194 should_not_match ("ab", "a");
195 should_match ("*a*", "a");
196 should_match ("*a*", "ab");
197 should_match ("*a*", "ba");
198 should_match ("*a*", "bac");
199 should_not_match ("*a*", "");
200 should_not_match ("*a*", "b");
201 should_match ("*", "");
202 should_match ("*", "a");
203 should_match ("a*", "a");
204 should_match ("a*", "ab");
205 should_not_match ("a*", "");
206 should_not_match ("a*", "ba");
207 should_match ("*a", "a");
208 should_match ("*a", "ba");
209 should_not_match ("*a", "");
210 should_not_match ("*a", "ab");
211 should_match ("a*b", "ab");
212 should_match ("a*b", "acb");
213 should_match ("a*b", "aab");
214 should_match ("a*b", "abb");
215 should_not_match ("a*b", "");
216 should_not_match ("a*b", "");
217 should_not_match ("a*b", "abc");
218 puts ("");
219}
220#endif
221
222static struct pattern *filter_pattern;
223
224static void
225set_filter_pattern (const char *pattern)
226{
227 if (sample_profiler_running)
228 block_sigprof ();
229
230 if (filter_pattern)
231 {
232 free_pattern (filter_pattern);
233 filter_pattern = 0;
234 }
235 if (!pattern) return;
236 filter_pattern = parse_pattern (pattern);
237
238 if (sample_profiler_running)
239 unblock_sigprof ();
240}
241
242static int
243apply_filter_1 (Lisp_Object function)
244{
245 const char *name;
246
247 if (!filter_pattern)
248 return 1;
249
250 if (SYMBOLP (function))
251 name = SDATA (SYMBOL_NAME (function));
252 else if (SUBRP (function))
253 name = XSUBR (function)->symbol_name;
254 else
255 return 0;
256
257 return pattern_match (filter_pattern, name);
258}
259
260static int
261apply_filter (struct backtrace *backlist)
262{
263 while (backlist)
264 {
265 if (apply_filter_1 (*backlist->function))
266 return 1;
267 backlist = backlist->next;
268 }
269 return 0;
270}
271
272DEFUN ("profiler-set-filter-pattern",
273 Fprofiler_set_filter_pattern, Sprofiler_set_filter_pattern,
274 1, 1, "sPattern: ",
275 doc: /* FIXME */)
276 (Lisp_Object pattern)
277{
278 if (NILP (pattern))
279 {
280 set_filter_pattern (0);
281 return Qt;
282 }
283 else if (!STRINGP (pattern))
284 error ("Invalid type of profiler filter pattern");
285
286 set_filter_pattern (SDATA (pattern));
287
288 return Qt;
289}
290
291
292
293/* Backtraces */
294
295static Lisp_Object
296make_backtrace (int size)
297{
298 return Fmake_vector (make_number (size), Qnil);
299}
300
301static EMACS_UINT
302backtrace_hash (Lisp_Object backtrace)
303{
304 int i;
305 EMACS_UINT hash = 0;
306 for (i = 0; i < ASIZE (backtrace); i++)
307 /* FIXME */
308 hash = SXHASH_COMBINE (XUINT (AREF (backtrace, i)), hash);
309 return hash;
310}
311
312static int
313backtrace_equal (Lisp_Object a, Lisp_Object b)
314{
315 int i, j;
316
317 for (i = 0, j = 0;; i++, j++)
318 {
319 Lisp_Object x = i < ASIZE (a) ? AREF (a, i) : Qnil;
320 Lisp_Object y = j < ASIZE (b) ? AREF (b, j) : Qnil;
321 if (NILP (x) && NILP (y))
322 break;
323 else if (!EQ (x, y))
324 return 0;
325 }
326
327 return 1;
328}
329
330static Lisp_Object
331backtrace_object_1 (Lisp_Object backtrace, int i)
332{
333 if (i >= ASIZE (backtrace) || NILP (AREF (backtrace, i)))
334 return Qnil;
335 else
336 return Fcons (AREF (backtrace, i), backtrace_object_1 (backtrace, i + 1));
337}
338
339static Lisp_Object
340backtrace_object (Lisp_Object backtrace)
341{
342 backtrace_object_1 (backtrace, 0);
343}
344
345
346
347/* Slots */
348
349struct slot
350{
351 struct slot *next, *prev;
352 Lisp_Object backtrace;
353 unsigned int count;
354 unsigned int elapsed;
355 unsigned char used : 1;
356};
357
358static void
359mark_slot (struct slot *slot)
360{
361 mark_object (slot->backtrace);
362}
363
364static Lisp_Object
365slot_object (struct slot *slot)
366{
367 return list3 (backtrace_object (slot->backtrace),
368 make_number (slot->count),
369 make_number (slot->elapsed));
370}
371
372
373
374/* Slot heaps */
375
376struct slot_heap
377{
378 unsigned int size;
379 struct slot *data;
380 struct slot *free_list;
381};
382
383static void
384clear_slot_heap (struct slot_heap *heap)
385{
386 int i;
387 struct slot *data;
388 struct slot *free_list;
389
390 data = heap->data;
391
392 for (i = 0; i < heap->size; i++)
393 data[i].used = 0;
394
395 free_list = heap->free_list = heap->data;
396 for (i = 1; i < heap->size; i++)
397 {
398 free_list->next = &data[i];
399 free_list = free_list->next;
400 }
401 free_list->next = 0;
402}
403
404static struct slot_heap *
405make_slot_heap (unsigned int size, int max_stack_depth)
406{
407 int i;
408 struct slot_heap *heap;
409 struct slot *data;
410
411 data = (struct slot *) xmalloc (sizeof (struct slot) * size);
412 for (i = 0; i < size; i++)
413 data[i].backtrace = make_backtrace (max_stack_depth);
414
415 heap = (struct slot_heap *) xmalloc (sizeof (struct slot_heap));
416 heap->size = size;
417 heap->data = data;
418 clear_slot_heap (heap);
419
420 return heap;
421}
422
423static void
424free_slot_heap (struct slot_heap *heap)
425{
426 int i;
427 struct slot *data = heap->data;
428 for (i = 0; i < heap->size; i++)
429 data[i].backtrace = Qnil;
430 xfree (data);
431 xfree (heap);
432}
433
434static void
435mark_slot_heap (struct slot_heap *heap)
436{
437 int i;
438 for (i = 0; i < heap->size; i++)
439 mark_slot (&heap->data[i]);
440}
441
442static struct slot *
443allocate_slot (struct slot_heap *heap)
444{
445 struct slot *slot;
446 if (!heap->free_list)
447 return 0;
448 slot = heap->free_list;
449 slot->count = 0;
450 slot->elapsed = 0;
451 slot->used = 1;
452 heap->free_list = heap->free_list->next;
453 return slot;
454}
455
456static void
457free_slot (struct slot_heap *heap, struct slot *slot)
458{
459 eassert (slot->used);
460 slot->used = 0;
461 slot->next = heap->free_list;
462 heap->free_list = slot;
463}
464
465static struct slot *
466min_slot (struct slot_heap *heap)
467{
468 int i;
469 struct slot *min = 0;
470 for (i = 0; i < heap->size; i++)
471 {
472 struct slot *slot = &heap->data[i];
473 if (!min || (slot->used && slot->count < min->count))
474 min = slot;
475 }
476 return min;
477}
478
479
480
481/* Slot tables */
482
483struct slot_table
484{
485 unsigned int size;
486 struct slot **data;
487};
488
489static void
490clear_slot_table (struct slot_table *table)
491{
492 int i;
493 for (i = 0; i < table->size; i++)
494 table->data[i] = 0;
495}
496
497static struct slot_table *
498make_slot_table (int size)
499{
500 struct slot_table *table
501 = (struct slot_table *) xmalloc (sizeof (struct slot_table));
502 table->size = size;
503 table->data = (struct slot **) xmalloc (sizeof (struct slot *) * size);
504 clear_slot_table (table);
505 return table;
506}
507
508static void
509free_slot_table (struct slot_table *table)
510{
511 xfree (table->data);
512 xfree (table);
513}
514
515static void
516remove_slot (struct slot_table *table, struct slot *slot)
517{
518 if (slot->prev)
519 slot->prev->next = slot->next;
520 else
521 {
522 EMACS_UINT hash = backtrace_hash (slot->backtrace);
523 table->data[hash % table->size] = slot->next;
524 }
525 if (slot->next)
526 slot->next->prev = slot->prev;
527}
528
529
530
531/* Logs */
532
533struct log
534{
535 Lisp_Object type;
536 Lisp_Object backtrace;
537 struct slot_heap *slot_heap;
538 struct slot_table *slot_table;
539 unsigned int others_count;
540 unsigned int others_elapsed;
541};
542
543static struct log *
544make_log (const char *type, int heap_size, int max_stack_depth)
545{
546 struct log *log =
547 (struct log *) xmalloc (sizeof (struct log));
548 log->type = intern (type);
549 log->backtrace = make_backtrace (max_stack_depth);
550 log->slot_heap = make_slot_heap (heap_size, max_stack_depth);
551 log->slot_table = make_slot_table (max (256, heap_size) / 10);
552 log->others_count = 0;
553 log->others_elapsed = 0;
554 return log;
555}
556
557static void
558free_log (struct log *log)
559{
560 log->backtrace = Qnil;
561 free_slot_heap (log->slot_heap);
562 free_slot_table (log->slot_table);
563}
564
565static void
566mark_log (struct log *log)
567{
568 mark_object (log->type);
569 mark_object (log->backtrace);
570 mark_slot_heap (log->slot_heap);
571}
572
573static void
574clear_log (struct log *log)
575{
576 clear_slot_heap (log->slot_heap);
577 clear_slot_table (log->slot_table);
578 log->others_count = 0;
579 log->others_elapsed = 0;
580}
581
582static void
583evict_slot (struct log *log, struct slot *slot)
584{
585 log->others_count += slot->count;
586 log->others_elapsed += slot->elapsed;
587 remove_slot (log->slot_table, slot);
588 free_slot (log->slot_heap, slot);
589}
590
591static void
592evict_min_slot (struct log *log)
593{
594 struct slot *min = min_slot (log->slot_heap);
595 if (min)
596 evict_slot (log, min);
597}
598
599static struct slot *
600new_slot (struct log *log, Lisp_Object backtrace)
601{
602 int i;
603 struct slot *slot = allocate_slot (log->slot_heap);
604
605 if (!slot)
606 {
607 evict_min_slot (log);
608 slot = allocate_slot (log->slot_heap);
609 eassert (slot);
610 }
611
612 slot->prev = 0;
613 slot->next = 0;
614 for (i = 0; i < ASIZE (backtrace); i++)
615 ASET (slot->backtrace, i, AREF (backtrace, i));
616
617 return slot;
618}
619
620static struct slot *
621ensure_slot (struct log *log, Lisp_Object backtrace)
622{
623 EMACS_UINT hash = backtrace_hash (backtrace);
624 int index = hash % log->slot_table->size;
625 struct slot *slot = log->slot_table->data[index];
626 struct slot *prev = slot;
627
628 while (slot)
629 {
630 if (backtrace_equal (backtrace, slot->backtrace))
631 goto found;
632 prev = slot;
633 slot = slot->next;
634 }
635
636 slot = new_slot (log, backtrace);
637 if (prev)
638 {
639 slot->prev = prev;
640 prev->next = slot;
641 }
642 else
643 log->slot_table->data[index] = slot;
644
645 found:
646 return slot;
647}
648
649static void
650record_backtrace (struct log *log, unsigned int count, unsigned int elapsed)
651{
652 int i;
653 Lisp_Object backtrace = log->backtrace;
654 struct backtrace *backlist = backtrace_list;
655
656 if (!apply_filter (backlist)) return;
657
658 for (i = 0; i < ASIZE (backtrace) && backlist; backlist = backlist->next)
659 {
660 Lisp_Object function = *backlist->function;
661 if (FUNCTIONP (function))
662 {
663 ASET (backtrace, i, function);
664 i++;
665 }
666 }
667 for (; i < ASIZE (backtrace); i++)
668 ASET (backtrace, i, Qnil);
669
670 if (!NILP (AREF (backtrace, 0)))
671 {
672 struct slot *slot = ensure_slot (log, backtrace);
673 slot->count += count;
674 slot->elapsed += elapsed;
675 }
676}
677
678static Lisp_Object
679log_object (struct log *log)
680{
681 int i;
682 Lisp_Object slots = Qnil;
683
684 if (log->others_count != 0 || log->others_elapsed != 0)
685 slots = list1 (list3 (list1 (Qt),
686 make_number (log->others_count),
687 make_number (log->others_elapsed)));
688
689 for (i = 0; i < log->slot_heap->size; i++)
690 {
691 struct slot *s = &log->slot_heap->data[i];
692 if (s->used)
693 {
694 Lisp_Object slot = slot_object (s);
695 slots = Fcons (slot, slots);
696 }
697 }
698
699 return list4 (log->type, Qnil, Fcurrent_time (), slots);
700}
701
702
703
704/* Sample profiler */
705
706static struct log *sample_log;
707static int current_sample_interval;
708
709DEFUN ("sample-profiler-start", Fsample_profiler_start, Ssample_profiler_start,
710 1, 1, 0,
711 doc: /* FIXME */)
712 (Lisp_Object sample_interval)
713{
714 struct sigaction sa;
715 struct itimerval timer;
716
717 if (sample_profiler_running)
718 error ("Sample profiler is already running");
719
720 if (!sample_log)
721 sample_log = make_log ("sample",
722 profiler_slot_heap_size,
723 profiler_max_stack_depth);
724
725 current_sample_interval = XINT (sample_interval);
726
727 sa.sa_sigaction = sigprof_handler;
728 sa.sa_flags = SA_RESTART | SA_SIGINFO;
729 sigemptyset (&sa.sa_mask);
730 sigaction (SIGPROF, &sa, 0);
731
732 timer.it_interval.tv_sec = 0;
733 timer.it_interval.tv_usec = current_sample_interval * 1000;
734 timer.it_value = timer.it_interval;
735 setitimer (ITIMER_PROF, &timer, 0);
736
737 sample_profiler_running = 1;
738
739 return Qt;
740}
741
742DEFUN ("sample-profiler-stop", Fsample_profiler_stop, Ssample_profiler_stop,
743 0, 0, 0,
744 doc: /* FIXME */)
745 (void)
746{
747 if (!sample_profiler_running)
748 error ("Sample profiler is not running");
749 sample_profiler_running = 0;
750
751 setitimer (ITIMER_PROF, 0, 0);
752
753 return Qt;
754}
755
756DEFUN ("sample-profiler-reset", Fsample_profiler_reset, Ssample_profiler_reset,
757 0, 0, 0,
758 doc: /* FIXME */)
759 (void)
760{
761 if (sample_log)
762 {
763 if (sample_profiler_running)
764 {
765 block_sigprof ();
766 clear_log (sample_log);
767 unblock_sigprof ();
768 }
769 else
770 {
771 free_log (sample_log);
772 sample_log = 0;
773 }
774 }
775}
776
777DEFUN ("sample-profiler-running-p",
778 Fsample_profiler_running_p, Ssample_profiler_running_p,
779 0, 0, 0,
780 doc: /* FIXME */)
781 (void)
782{
783 return sample_profiler_running ? Qt : Qnil;
784}
785
786DEFUN ("sample-profiler-log",
787 Fsample_profiler_log, Ssample_profiler_log,
788 0, 0, 0,
789 doc: /* FIXME */)
790 (void)
791{
792 int i;
793 Lisp_Object result = Qnil;
794
795 if (sample_log)
796 {
797 if (sample_profiler_running)
798 {
799 block_sigprof ();
800 result = log_object (sample_log);
801 unblock_sigprof ();
802 }
803 else
804 result = log_object (sample_log);
805 }
806
807 return result;
808}
809
810
811
812/* Memory profiler */
813
814static struct log *memory_log;
815
816DEFUN ("memory-profiler-start", Fmemory_profiler_start, Smemory_profiler_start,
817 0, 0, 0,
818 doc: /* FIXME */)
819 (void)
820{
821 if (memory_profiler_running)
822 error ("Memory profiler is already running");
823
824 if (!memory_log)
825 memory_log = make_log ("memory",
826 profiler_slot_heap_size,
827 profiler_max_stack_depth);
828
829 memory_profiler_running = 1;
830
831 return Qt;
832}
833
834DEFUN ("memory-profiler-stop",
835 Fmemory_profiler_stop, Smemory_profiler_stop,
836 0, 0, 0,
837 doc: /* FIXME */)
838 (void)
839{
840 if (!memory_profiler_running)
841 error ("Memory profiler is not running");
842 memory_profiler_running = 0;
843
844 return Qt;
845}
846
847DEFUN ("memory-profiler-reset",
848 Fmemory_profiler_reset, Smemory_profiler_reset,
849 0, 0, 0,
850 doc: /* FIXME */)
851 (void)
852{
853 if (memory_log)
854 {
855 if (memory_profiler_running)
856 clear_log (memory_log);
857 else
858 {
859 free_log (memory_log);
860 memory_log = 0;
861 }
862 }
863}
864
865DEFUN ("memory-profiler-running-p",
866 Fmemory_profiler_running_p, Smemory_profiler_running_p,
867 0, 0, 0,
868 doc: /* FIXME */)
869 (void)
870{
871 return memory_profiler_running ? Qt : Qnil;
872}
873
874DEFUN ("memory-profiler-log",
875 Fmemory_profiler_log, Smemory_profiler_log,
876 0, 0, 0,
877 doc: /* FIXME */)
878 (void)
879{
880 Lisp_Object result = Qnil;
881
882 if (memory_log)
883 result = log_object (memory_log);
884
885 return result;
886}
887
888
889
890/* Signals and probes */
891
892static void
893sigprof_handler (int signal, siginfo_t *info, void *ctx)
894{
895 record_backtrace (sample_log, 1, current_sample_interval);
896}
897
898static void
899block_sigprof (void)
900{
901 sigset_t sigset;
902 sigemptyset (&sigset);
903 sigaddset (&sigset, SIGPROF);
904 sigprocmask (SIG_BLOCK, &sigset, 0);
905}
906
907static void
908unblock_sigprof (void)
909{
910 sigset_t sigset;
911 sigemptyset (&sigset);
912 sigaddset (&sigset, SIGPROF);
913 sigprocmask (SIG_UNBLOCK, &sigset, 0);
914}
915
916void
917malloc_probe (size_t size)
918{
919 record_backtrace (memory_log, size, 0);
920}
921
922
923
924void
925mark_profiler (void)
926{
927 if (sample_log)
928 {
929 if (sample_profiler_running)
930 {
931 block_sigprof ();
932 mark_log (sample_log);
933 unblock_sigprof ();
934 }
935 else
936 mark_log (sample_log);
937 }
938 if (memory_log)
939 mark_log (memory_log);
940}
941
942void
943syms_of_profiler (void)
944{
945 DEFVAR_INT ("profiler-max-stack-depth", profiler_max_stack_depth,
946 doc: /* FIXME */);
947 profiler_max_stack_depth = 16;
948 DEFVAR_INT ("profiler-slot-heap-size", profiler_slot_heap_size,
949 doc: /* FIXME */);
950 profiler_slot_heap_size = 10000;
951
952 defsubr (&Sprofiler_set_filter_pattern);
953
954 defsubr (&Ssample_profiler_start);
955 defsubr (&Ssample_profiler_stop);
956 defsubr (&Ssample_profiler_reset);
957 defsubr (&Ssample_profiler_running_p);
958 defsubr (&Ssample_profiler_log);
959
960 defsubr (&Smemory_profiler_start);
961 defsubr (&Smemory_profiler_stop);
962 defsubr (&Smemory_profiler_reset);
963 defsubr (&Smemory_profiler_running_p);
964 defsubr (&Smemory_profiler_log);
965}