diff options
| author | Stefan Monnier | 2012-11-08 14:12:23 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2012-11-08 14:12:23 -0500 |
| commit | b7432bb20f48902994bee522bea15acdb0c0e209 (patch) | |
| tree | 940e242625e16ade096c4144d728c56107aa7005 /src/profiler.c | |
| parent | 880027430c5580abf612a82273bd49b75b9fb73c (diff) | |
| download | emacs-b7432bb20f48902994bee522bea15acdb0c0e209.tar.gz emacs-b7432bb20f48902994bee522bea15acdb0c0e209.zip | |
Use ad-hoc comparison function for the profiler's hash-tables.
* src/profiler.c (Qprofiler_backtrace_equal, hashtest_profiler): New vars.
(make_log): Use them.
(handle_profiler_signal): Don't inhibit quit any longer since we don't
call Fequal any more.
(Ffunction_equal): New function.
(cmpfn_profiler, hashfn_profiler): New functions.
(syms_of_profiler): Initialize them.
* src/lisp.h (struct hash_table_test): New struct.
(struct Lisp_Hash_Table): Use it.
* src/alloc.c (mark_object): Mark hash_table_test fields of hash tables.
* src/fns.c (make_hash_table): Take a struct to describe the test.
(cmpfn_eql, cmpfn_equal, cmpfn_user_defined, hashfn_eq, hashfn_eql)
(hashfn_equal, hashfn_user_defined): Adjust to new calling convention.
(hash_lookup, hash_remove_from_table): Move assertion checking of
hashfn result here. Check hash-equality before calling cmpfn.
(Fmake_hash_table): Adjust call to make_hash_table.
(hashtest_eq, hashtest_eql, hashtest_equal): New structs.
(syms_of_fns): Initialize them.
* src/emacs.c (main): Move syms_of_fns earlier.
* src/xterm.c (syms_of_xterm):
* src/category.c (hash_get_category_set): Adjust call to make_hash_table.
* src/print.c (print_object): Adjust to new hash-table struct.
* src/composite.c (composition_gstring_put_cache): Adjust to new hashfn.
Diffstat (limited to 'src/profiler.c')
| -rw-r--r-- | src/profiler.c | 91 |
1 files changed, 76 insertions, 15 deletions
diff --git a/src/profiler.c b/src/profiler.c index 51580710f28..6f112440902 100644 --- a/src/profiler.c +++ b/src/profiler.c | |||
| @@ -35,6 +35,9 @@ saturated_add (EMACS_INT a, EMACS_INT b) | |||
| 35 | 35 | ||
| 36 | typedef struct Lisp_Hash_Table log_t; | 36 | typedef struct Lisp_Hash_Table log_t; |
| 37 | 37 | ||
| 38 | static Lisp_Object Qprofiler_backtrace_equal; | ||
| 39 | static struct hash_table_test hashtest_profiler; | ||
| 40 | |||
| 38 | static Lisp_Object | 41 | static Lisp_Object |
| 39 | make_log (int heap_size, int max_stack_depth) | 42 | make_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 | ||
| 509 | DEFUN ("function-equal", Ffunction_equal, Sfunction_equal, 2, 2, 0, | ||
| 510 | doc: /* Return non-nil if F1 and F2 come from the same source. | ||
| 511 | Used to determine if different closures are just different instances of | ||
| 512 | the 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 | |||
| 529 | static bool | ||
| 530 | cmpfn_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 | |||
| 547 | static EMACS_UINT | ||
| 548 | hashfn_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) ? XUINT (AREF (f, COMPILED_BYTECODE)) | ||
| 559 | : (CONSP (f) && CONSP (XCDR (f)) && EQ (Qclosure, XCAR (f))) | ||
| 560 | ? XUINT (XCDR (XCDR (f))) : XUINT (f)); | ||
| 561 | hash = hash1 + (hash << 1) + (hash == (EMACS_INT) hash); | ||
| 562 | } | ||
| 563 | return (hash & INTMASK); | ||
| 564 | } | ||
| 565 | else | ||
| 566 | return XUINT (bt); | ||
| 567 | } | ||
| 568 | |||
| 518 | void | 569 | void |
| 519 | syms_of_profiler (void) | 570 | syms_of_profiler (void) |
| 520 | { | 571 | { |
| @@ -527,6 +578,16 @@ If the log gets full, some of the least-seen call-stacks will be evicted | |||
| 527 | to make room for new entries. */); | 578 | to 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; |