Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
emacs
emacs
Commits
3a880af4
Commit
3a880af4
authored
Sep 26, 2012
by
Stefan Monnier
Browse files
Options
Browse Files
Download
Plain Diff
Merge profiler branch
parents
9180598c
234148bf
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1252 additions
and
47 deletions
+1252
-47
etc/NEWS
etc/NEWS
+5
-0
lisp/ChangeLog
lisp/ChangeLog
+5
-0
lisp/profiler.el
lisp/profiler.el
+665
-0
src/ChangeLog
src/ChangeLog
+45
-19
src/Makefile.in
src/Makefile.in
+1
-0
src/alloc.c
src/alloc.c
+57
-10
src/emacs.c
src/emacs.c
+2
-0
src/eval.c
src/eval.c
+3
-13
src/lisp.h
src/lisp.h
+20
-0
src/makefile.w32-in
src/makefile.w32-in
+7
-1
src/profiler.c
src/profiler.c
+426
-0
src/xdisp.c
src/xdisp.c
+16
-4
No files found.
etc/NEWS
View file @
3a880af4
...
...
@@ -678,6 +678,11 @@ are deprecated and will be removed eventually.
*
Lisp changes in Emacs 24.3
** New sampling-based Elisp profiler.
Try M-x profiler-start ... M-x profiler-stop; and then M-x profiler-report.
The sampling rate can be based on CPU time (only supported on some
systems), or based on memory allocations.
** CL-style generalized variables are now in core Elisp.
`setf'
is autoloaded; `push' and `pop' accept generalized variables.
...
...
lisp/ChangeLog
View file @
3a880af4
2012-09-26 Tomohiro Matsuyama <tomo@cx4a.org>
Stefan Monnier <monnier@iro.umontreal.ca>
* profiler.el: New file.
2012-09-26 Stefan Monnier <monnier@iro.umontreal.ca>
* emacs-lisp/testcover.el (testcover-after): Add gv-expander.
...
...
lisp/profiler.el
0 → 100644
View file @
3a880af4
This diff is collapsed.
Click to expand it.
src/ChangeLog
View file @
3a880af4
2012-09-26 Tomohiro Matsuyama <tomo@cx4a.org>
Stefan Monnier <monnier@iro.umontreal.ca>
Juanma Barranquero <lekktu@gmail.com>
* profiler.c: New file.
* Makefile.in (base_obj): Add profiler.o.
* makefile.w32-in (OBJ2, GLOBAL_SOURCES): Add profiler.c.
($(BLD)/profiler.$(O)): New target.
* emacs.c (main): Call syms_of_profiler.
* alloc.c (Qautomatic_gc): New constant.
(MALLOC_PROBE): New macro.
(xmalloc, xzalloc, xrealloc, lisp_malloc, lisp_align_malloc): Use it.
(total_bytes_of_live_objects): New function.
(Fgarbage_collect): Use it. Record itself in backtrace_list.
Call malloc_probe for the memory profiler.
(syms_of_alloc): Define Qautomatic_gc.
* eval.c (eval_sub, Ffuncall): Reorder assignments to avoid
race condition.
(struct backtrace): Move definition...
* lisp.h (struct backtrace): ..here.
(Qautomatic_gc, profiler_memory_running): Declare vars.
(malloc_probe, syms_of_profiler): Declare functions.
* xdisp.c (Qautomatic_redisplay): New constant.
(redisplay_internal): Record itself in backtrace_list.
(syms_of_xdisp): Define Qautomatic_redisplay.
2012-09-25 Juanma Barranquero <lekktu@gmail.com>
* makefile.w32-in ($(BLD)/callproc.$(O)): Update dependencies.
...
...
@@ -291,8 +317,8 @@
(reinvoke_input_signal): Remove. All uses replaced by
handle_async_input.
(quit_count): Now volatile, since a signal handler uses it.
(handle_interrupt): Now takes bool IN_SIGNAL_HANDLER as arg.
All
callers changed. Block SIGINT only if not already blocked.
(handle_interrupt): Now takes bool IN_SIGNAL_HANDLER as arg.
All
callers changed. Block SIGINT only if not already blocked.
Clear sigmask reliably, even if Fsignal returns, which it can.
Omit unnecessary accesses to volatile var.
(quit_throw_to_read_char): No need to restore sigmask.
...
...
@@ -392,8 +418,8 @@
if it is defined. Arguments and return value changed.
(valid_image_p, make_image): Callers changed.
(xbm_type, xpm_type, pbm_type, png_type, jpeg_type, tiff_type)
(gif_type, imagemagick_type, svg_type, gs_type):
Add
initialization functions.
(gif_type, imagemagick_type, svg_type, gs_type):
Add
initialization functions.
(Finit_image_library): Call lookup_image_type.
(CHECK_LIB_AVAILABLE): Macro deleted.
(lookup_image_type): Call define_image_type here, rather than via
...
...
@@ -415,8 +441,8 @@
* window.c (Fsplit_window_internal): Handle only Qt value of
Vwindow_combination_limit separately.
(Qtemp_buffer_resize): New symbol.
(Vwindow_combination_limit): New default value.
Rewrite
doc-string.
(Vwindow_combination_limit): New default value.
Rewrite
doc-string.
2012-09-22 Eli Zaretskii <eliz@gnu.org>
...
...
@@ -515,7 +541,7 @@
(Fx_create_frame): Call x_set_offset to correctly interpret
top_pos in geometry.
* frame.c (read_integer, XParseGeometry): Move
d
from w32xfns.c.
* frame.c (read_integer, XParseGeometry): Move from w32xfns.c.
(Fx_parse_geometry): If there is a space in string, call
Qns_parse_geometry, otherwise do as on other terms (Bug#12368).
...
...
@@ -616,8 +642,8 @@
2012-09-16 Martin Rudalics <rudalics@gmx.at>
* window.c (Fwindow_parameter, Fset_window_parameter):
Accept
any window as argument (Bug#12452).
* window.c (Fwindow_parameter, Fset_window_parameter):
Accept
any window as argument (Bug#12452).
2012-09-16 Jan Djärv <jan.h.d@swipnet.se>
...
...
@@ -692,8 +718,8 @@
2012-09-14 Dmitry Antipov <dmantipov@yandex.ru>
Avoid out-of-range marker position (Bug#12426).
* insdel.c (replace_range, replace_range_2):
Adjust
markers before overlays, as suggested by comments.
* insdel.c (replace_range, replace_range_2):
Adjust
markers before overlays, as suggested by comments.
(insert_1_both, insert_from_buffer_1, adjust_after_replace):
Remove redundant check before calling offset_intervals.
...
...
@@ -992,8 +1018,8 @@
in the internal border.
(x_set_window_size): Remove static variables and their usage.
(ns_redraw_scroll_bars): Fix NSTRACE arg.
(ns_after_update_window_line, ns_draw_fringe_bitmap):
Remove
fringe/internal border adjustment (Bug#11052).
(ns_after_update_window_line, ns_draw_fringe_bitmap):
Remove
fringe/internal border adjustment (Bug#11052).
(ns_draw_fringe_bitmap): Make code more like other terms (xterm.c).
(ns_draw_window_cursor): Remove fringe/internal border adjustment.
(ns_fix_rect_ibw): Remove.
...
...
@@ -1210,8 +1236,8 @@
(init_signals) [FORWARD_SIGNAL_TO_MAIN_THREAD]: Initialize it;
code moved here from emacs.c's main function.
* sysdep.c, syssignal.h (handle_on_main_thread): New function,
replacing the old SIGNAL_THREAD_CHECK. All uses changed.
This
lets callers save and restore errno properly.
replacing the old SIGNAL_THREAD_CHECK. All uses changed.
This
lets callers save and restore errno properly.
2012-09-05 Dmitry Antipov <dmantipov@yandex.ru>
...
...
@@ -1520,8 +1546,8 @@
* process.c: Include TERM_HEADER instead of listing all possible
window-system headers.
* nsterm.h: Remove declarations now in frame.h.
Define
FRAME_X_SCREEN, FRAME_X_VISUAL.
* nsterm.h: Remove declarations now in frame.h.
Define
FRAME_X_SCREEN, FRAME_X_VISUAL.
* menu.c: Include TERM_HEADER instead of listing all possible
window-system headers.
...
...
@@ -1717,8 +1743,8 @@
* nsterm.h (NSPanel): New class variable dialog_return.
* nsmenu.m (initWithContentRect:styleMask:backing:defer:):
Initialize
dialog_return.
* nsmenu.m (initWithContentRect:styleMask:backing:defer:):
Initialize
dialog_return.
(windowShouldClose:): Use stop instead of stopModalWithCode.
(clicked:): Ditto, and also set dialog_return (Bug#12258).
(timeout_handler:): Use stop instead of abortModal. Send a dummy
...
...
src/Makefile.in
View file @
3a880af4
...
...
@@ -339,6 +339,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
process.o gnutls.o callproc.o
\
region-cache.o sound.o atimer.o
\
doprnt.o intervals.o textprop.o composite.o xml.o
\
profiler.o
\
$(MSDOS_OBJ)
$(MSDOS_X_OBJ)
$(NS_OBJ)
$(CYGWIN_OBJ)
$(FONT_OBJ)
\
$(WINDOW_SYSTEM_OBJ)
obj
=
$(base_obj)
$(NS_OBJC_OBJ)
...
...
src/alloc.c
View file @
3a880af4
...
...
@@ -205,6 +205,7 @@ static Lisp_Object Qintervals;
static Lisp_Object Qbuffers;
static Lisp_Object Qstring_bytes, Qvector_slots, Qheap;
static Lisp_Object Qgc_cons_threshold;
Lisp_Object Qautomatic_gc;
Lisp_Object Qchar_table_extra_slots;
/* Hook run after GC has finished. */
...
...
@@ -648,6 +649,13 @@ malloc_unblock_input (void)
# define MALLOC_UNBLOCK_INPUT ((void) 0)
#endif
#define MALLOC_PROBE(size) \
do { \
if (profiler_memory_running) \
malloc_probe (size); \
} while (0)
/* Like malloc but check for no memory and block interrupt input.. */
void *
...
...
@@ -661,6 +669,7 @@ xmalloc (size_t size)
if (!val && size)
memory_full (size);
MALLOC_PROBE (size);
return val;
}
...
...
@@ -678,6 +687,7 @@ xzalloc (size_t size)
if (!val && size)
memory_full (size);
memset (val, 0, size);
MALLOC_PROBE (size);
return val;
}
...
...
@@ -699,6 +709,7 @@ xrealloc (void *block, size_t size)
if (!val && size)
memory_full (size);
MALLOC_PROBE (size);
return val;
}
...
...
@@ -888,6 +899,7 @@ lisp_malloc (size_t nbytes, enum mem_type type)
MALLOC_UNBLOCK_INPUT;
if (!val && nbytes)
memory_full (nbytes);
MALLOC_PROBE (nbytes);
return val;
}
...
...
@@ -1093,6 +1105,8 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
MALLOC_UNBLOCK_INPUT;
MALLOC_PROBE (nbytes);
eassert (0 == ((uintptr_t) val) % BLOCK_ALIGN);
return val;
}
...
...
@@ -5043,6 +5057,23 @@ bounded_number (EMACS_INT number)
return make_number (min (MOST_POSITIVE_FIXNUM, number));
}
/* Calculate total bytes of live objects. */
static size_t
total_bytes_of_live_objects (void)
{
size_t tot = 0;
tot += total_conses * sizeof (struct Lisp_Cons);
tot += total_symbols * sizeof (struct Lisp_Symbol);
tot += total_markers * sizeof (union Lisp_Misc);
tot += total_string_bytes;
tot += total_vector_slots * word_size;
tot += total_floats * sizeof (struct Lisp_Float);
tot += total_intervals * sizeof (struct interval);
tot += total_strings * sizeof (struct Lisp_String);
return tot;
}
DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
doc: /* Reclaim storage for Lisp objects no longer needed.
Garbage collection happens automatically if you cons more than
...
...
@@ -5068,6 +5099,8 @@ See Info node `(elisp)Garbage Collection'. */)
ptrdiff_t count = SPECPDL_INDEX ();
EMACS_TIME start;
Lisp_Object retval = Qnil;
size_t tot_before = 0;
struct backtrace backtrace;
if (abort_on_gc)
emacs_abort ();
...
...
@@ -5077,6 +5110,14 @@ See Info node `(elisp)Garbage Collection'. */)
if (pure_bytes_used_before_overflow)
return Qnil;
/* Record this function, so it appears on the profiler's backtraces. */
backtrace.next = backtrace_list;
backtrace.function = &Qautomatic_gc;
backtrace.args = &Qautomatic_gc;
backtrace.nargs = 0;
backtrace.debug_on_exit = 0;
backtrace_list = &backtrace;
check_cons_list ();
/* Don't keep undo information around forever.
...
...
@@ -5084,6 +5125,9 @@ See Info node `(elisp)Garbage Collection'. */)
FOR_EACH_BUFFER (nextb)
compact_buffer (nextb);
if (profiler_memory_running)
tot_before = total_bytes_of_live_objects ();
start = current_emacs_time ();
/* In case user calls debug_print during GC,
...
...
@@ -5255,16 +5299,7 @@ See Info node `(elisp)Garbage Collection'. */)
gc_relative_threshold = 0;
if (FLOATP (Vgc_cons_percentage))
{ /* Set gc_cons_combined_threshold. */
double tot = 0;
tot += total_conses * sizeof (struct Lisp_Cons);
tot += total_symbols * sizeof (struct Lisp_Symbol);
tot += total_markers * sizeof (union Lisp_Misc);
tot += total_string_bytes;
tot += total_vector_slots * word_size;
tot += total_floats * sizeof (struct Lisp_Float);
tot += total_intervals * sizeof (struct interval);
tot += total_strings * sizeof (struct Lisp_String);
double tot = total_bytes_of_live_objects ();
tot *= XFLOAT_DATA (Vgc_cons_percentage);
if (0 < tot)
...
...
@@ -5367,6 +5402,17 @@ See Info node `(elisp)Garbage Collection'. */)
gcs_done++;
/* Collect profiling data. */
if (profiler_memory_running)
{
size_t swept = 0;
size_t tot_after = total_bytes_of_live_objects ();
if (tot_before > tot_after)
swept = tot_before - tot_after;
malloc_probe (swept);
}
backtrace_list = backtrace.next;
return retval;
}
...
...
@@ -6527,6 +6573,7 @@ do hash-consing of the objects allocated to pure space. */);
DEFSYM (Qstring_bytes, "string-bytes");
DEFSYM (Qvector_slots, "vector-slots");
DEFSYM (Qheap, "heap");
DEFSYM (Qautomatic_gc, "Automatic GC");
DEFSYM (Qgc_cons_threshold, "gc-cons-threshold");
DEFSYM (Qchar_table_extra_slots, "char-table-extra-slots");
...
...
src/emacs.c
View file @
3a880af4
...
...
@@ -1419,6 +1419,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
syms_of_ntterm ();
#endif /* WINDOWSNT */
syms_of_profiler ();
keys_of_casefiddle ();
keys_of_cmds ();
keys_of_buffer ();
...
...
src/eval.c
View file @
3a880af4
...
...
@@ -31,17 +31,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "xterm.h"
#endif
struct backtrace
{
struct backtrace *next;
Lisp_Object *function;
Lisp_Object *args; /* Points to vector of args. */
ptrdiff_t nargs; /* Length of vector. */
/* Nonzero means call value of debugger when done with this operation. */
unsigned int debug_on_exit : 1;
};
static struct backtrace *backtrace_list;
struct backtrace *backtrace_list;
#if !BYTE_MARK_STACK
static
...
...
@@ -2055,11 +2045,11 @@ eval_sub (Lisp_Object form)
original_args = XCDR (form);
backtrace.next = backtrace_list;
backtrace_list = &backtrace;
backtrace.function = &original_fun; /* This also protects them from gc. */
backtrace.args = &original_args;
backtrace.nargs = UNEVALLED;
backtrace.debug_on_exit = 0;
backtrace_list = &backtrace;
if (debug_on_next_call)
do_debug_on_call (Qt);
...
...
@@ -2730,11 +2720,11 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */)
}
backtrace.next = backtrace_list;
backtrace_list = &backtrace;
backtrace.function = &args[0];
backtrace.args = &args[1]; /* This also GCPROs them. */
backtrace.nargs = nargs - 1;
backtrace.debug_on_exit = 0;
backtrace_list = &backtrace;
/* Call GC after setting up the backtrace, so the latter GCPROs the args. */
maybe_gc ();
...
...
src/lisp.h
View file @
3a880af4
...
...
@@ -2031,6 +2031,18 @@ extern ptrdiff_t specpdl_size;
#define SPECPDL_INDEX() (specpdl_ptr - specpdl)
struct backtrace
{
struct backtrace *next;
Lisp_Object *function;
Lisp_Object *args; /* Points to vector of args. */
ptrdiff_t nargs; /* Length of vector. */
/* Nonzero means call value of debugger when done with this operation. */
unsigned int debug_on_exit : 1;
};
extern struct backtrace *backtrace_list;
/* Everything needed to describe an active condition case.
Members are volatile if their values need to survive _longjmp when
...
...
@@ -2916,6 +2928,7 @@ build_string (const char *str)
extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
extern void make_byte_code (struct Lisp_Vector *);
extern Lisp_Object Qautomatic_gc;
extern Lisp_Object Qchar_table_extra_slots;
extern struct Lisp_Vector *allocate_vector (EMACS_INT);
extern struct Lisp_Vector *allocate_pseudovector (int memlen, int lisplen, int tag);
...
...
@@ -3534,6 +3547,13 @@ extern int have_menus_p (void);
void syms_of_dbusbind (void);
#endif
/* Defined in profiler.c. */
extern bool profiler_memory_running;
extern void malloc_probe (size_t);
extern void syms_of_profiler (void);
#ifdef DOS_NT
/* Defined in msdos.c, w32.c. */
extern char *emacs_root_dir (void);
...
...
src/makefile.w32-in
View file @
3a880af4
...
...
@@ -125,6 +125,7 @@ OBJ2 = $(BLD)/sysdep.$(O) \
$(BLD)
/terminal.
$(O)
\
$(BLD)
/menu.
$(O)
\
$(BLD)
/xml.
$(O)
\
$(BLD)
/profiler.
$(O)
\
$(BLD)
/w32term.
$(O)
\
$(BLD)
/w32xfns.
$(O)
\
$(BLD)
/w32fns.
$(O)
\
...
...
@@ -222,7 +223,7 @@ GLOBAL_SOURCES = dosfns.c msdos.c \
process.c callproc.c unexw32.c
\
region-cache.c sound.c atimer.c
\
doprnt.c intervals.c textprop.c composite.c
\
gnutls.c xml.c
gnutls.c xml.c
profiler.c
SOME_MACHINE_OBJECTS
=
dosfns.o msdos.o
\
xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o dbusbind.o
obj
=
$(GLOBAL_SOURCES:.c=.o)
...
...
@@ -973,6 +974,11 @@ $(BLD)/xml.$(O) : \
$(CONFIG_H)
\
$(LISP_H)
$(BLD)/profiler.$(O)
:
\
$(SRC)/profiler.c
\
$(CONFIG_H)
\
$(LISP_H)
$(BLD)/image.$(O)
:
\
$(SRC)/image.c
\
$(SRC)/blockinput.h
\
...
...
src/profiler.c
0 → 100644
View file @
3a880af4
/* Profiler implementation.
Copyright (C) 2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <stdio.h>
#include <limits.h>
#include <sys/time.h>
#include <signal.h>
#include <setjmp.h>
#include "lisp.h"
/* Logs. */
typedef
struct
Lisp_Hash_Table
log_t
;
static
Lisp_Object
make_log
(
int
heap_size
,
int
max_stack_depth
)
{
/* We use a standard Elisp hash-table object, but we use it in
a special way. This is OK as long as the object is not exposed
to Elisp, i.e. until it is returned by *-profiler-log, after which
it can't be used any more. */
Lisp_Object
log
=
make_hash_table
(
Qequal
,
make_number
(
heap_size
),
make_float
(
DEFAULT_REHASH_SIZE
),
make_float
(
DEFAULT_REHASH_THRESHOLD
),
Qnil
,
Qnil
,
Qnil
);
struct
Lisp_Hash_Table
*
h
=
XHASH_TABLE
(
log
);
/* What is special about our hash-tables is that the keys are pre-filled
with the vectors we'll put in them. */
int
i
=
ASIZE
(
h
->
key_and_value
)
/
2
;
while
(
0
<
i
)
set_hash_key_slot
(
h
,
--
i
,
Fmake_vector
(
make_number
(
max_stack_depth
),
Qnil
));
return
log
;
}
/* Evict the least used half of the hash_table.
When the table is full, we have to evict someone.
The easiest and most efficient is to evict the value we're about to add
(i.e. once the table is full, stop sampling).
We could also pick the element with the lowest count and evict it,
but finding it is O(N) and for that amount of work we get very
little in return: for the next sample, this latest sample will have
count==1 and will hence be a prime candidate for eviction :-(
So instead, we take O(N) time to eliminate more or less half of the
entries (the half with the lowest counts). So we get an amortized
cost of O(1) and we get O(N) time for a new entry to grow larger
than the other least counts before a new round of eviction. */
static
EMACS_INT
approximate_median
(
log_t
*
log
,
ptrdiff_t
start
,
ptrdiff_t
size
)
{
eassert
(
size
>
0
);
if
(
size
<
2
)
return
XINT
(
HASH_VALUE
(
log
,
start
));
if
(
size
<
3
)
/* Not an actual median, but better for our application than
choosing either of the two numbers. */
return
((
XINT
(
HASH_VALUE
(
log
,
start
))
+
XINT
(
HASH_VALUE
(
log
,
start
+
1
)))
/
2
);
else
{
ptrdiff_t
newsize
=
size
/
3
;
ptrdiff_t
start2
=
start
+
newsize
;
EMACS_INT
i1
=
approximate_median
(
log
,
start
,
newsize
);
EMACS_INT
i2
=
approximate_median
(
log
,
start2
,
newsize
);
EMACS_INT
i3
=
approximate_median
(
log
,
start2
+
newsize
,
size
-
2
*
newsize
);
return
(
i1
<
i2
?
(
i2
<
i3
?
i2
:
(
i1
<
i3
?
i3
:
i1
))
:
(
i1
<
i3
?
i1
:
(
i2
<
i3
?
i3
:
i2
)));
}
}
static
void
evict_lower_half
(
log_t
*
log
)
{
ptrdiff_t
size
=
ASIZE
(
log
->
key_and_value
)
/
2
;
EMACS_INT
median
=
approximate_median
(
log
,
0
,
size
);
ptrdiff_t
i
;
for
(
i
=
0
;
i
<
size
;
i
++
)
/* Evict not only values smaller but also values equal to the median,
so as to make sure we evict something no matter what. */
if
(
XINT
(
HASH_VALUE
(
log
,
i
))
<=
median
)
{
Lisp_Object
key
=
HASH_KEY
(
log
,
i
);
{
/* FIXME: we could make this more efficient. */
Lisp_Object
tmp
;
XSET_HASH_TABLE
(
tmp
,
log
);
/* FIXME: Use make_lisp_ptr. */
Fremhash
(
key
,
tmp
);
}
eassert
(
EQ
(
log
->
next_free
,
make_number
(
i
)));
{
int
j
;
eassert
(
VECTORP
(
key
));
for
(
j
=
0
;
j
<
ASIZE
(
key
);
j
++
)
ASET
(
key
,
j
,
Qnil
);
}
set_hash_key_slot
(
log
,
i
,
key
);
}
}
/* Record the current backtrace in LOG. BASE is a special name for
describing which the backtrace come from. BASE can be nil. COUNT is
a number how many times the profiler sees the backtrace at the
time. ELAPSED is a elapsed time in millisecond that the backtrace
took. */
static
void
record_backtrace
(
log_t
*
log
,
size_t
count
)
{
struct
backtrace
*
backlist
=
backtrace_list
;
Lisp_Object
backtrace
;
ptrdiff_t
index
,
i
=
0
;
ptrdiff_t
asize
;
if
(
!
INTEGERP
(
log
->
next_free
))
/* FIXME: transfer the evicted counts to a special entry rather
than dropping them on the floor. */
evict_lower_half
(
log
);
index
=
XINT
(
log
->
next_free
);
/* Get a "working memory" vector. */
backtrace
=
HASH_KEY
(
log
,
index
);
asize
=
ASIZE
(
backtrace
);
/* Copy the backtrace contents into working memory. */
for
(;
i
<
asize
&&
backlist
;
i
++
,
backlist
=
backlist
->
next
)
/* FIXME: For closures we should ignore the environment. */
ASET
(
backtrace
,
i
,
*
backlist
->
function
);
/* Make sure that unused space of working memory is filled with nil. */
for
(;
i
<
asize
;
i
++
)
ASET
(
backtrace
,
i
,
Qnil
);
{
/* We basically do a `gethash+puthash' here, except that we have to be
careful to avoid memory allocation since we're in a signal
handler, and we optimize the code to try and avoid computing the
hash+lookup twice. See fns.c:Fputhash for reference. */
EMACS_UINT
hash
;
ptrdiff_t
j
=
hash_lookup
(
log
,
backtrace
,
&
hash
);
if
(
j
>=
0
)
set_hash_value_slot
(
log
,
j
,
make_number
(
count
+
XINT
(
HASH_VALUE
(
log
,
j
))));
else
{
/* BEWARE! hash_put in general can allocate memory.
But currently it only does that if log->next_free is nil. */
int
j
;
eassert
(
!
NILP
(
log
->
next_free
));
j
=
hash_put
(
log
,
backtrace
,
make_number
(
count
),
hash
);
/* Let's make sure we've put `backtrace' right where it
already was to start with. */
eassert
(
index
==
j
);
/* FIXME: If the hash-table is almost full, we should set
some global flag so that some Elisp code can offload its
data elsewhere, so as to avoid the eviction code.
There are 2 ways to do that, AFAICT:
- Set a flag checked in QUIT, such that QUIT can then call
Fprofiler_cpu_log and stash the full log for later use.
- Set a flag check in post-gc-hook, so that Elisp code can call
profiler-cpu-log. That gives us more flexibility since that
Elisp code can then do all kinds of fun stuff like write
the log to disk. Or turn it right away into a call tree.
Of course, using Elisp is generally preferable, but it may
take longer until we get a chance to run the Elisp code, so
there's more risk that the table will get full before we
get there. */
}
}
}
/* Sample profiler. */
/* FIXME: Add support for the CPU profiler in W32. */
/* FIXME: the sigprof_handler suffers from race-conditions if the signal
is delivered to a thread other than the main Emacs thread. */
#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
;
/* The current sample interval in millisecond. */
static
int
current_sample_interval
;
/* Signal handler for sample profiler. */