From 6521894d1aa5a1017dd6f3f55b5e7c11dde5d004 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 24 Sep 2012 22:30:46 -0400 Subject: [PATCH] * src/profiler.c: Rename sample_profiler_* to profiler_cpu_* and memory_profiler_* to profiler_memory_*. Move sigprof_handler before its first use, inside the PROFILER_CPU_SUPPORT conditional. --- lisp/profiler.el | 44 +++++++------- src/ChangeLog | 6 ++ src/alloc.c | 13 ++-- src/lisp.h | 4 +- src/profiler.c | 177 ++++++++++++++++++++++++++++--------------------------- 5 files changed, 124 insertions(+), 120 deletions(-) diff --git a/lisp/profiler.el b/lisp/profiler.el index 90740a2e286..fb38b00c2d8 100644 --- a/lisp/profiler.el +++ b/lisp/profiler.el @@ -579,30 +579,30 @@ Also, if MODE is `mem' or `cpu+mem', then memory profiler will be started." nil t nil nil "cpu")))) (cl-ecase mode (cpu - (sample-profiler-start profiler-sample-interval) + (profiler-cpu-start profiler-sample-interval) (message "CPU profiler started")) (mem - (memory-profiler-start) + (profiler-memory-start) (message "Memory profiler started")) (cpu+mem - (sample-profiler-start profiler-sample-interval) - (memory-profiler-start) + (profiler-cpu-start profiler-sample-interval) + (profiler-memory-start) (message "CPU and memory profiler started")))) (defun profiler-stop () "Stop started profilers. Profiler logs will be kept." (interactive) (cond - ((and (sample-profiler-running-p) - (memory-profiler-running-p)) - (sample-profiler-stop) - (memory-profiler-stop) + ((and (profiler-cpu-running-p) + (profiler-memory-running-p)) + (profiler-cpu-stop) + (profiler-memory-stop) (message "CPU and memory profiler stopped")) - ((sample-profiler-running-p) - (sample-profiler-stop) + ((profiler-cpu-running-p) + (profiler-cpu-stop) (message "CPU profiler stopped")) - ((memory-profiler-running-p) - (memory-profiler-stop) + ((profiler-memory-running-p) + (profiler-memory-stop) (message "Memory profiler stopped")) (t (error "No profilers started")))) @@ -610,19 +610,19 @@ Also, if MODE is `mem' or `cpu+mem', then memory profiler will be started." (defun profiler-reset () "Reset profiler log." (interactive) - (ignore (sample-profiler-log)) - (ignore (memory-profiler-log)) + (ignore (profiler-cpu-log)) + (ignore (profiler-memory-log)) t) (defun profiler--report-cpu () - (let ((log (sample-profiler-log))) + (let ((log (profiler-cpu-log))) (when log (puthash 'type 'cpu log) (puthash 'timestamp (current-time) log) (profiler-report-log log)))) (defun profiler--report-memory () - (let ((log (memory-profiler-log))) + (let ((log (profiler-memory-log))) (when log (puthash 'type 'memory log) (puthash 'timestamp (current-time) log) @@ -647,19 +647,19 @@ Also, if MODE is `mem' or `cpu+mem', then memory profiler will be started." (cl-defmacro with-sample-profiling ((&key interval) &rest body) `(unwind-protect (progn - (ignore (sample-profiler-log)) - (sample-profiler-start ,interval) + (ignore (profiler-cpu-log)) + (profiler-cpu-start ,interval) ,@body) - (sample-profiler-stop) + (profiler-cpu-stop) (profiler--report-cpu))) (defmacro with-memory-profiling (&rest body) `(unwind-protect (progn - (ignore (memory-profiler-log)) - (memory-profiler-start) + (ignore (profiler-memory-log)) + (profiler-memory-start) ,@body) - (memory-profiler-stop) + (profiler-memory-stop) (profiler--report-memory))) (provide 'profiler) diff --git a/src/ChangeLog b/src/ChangeLog index 19b8afe5d51..d534a3f4104 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2012-09-25 Stefan Monnier + + * profiler.c: Rename sample_profiler_* to profiler_cpu_* and + memory_profiler_* to profiler_memory_*. Move sigprof_handler before + its first use, inside the PROFILER_CPU_SUPPORT conditional. + 2012-09-24 Stefan Monnier * profiler.c (evict_lower_half): Fix typo. diff --git a/src/alloc.c b/src/alloc.c index 2fc93f825d1..8c0f99cbb05 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -5447,7 +5447,7 @@ See Info node `(elisp)Garbage Collection'. */) FOR_EACH_BUFFER (nextb) compact_buffer (nextb); - if (memory_profiler_running) + if (profiler_memory_running) tot_before = total_bytes_of_live_objects (); start = current_emacs_time (); @@ -5726,15 +5726,12 @@ See Info node `(elisp)Garbage Collection'. */) gcs_done++; /* Collect profiling data. */ - if (memory_profiler_running) + if (profiler_memory_running) { size_t swept = 0; - if (memory_profiler_running) - { - size_t tot_after = total_bytes_of_live_objects (); - if (tot_before > tot_after) - swept = tot_before - tot_after; - } + size_t tot_after = total_bytes_of_live_objects (); + if (tot_before > tot_after) + swept = tot_before - tot_after; malloc_probe (swept); } diff --git a/src/lisp.h b/src/lisp.h index f029a061d24..a0390fd360f 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3527,11 +3527,11 @@ void syms_of_dbusbind (void); /* Defined in profiler.c. */ -extern bool memory_profiler_running; +extern bool profiler_memory_running; extern void malloc_probe (size_t); #define MALLOC_PROBE(size) \ do { \ - if (memory_profiler_running) \ + if (profiler_memory_running) \ malloc_probe (size); \ } while (0) extern void syms_of_profiler (void); diff --git a/src/profiler.c b/src/profiler.c index d22ab14e7ce..1c4fa0fa218 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -25,17 +25,6 @@ along with GNU Emacs. If not, see . */ #include #include "lisp.h" -/* True if sampling profiler is running. */ - -bool sample_profiler_running; - -/* True if memory profiler is running. */ - -bool memory_profiler_running; - -static void sigprof_handler (int, siginfo_t *, void *); - - /* Logs. */ typedef struct Lisp_Hash_Table log_t; @@ -193,6 +182,9 @@ record_backtrace (log_t *log, size_t count) #if defined SIGPROF && defined HAVE_SETITIMER #define PROFILER_CPU_SUPPORT +/* True if sampling profiler is running. */ +static bool profiler_cpu_running; + static Lisp_Object cpu_log; /* Separate counter for the time spent in the GC. */ static EMACS_INT cpu_gc_count; @@ -201,23 +193,41 @@ static EMACS_INT cpu_gc_count; static int current_sample_interval; -DEFUN ("sample-profiler-start", Fsample_profiler_start, Ssample_profiler_start, +/* Signal handler for sample profiler. */ + +static void +sigprof_handler (int signal, siginfo_t *info, void *ctx) +{ + eassert (HASH_TABLE_P (cpu_log)); + if (backtrace_list && EQ (*backtrace_list->function, Qautomatic_gc)) + /* Special case the time-count inside GC because the hash-table + code is not prepared to be used while the GC is running. + More specifically it uses ASIZE at many places where it does + not expect the ARRAY_MARK_FLAG to be set. We could try and + harden the hash-table code, but it doesn't seem worth the + effort. */ + cpu_gc_count += current_sample_interval; + else + record_backtrace (XHASH_TABLE (cpu_log), current_sample_interval); +} + +DEFUN ("profiler-cpu-start", Fprofiler_cpu_start, Sprofiler_cpu_start, 1, 1, 0, - doc: /* Start or restart sample profiler. Sample profiler will -take samples each SAMPLE-INTERVAL in millisecond. See also -`profiler-slot-heap-size' and `profiler-max-stack-depth'. */) + doc: /* Start or restart the cpu profiler. +The cpu profiler will take call-stack samples each SAMPLE-INTERVAL (expressed in milliseconds). +See also `profiler-log-size' and `profiler-max-stack-depth'. */) (Lisp_Object sample_interval) { struct sigaction sa; struct itimerval timer; - if (sample_profiler_running) + if (profiler_cpu_running) error ("Sample profiler is already running"); if (NILP (cpu_log)) { cpu_gc_count = 0; - cpu_log = make_log (profiler_slot_heap_size, + cpu_log = make_log (profiler_log_size, profiler_max_stack_depth); } @@ -233,48 +243,49 @@ take samples each SAMPLE-INTERVAL in millisecond. See also timer.it_value = timer.it_interval; setitimer (ITIMER_PROF, &timer, 0); - sample_profiler_running = 1; + profiler_cpu_running = 1; return Qt; } -DEFUN ("sample-profiler-stop", Fsample_profiler_stop, Ssample_profiler_stop, +DEFUN ("profiler-cpu-stop", Fprofiler_cpu_stop, Sprofiler_cpu_stop, 0, 0, 0, - doc: /* Stop sample profiler. Profiler log will be kept. */) + doc: /* Stop the cpu profiler. The profiler log is not affected. */) (void) { - if (!sample_profiler_running) + if (!profiler_cpu_running) error ("Sample profiler is not running"); - sample_profiler_running = 0; + profiler_cpu_running = 0; setitimer (ITIMER_PROF, 0, 0); return Qt; } -DEFUN ("sample-profiler-running-p", - Fsample_profiler_running_p, Ssample_profiler_running_p, +DEFUN ("profiler-cpu-running-p", + Fprofiler_cpu_running_p, Sprofiler_cpu_running_p, 0, 0, 0, - doc: /* Return t if sample profiler is running. */) + doc: /* Return non-nil iff cpu profiler is running. */) (void) { - return sample_profiler_running ? Qt : Qnil; + return profiler_cpu_running ? Qt : Qnil; } -DEFUN ("sample-profiler-log", - Fsample_profiler_log, Ssample_profiler_log, +DEFUN ("profiler-cpu-log", Fprofiler_cpu_log, Sprofiler_cpu_log, 0, 0, 0, - doc: /* Return sample profiler log. The data is a list of -(sample nil TIMESTAMP SLOTS), where TIMESTAMP is a timestamp when the -log is collected and SLOTS is a list of slots. */) + doc: /* Return the current cpu profiler log. +The log is a hash-table mapping backtraces to counters which represent +the amount of time spent at those points. Every backtrace is a vector +of functions, where the last few elements may be nil. +Before returning, a new log is allocated for future samples. */) (void) { Lisp_Object result = cpu_log; /* Here we're making the log visible to Elisp , so it's not safe any more for our use afterwards since we can't rely on its special pre-allocated keys anymore. So we have to allocate a new one. */ - cpu_log = (sample_profiler_running - ? make_log (profiler_slot_heap_size, profiler_max_stack_depth) + cpu_log = (profiler_cpu_running + ? make_log (profiler_log_size, profiler_max_stack_depth) : Qnil); Fputhash (Fmake_vector (make_number (1), Qautomatic_gc), make_number (cpu_gc_count), @@ -282,66 +293,74 @@ log is collected and SLOTS is a list of slots. */) cpu_gc_count = 0; return result; } -#endif +#endif /* not defined PROFILER_CPU_SUPPORT */ /* Memory profiler. */ +/* True if memory profiler is running. */ +bool profiler_memory_running; + static Lisp_Object memory_log; -DEFUN ("memory-profiler-start", Fmemory_profiler_start, Smemory_profiler_start, +DEFUN ("profiler-memory-start", Fprofiler_memory_start, Sprofiler_memory_start, 0, 0, 0, - doc: /* Start/restart memory profiler. See also -`profiler-slot-heap-size' and `profiler-max-stack-depth'. */) + doc: /* Start/restart the memory profiler. +The memory profiler will take samples of the call-stack whenever a new +allocation takes place. Note that most small allocations only trigger +the profiler occasionally. +See also `profiler-log-size' and `profiler-max-stack-depth'. */) (void) { - if (memory_profiler_running) + if (profiler_memory_running) error ("Memory profiler is already running"); if (NILP (memory_log)) - memory_log = make_log (profiler_slot_heap_size, + memory_log = make_log (profiler_log_size, profiler_max_stack_depth); - memory_profiler_running = 1; + profiler_memory_running = 1; return Qt; } -DEFUN ("memory-profiler-stop", - Fmemory_profiler_stop, Smemory_profiler_stop, +DEFUN ("profiler-memory-stop", + Fprofiler_memory_stop, Sprofiler_memory_stop, 0, 0, 0, - doc: /* Stop memory profiler. Profiler log will be kept. */) + doc: /* Stop the memory profiler. The profiler log is not affected. */) (void) { - if (!memory_profiler_running) + if (!profiler_memory_running) error ("Memory profiler is not running"); - memory_profiler_running = 0; + profiler_memory_running = 0; return Qt; } -DEFUN ("memory-profiler-running-p", - Fmemory_profiler_running_p, Smemory_profiler_running_p, +DEFUN ("profiler-memory-running-p", + Fprofiler_memory_running_p, Sprofiler_memory_running_p, 0, 0, 0, - doc: /* Return t if memory profiler is running. */) + doc: /* Return non-nil if memory profiler is running. */) (void) { - return memory_profiler_running ? Qt : Qnil; + return profiler_memory_running ? Qt : Qnil; } -DEFUN ("memory-profiler-log", - Fmemory_profiler_log, Smemory_profiler_log, +DEFUN ("profiler-memory-log", + Fprofiler_memory_log, Sprofiler_memory_log, 0, 0, 0, - doc: /* Return memory profiler log. The data is a list of -(memory nil TIMESTAMP SLOTS), where TIMESTAMP is a timestamp when the -log is collected and SLOTS is a list of slots. */) + doc: /* Return the current memory profiler log. +The log is a hash-table mapping backtraces to counters which represent +the amount of memory allocated at those points. Every backtrace is a vector +of functions, where the last few elements may be nil. +Before returning, a new log is allocated for future samples. */) (void) { Lisp_Object result = memory_log; /* Here we're making the log visible to Elisp , so it's not safe any more for our use afterwards since we can't rely on its special pre-allocated keys anymore. So we have to allocate a new one. */ - memory_log = (memory_profiler_running - ? make_log (profiler_slot_heap_size, profiler_max_stack_depth) + memory_log = (profiler_memory_running + ? make_log (profiler_log_size, profiler_max_stack_depth) : Qnil); return result; } @@ -349,24 +368,6 @@ log is collected and SLOTS is a list of slots. */) /* Signals and probes. */ -/* Signal handler for sample profiler. */ - -static void -sigprof_handler (int signal, siginfo_t *info, void *ctx) -{ - eassert (HASH_TABLE_P (cpu_log)); - if (backtrace_list && EQ (*backtrace_list->function, Qautomatic_gc)) - /* Special case the time-count inside GC because the hash-table - code is not prepared to be used while the GC is running. - More specifically it uses ASIZE at many places where it does - not expect the ARRAY_MARK_FLAG to be set. We could try and - harden the hash-table code, but it doesn't seem worth the - effort. */ - cpu_gc_count += current_sample_interval; - else - record_backtrace (XHASH_TABLE (cpu_log), current_sample_interval); -} - /* Record that the current backtrace allocated SIZE bytes. */ void malloc_probe (size_t size) @@ -379,26 +380,26 @@ void syms_of_profiler (void) { DEFVAR_INT ("profiler-max-stack-depth", profiler_max_stack_depth, - doc: /* FIXME */); + doc: /* Number of elements from the call-stack recorded in the log. */); profiler_max_stack_depth = 16; - DEFVAR_INT ("profiler-slot-heap-size", profiler_slot_heap_size, - doc: /* FIXME */); - profiler_slot_heap_size = 10000; + DEFVAR_INT ("profiler-log-size", profiler_log_size, + doc: /* Number of distinct call-stacks that can be recorded in a profiler log. +If the log gets full, some of the least-seen call-stacks will be evicted +to make room for new entries. */); + profiler_log_size = 10000; - /* FIXME: Rename things to start with "profiler-", to use "cpu" instead of - "sample", and to make them sound like they're internal or something. */ #ifdef PROFILER_CPU_SUPPORT cpu_log = Qnil; staticpro (&cpu_log); - defsubr (&Ssample_profiler_start); - defsubr (&Ssample_profiler_stop); - defsubr (&Ssample_profiler_running_p); - defsubr (&Ssample_profiler_log); + defsubr (&Sprofiler_cpu_start); + defsubr (&Sprofiler_cpu_stop); + defsubr (&Sprofiler_cpu_running_p); + defsubr (&Sprofiler_cpu_log); #endif memory_log = Qnil; staticpro (&memory_log); - defsubr (&Smemory_profiler_start); - defsubr (&Smemory_profiler_stop); - defsubr (&Smemory_profiler_running_p); - defsubr (&Smemory_profiler_log); + defsubr (&Sprofiler_memory_start); + defsubr (&Sprofiler_memory_stop); + defsubr (&Sprofiler_memory_running_p); + defsubr (&Sprofiler_memory_log); } -- 2.11.4.GIT