From: Erik H. <eh...@gm...> - 2009-02-11 13:53:20
|
I've monitored the cl-bench results with respect to the latest changes for better unboxed type use. The TAK code roughly looks like this: (defun TAK (x y z) (declare (fixnum x y z)) (if (< 20 z) z (tak (tak (1+ x) y z) (tak x (1+ y) z) (tak x y (1+ z))))) What happens is this: Upon entry of the function, the variables x y z are unboxed into 'int's. Then, x and y are used exactly once in their unboxed version: in the 1+ form. The other 2 times, they're re-boxed and the boxed value is passed into the TAK invocation. For z the same is true, except that its unboxed value is used twice. What I'm trying to tell you? Well, to improve performance here, we have 2 options: * be smarter about boxing and unboxing; keeping statistics on the representation required; choosing the most-often-required representation as the default form * be smarter about argument and return-value passing: try to create functions - local functions and recursive function calls - which can receive and return unboxed values. I suppose the latter is the preferred solution as in case of the TAK example, it would allow for 3 unboxings and 1 reboxing regardless of the values passed for the arguments. If anybody is looking for a nice project to work on, this could be it. Bye, Erik. |
From: Ville V. <vil...@gm...> - 2009-02-11 15:18:44
|
On Wed, Feb 11, 2009 at 3:53 PM, Erik Huelsmann <eh...@gm...> wrote: > * be smarter about argument and return-value passing: try to create > functions - local functions and recursive function calls - which can > receive and return unboxed values. Quick question: why do we box/unbox values when calling lisp functions from within lisp? I'd think it's really necessary only when lisp code is called from java. Just wondering.. |
From: Ville V. <vil...@gm...> - 2009-02-12 06:20:57
|
On Wed, Feb 11, 2009 at 5:18 PM, Ville Voutilainen <vil...@gm...> wrote: > Quick question: why do we box/unbox values when calling lisp functions > from within lisp? I'd think it's really necessary only when lisp code is > called from java. Just wondering.. To elaborate a bit.. in case when we can inline code, we can probably see into the called code and remove type checks when they are found unnecessary. That won't work when calling already-compiled code, but it can be done for some cases. Runtime optimization of that will probably be the responsibility of JIT, but in addition to optimizing recursive cases, it's possible to optimize certain cases of normal function calls too. |
From: Erik H. <eh...@gm...> - 2009-02-12 08:30:13
|
On Wed, Feb 11, 2009 at 4:18 PM, Ville Voutilainen <vil...@gm...> wrote: > On Wed, Feb 11, 2009 at 3:53 PM, Erik Huelsmann <eh...@gm...> wrote: >> * be smarter about argument and return-value passing: try to create >> functions - local functions and recursive function calls - which can >> receive and return unboxed values. > > Quick question: why do we box/unbox values when calling lisp functions > from within lisp? I'd think it's really necessary only when lisp code is > called from java. Just wondering.. To record my answer (as given to you yesterday on IRC) for posterity and a wider interested audience (if there is any): Without declarations, we simply don't know what will be passed in. The only way to pass around generic objects is to pass around boxed values. When a function contains declaration forms, the value's type can be checked and the value can be unboxed (although nothing actually *requires* it to be unboxed). When a function is known to have arguments of specific types which can be unboxed, Ville asked then why don't we use the unboxed values? The answer is this: the fact that the values can be unboxed is probably an implementation detail in the function itself. In CL, a single function can be recompiled, meaning that other functions cannot depend on implementation details like these, unless the implementor is willing to trace back in the call graph and recompile all functions depending on this one. I don't think we should be willing to take that hit (yet). This leaves a few situations where there's nothing wrong with taking advantage of known implementation details: compilation of local funtions, for example: they will be recompiled upon recompilation of the enclosing function anyway. Another is recursive calls: when a function is calling itself recursively, it should be able to take advantage of some of its implementation details. With kind regards, Erik. |