Commit 6521894d authored by Stefan Monnier's avatar Stefan Monnier

* 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.
parent ad942b63
......@@ -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)
......
2012-09-25 Stefan Monnier <monnier@iro.umontreal.ca>
* 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 <monnier@iro.umontreal.ca>
* profiler.c (evict_lower_half): Fix typo.
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -25,17 +25,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <setjmp.h>
#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);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment