[Ecls-list] Consing source identified
Juan Jose Garcia-Ripoll
jjgarcia at users.sourceforge.net
Sun Feb 10 14:26:27 UTC 2008
Hi,
as explained in previous emails, ECL seems to be consing too much when
performing simple operations, such as invoking a method or
pretty-printing an object. Using CMUCL's newly ported library,
PROFILE, I have been able to determine the cause of consing and they
are method combinations.
When a generic function is invoked, it never translates to a function
being directly called. The lisp implementation has to create a closure
that contains a list of methods, and invokes them in some order,
determined by the kind of method-combination that this function uses.
For instance, take the simplest case
(defmethod foo ((a t))
(print a))
This is a generic function with a single method which applies to any
object. Evaluating a form such as (foo 1.0) will result in 1.0 being
printed on the terminal. How this happens, is not a simple issue.
Basically:
1) ECL determines the types of the arguments.
2) From these types, a list of potential mehods is created.
3) This list is sorted.
4) A closure function is created that contains this list.
5) The closure function is actually invoked, with the argumens of the
method: 1.0
6) The closure function calls the first method, which may then call
other methods.
Steps 1-4 are only performed the first time a method is invoked. On
later uses of this method, this closure is taken from a cache.
However, the real problem lays in 5-6). The simplest method
combination is created by (src/clos/combin.lsp)
(defun combine-method-functions (method rest-methods)
(declare (si::c-local))
#'(lambda (&rest .combined-method-args.)
(let ((*next-methods* rest-methods))
(declare (special *next-methods*))
(apply method .combined-method-args.))))
This function will almost always "cons",because it has to create the
list of arguments to the method (.combined-method-args.), and pass it
down to the actual functions that do the job.
I am currently researching different techniques to avoid building
these lists. This is done in a branch called "new_apply", to avoid
breaking ECL, but I hope development will proceed fast.
The most promising idea is to have what I call "stack frames". These
are lisp objects, allocated on the stack and with a dynamic extent,
which are similar to an adjustable array and which can be used as a
buffer to build a function call. The C code for implementing something
like (APPLY f ob1 ob2 l) would look as follows when using frames
{ECL_BUILD_STACK_FRAME(frame);
ecl_stack_frame_push(frame, ob1);
ecl_stack_frame_push(frame, ob2);
ecl_stack_frame_push_list(frame, l);
ecl_apply_from_stack_frame(frame, f);
ecl_stack_frame_close(frame);
}
Typically, frames will be created as chunks of the interpreter stack,
which are deallocated when ecl_stack_frame_close is called. Having
these objects, though, has a nice advantage, which is that they can be
passed down to other functions and used to call many different
functions with the same arguments. Thus, a standard combination would
now look as follows, with absolutely no consing in the compiled
version:
(defun combine-method-functions (method rest-methods)
(declare (si::c-local))
#'(lambda (.combined-method-args-frame.)
(let ((*next-methods* rest-methods))
(declare (special *next-methods*))
(apply-from-stack-frame method .combined-method-args-frame.))))
Development is scheduled to proceed as follows:
1) Implement stack frames and ecl_apply_from_stack_frame()
2) Rewrite cl_funcall to use stack frames
3) Rewrite cl_apply to use stack frames
4) Change the mapping functions (src/c/mapfun) to use stack frames
5) Remove cl_apply_from_stack()
6) Change the compiler to use stack frames in MULTIPLE-VALUE-CALL,
7) Change the compiler to use stack frames in function invocations
8) Rewrite method combinations using stack frames
In my tentative implementation, steps 1-7 seem already to work, though
further testing is required.
I would like to hear your ideas regarding this new implementation.
BTW, none of this code has yet been committed.
Juanjo
--
Facultad de Fisicas, Universidad Complutense,
Ciudad Universitaria s/n Madrid 28040 (Spain)
http://juanjose.garciaripoll.googlepages.com
More information about the ecl-devel
mailing list