aboutsummaryrefslogtreecommitdiffstats
path: root/src/profiler.c
diff options
context:
space:
mode:
authorJoakim Verona2012-11-13 03:01:33 +0100
committerJoakim Verona2012-11-13 03:01:33 +0100
commit74fa27af7f4b50a6f5e2a378802b4c5edc11d044 (patch)
tree7030d55ecc2e06df59c08047b6f89e5b11a329dc /src/profiler.c
parent2a4942ed0e4cca22145a0d973112454c410c3dd7 (diff)
parentb95a9c0cba301ef8f1920a1d123ccd6873c14a63 (diff)
downloademacs-74fa27af7f4b50a6f5e2a378802b4c5edc11d044.tar.gz
emacs-74fa27af7f4b50a6f5e2a378802b4c5edc11d044.zip
upstream
Diffstat (limited to 'src/profiler.c')
-rw-r--r--src/profiler.c91
1 files changed, 76 insertions, 15 deletions
diff --git a/src/profiler.c b/src/profiler.c
index 51580710f28..3d8f7243d2f 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -35,6 +35,9 @@ saturated_add (EMACS_INT a, EMACS_INT b)
35 35
36typedef struct Lisp_Hash_Table log_t; 36typedef struct Lisp_Hash_Table log_t;
37 37
38static Lisp_Object Qprofiler_backtrace_equal;
39static struct hash_table_test hashtest_profiler;
40
38static Lisp_Object 41static Lisp_Object
39make_log (int heap_size, int max_stack_depth) 42make_log (int heap_size, int max_stack_depth)
40{ 43{
@@ -42,10 +45,11 @@ make_log (int heap_size, int max_stack_depth)
42 a special way. This is OK as long as the object is not exposed 45 a special way. This is OK as long as the object is not exposed
43 to Elisp, i.e. until it is returned by *-profiler-log, after which 46 to Elisp, i.e. until it is returned by *-profiler-log, after which
44 it can't be used any more. */ 47 it can't be used any more. */
45 Lisp_Object log = make_hash_table (Qequal, make_number (heap_size), 48 Lisp_Object log = make_hash_table (hashtest_profiler,
49 make_number (heap_size),
46 make_float (DEFAULT_REHASH_SIZE), 50 make_float (DEFAULT_REHASH_SIZE),
47 make_float (DEFAULT_REHASH_THRESHOLD), 51 make_float (DEFAULT_REHASH_THRESHOLD),
48 Qnil, Qnil, Qnil); 52 Qnil);
49 struct Lisp_Hash_Table *h = XHASH_TABLE (log); 53 struct Lisp_Hash_Table *h = XHASH_TABLE (log);
50 54
51 /* What is special about our hash-tables is that the keys are pre-filled 55 /* What is special about our hash-tables is that the keys are pre-filled
@@ -238,8 +242,6 @@ handle_profiler_signal (int signal)
238 cpu_gc_count = saturated_add (cpu_gc_count, 1); 242 cpu_gc_count = saturated_add (cpu_gc_count, 1);
239 else 243 else
240 { 244 {
241 Lisp_Object oquit;
242 bool saved_pending_signals;
243 EMACS_INT count = 1; 245 EMACS_INT count = 1;
244#ifdef HAVE_ITIMERSPEC 246#ifdef HAVE_ITIMERSPEC
245 if (profiler_timer_ok) 247 if (profiler_timer_ok)
@@ -249,19 +251,8 @@ handle_profiler_signal (int signal)
249 count += overruns; 251 count += overruns;
250 } 252 }
251#endif 253#endif
252 /* record_backtrace uses hash functions that call Fequal, which
253 uses QUIT, which can call malloc, which can cause disaster in
254 a signal handler. So inhibit QUIT. */
255 oquit = Vinhibit_quit;
256 saved_pending_signals = pending_signals;
257 Vinhibit_quit = Qt;
258 pending_signals = 0;
259
260 eassert (HASH_TABLE_P (cpu_log)); 254 eassert (HASH_TABLE_P (cpu_log));
261 record_backtrace (XHASH_TABLE (cpu_log), count); 255 record_backtrace (XHASH_TABLE (cpu_log), count);
262
263 Vinhibit_quit = oquit;
264 pending_signals = saved_pending_signals;
265 } 256 }
266} 257}
267 258
@@ -515,6 +506,66 @@ malloc_probe (size_t size)
515 record_backtrace (XHASH_TABLE (memory_log), min (size, MOST_POSITIVE_FIXNUM)); 506 record_backtrace (XHASH_TABLE (memory_log), min (size, MOST_POSITIVE_FIXNUM));
516} 507}
517 508
509DEFUN ("function-equal", Ffunction_equal, Sfunction_equal, 2, 2, 0,
510 doc: /* Return non-nil if F1 and F2 come from the same source.
511Used to determine if different closures are just different instances of
512the same lambda expression, or are really unrelated function. */)
513 (Lisp_Object f1, Lisp_Object f2)
514{
515 bool res;
516 if (EQ (f1, f2))
517 res = true;
518 else if (COMPILEDP (f1) && COMPILEDP (f2))
519 res = EQ (AREF (f1, COMPILED_BYTECODE), AREF (f2, COMPILED_BYTECODE));
520 else if (CONSP (f1) && CONSP (f2) && CONSP (XCDR (f1)) && CONSP (XCDR (f2))
521 && EQ (Qclosure, XCAR (f1))
522 && EQ (Qclosure, XCAR (f2)))
523 res = EQ (XCDR (XCDR (f1)), XCDR (XCDR (f2)));
524 else
525 res = false;
526 return res ? Qt : Qnil;
527}
528
529static bool
530cmpfn_profiler (struct hash_table_test *t,
531 Lisp_Object bt1, Lisp_Object bt2)
532{
533 if (VECTORP (bt1) && VECTORP (bt2))
534 {
535 ptrdiff_t i, l = ASIZE (bt1);
536 if (l != ASIZE (bt2))
537 return false;
538 for (i = 0; i < l; i++)
539 if (NILP (Ffunction_equal (AREF (bt1, i), AREF (bt2, i))))
540 return false;
541 return true;
542 }
543 else
544 return EQ (bt1, bt2);
545}
546
547static EMACS_UINT
548hashfn_profiler (struct hash_table_test *ht, Lisp_Object bt)
549{
550 if (VECTORP (bt))
551 {
552 EMACS_UINT hash = 0;
553 ptrdiff_t i, l = ASIZE (bt);
554 for (i = 0; i < l; i++)
555 {
556 Lisp_Object f = AREF (bt, i);
557 EMACS_UINT hash1
558 = (COMPILEDP (f) ? XHASH (AREF (f, COMPILED_BYTECODE))
559 : (CONSP (f) && CONSP (XCDR (f)) && EQ (Qclosure, XCAR (f)))
560 ? XHASH (XCDR (XCDR (f))) : XHASH (f));
561 hash = sxhash_combine (hash, hash1);
562 }
563 return (hash & INTMASK);
564 }
565 else
566 return XHASH (bt);
567}
568
518void 569void
519syms_of_profiler (void) 570syms_of_profiler (void)
520{ 571{
@@ -527,6 +578,16 @@ If the log gets full, some of the least-seen call-stacks will be evicted
527to make room for new entries. */); 578to make room for new entries. */);
528 profiler_log_size = 10000; 579 profiler_log_size = 10000;
529 580
581 DEFSYM (Qprofiler_backtrace_equal, "profiler-backtrace-equal");
582 {
583 struct hash_table_test test
584 = { Qprofiler_backtrace_equal, Qnil, Qnil,
585 cmpfn_profiler, hashfn_profiler };
586 hashtest_profiler = test;
587 }
588
589 defsubr (&Sfunction_equal);
590
530#ifdef PROFILER_CPU_SUPPORT 591#ifdef PROFILER_CPU_SUPPORT
531 profiler_cpu_running = NOT_RUNNING; 592 profiler_cpu_running = NOT_RUNNING;
532 cpu_log = Qnil; 593 cpu_log = Qnil;