Re: memory usage issue for double-float operations
Matt Kaufmann <[email protected]> Tue, 08 Oct 2024 10:15:47 -0500
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <[email protected]> |
Thank you so much; very cool! Is block compilation necessary for this to work? Stas Boukarev <[email protected]> writes: > [1:text/plain Hide] > > Now unboxed returns also work. Trace works as well. The following no longer > conses: > > (declaim (type (simple-array double-float (1)) *ar*)) > > (defvar *ar* (make-array 1 > :element-type 'double-float > :initial-element 0.0d0)) > > (declaim (ftype (function (double-float) (values double-float &optional)) > f1)) > > (defun f1 (v) > (+ v v)) > > (declaim (ftype (function (double-float) *) f2)) > > (defun f2 (v) > (loop for i from 1 to 1000 > do > (setf (aref *ar* 0) (f1 v)))) > > > On Tue, Oct 8, 2024 at 12:17 AM Stas Boukarev <[email protected]> wrote: > >> I just pushed the initial attempt for unboxed arguments, so the following >> doesn't cons anymore: >> >> (declaim (ftype (function (double-float double-float) (values t >> &optional)) f)) >> >> (defun f (a b) >> (> (+ a b) 3d0)) >> >> (defun bar (n) >> (declare (fixnum n)) >> (f (* pi n) (* pi (1+ n)))) >> >> >> Not consing the return value will come in the near future. #'f works as >> expected, and incompatible redefinitions behave reasonably. trace doesn't >> yet work. >> >> On Sun, Sep 29, 2024 at 1:46 AM Stas Boukarev <[email protected]> wrote: >> >>> It could be improved in the future, but currently it's really not ready >>> for public use and may change at any time. >>> You might try block compilation instead. >>> >>> On Sun, Sep 29, 2024 at 1:37 AM Matt Kaufmann <[email protected]> >>> wrote: >>> >>>> I very much appreciate all the replies, and I think I understand. >>>> Thank you, all who replied! >>>> >>>> > > That's not directly supported by SBCL's current calling conventions. >>>> > >>>> > It is actually supported, but we don't advertise it or make it >>>> well-behaved >>>> > when misused. >>>> >>>> In our application we can arrange for every function to have a >>>> suitable ftype proclaimed before it is defined, so that double-floats >>>> are passed and returned only as indicated by the function's ftype; >>>> also, every function is defined before it is called. If these suffice >>>> to guarantee no "misuse" of support for avoiding boxing, and if there >>>> is a reasonably simple way to provide that support (like setting some >>>> global), then I'd like to know how that can work, provided that such >>>> support is likely to remain available in SBCL. >>>> >>>> Thanks, >>>> Matt >>>> Stas Boukarev <[email protected]> writes: >>>> >>>> > [1:multipart/alternative Hide] >>>> > >>>> > >>>> > [1/1:text/plain Hide] >>>> > >>>> >> That's not directly supported by SBCL's current calling conventions. >>>> > >>>> > It is actually supported, but we don't advertise it or make it >>>> well-behaved >>>> > when misused. >>>> > >>>> > On Sun, Sep 29, 2024 at 12:30 AM Christophe Rhodes <[email protected]> >>>> wrote: >>>> > >>>> >> Matt Kaufmann <[email protected]> writes: >>>> >> >>>> >> > I'd really like to avoid boxing of double-floats returned by >>>> function >>>> >> > calls. >>>> >> >>>> >> Avoiding boxing is, essentially, arranging that there be a known >>>> >> location for the callee and the caller to cooperate in writing and >>>> >> reading an unboxed return value, without risking that value being >>>> >> accidentally interpreted as a tagged lisp object pointer. >>>> >> >>>> >> That's not directly supported by SBCL's current calling conventions. >>>> >> But you can do it yourself: have your function, instead of returning a >>>> >> double-float, take as an argument a (simple-array double-float (1)), >>>> and >>>> >> write its result there; the caller can read the value from there, and >>>> >> all should happen without consing: >>>> >> >>>> >> (defun f1 (v result) >>>> >> (declare (type double-float v) >>>> >> (type (simple-array double-float (1)) result)) >>>> >> (setf (aref result 0) (+ v v)) >>>> >> (values)) >>>> >> >>>> >> (defvar *ar* (make-array 1 :element-type 'double-float)) >>>> >> (declaim (type (simple-array double-float (1)) *ar*)) >>>> >> >>>> >> (defun f2 (v) >>>> >> (let ((f1r (make-array 1 :element-type 'double-float))) >>>> >> (declare (dynamic-extent f1r)) >>>> >> (loop repeat 1000 >>>> >> do (setf (aref *ar* 0) (progn (f1 v f1r) (aref f1r 0)))))) >>>> >> >>>> >> Christophe >>>> >> >>>> >> > Below is a small example that boxes unless the function is >>>> >> > made inline. Is there, or could there be, a way to avoid boxing the >>>> >> > double-float result, other than inlining? Or should I just accept >>>> >> > that this is somehow not possible? (Thanks again, Michał "phoe" >>>> >> > Herda, for the reply; note that I've done all I could below to avoid >>>> >> > boxing inputs.) >>>> >> > >>>> >> > (declaim (optimize (compilation-speed 0) (debug 0) (speed 3) (space >>>> 0) >>>> >> > (safety 0))) >>>> >> > >>>> >> > (declaim (type (simple-array double-float (1)) *ar*)) >>>> >> > >>>> >> > (defvar *ar* (make-array '(1) >>>> >> > :element-type 'double-float >>>> >> > :initial-element 0.0d0)) >>>> >> > >>>> >> > (declaim (ftype (function (double-float) double-float) >>>> >> > f1)) >>>> >> > >>>> >> > ; (declaim (inline f1)) ; eliminates consing for (time (f2 1.0d0)) >>>> below >>>> >> > >>>> >> > (defun f1 (v) >>>> >> > (declare (type double-float v)) >>>> >> > (the double-float (+ v v))) >>>> >> > >>>> >> > (declaim (ftype (function (double-float) *) >>>> >> > f2)) >>>> >> > >>>> >> > (defun f2 (v) >>>> >> > (declare (type double-float v)) >>>> >> > (loop for i from 1 to 1000 >>>> >> > do >>>> >> > (setf (aref (the (simple-array double-float (1)) >>>> >> > *ar*) >>>> >> > 0) >>>> >> > (the double-float (f1 v))))) >>>> >> > >>>> >> > ; 32,768 bytes consed, except 0 if f1 calls are inlined: >>>> >> > (time (f2 1.0d0)) >>>> >> > >>>> >> > Matt Kaufmann <[email protected]> writes: >>>> >> > >>>> >> >> Very interesting. I expected the declare form in the defun of >>>> >> >> my-update -- >>>> >> >> >>>> >> >> (declare (type (simple-array double-float (*)) ar) >>>> >> >> (type double-float v)) >>>> >> >> >>>> >> >> -- to avoid boxing. As another experiment I added the following >>>> just >>>> >> >> before the defun of my-update -- but consing still occurred. >>>> >> >> >>>> >> >> (declaim (ftype (function ((simple-array double-float (*)) t >>>> >> double-float) >>>> >> >> double-float) >>>> >> >> my-update)) >>>> >> >> >>>> >> >> Apparently those extra efforts don't change your point about >>>> boxing, >>>> >> >> which contradicts what I thought I understood. I appreciate the >>>> help! >>>> >> >> >>>> >> >> Thanks, >>>> >> >> Matt >>>> >> >> Michał "phoe" Herda <[email protected]> writes: >>>> >> >> >>>> >> >>> Converting a double float to a function argument requires boxing, >>>> which >>>> >> >>> allocates memory. If the function is inlined, there are no >>>> arguments to >>>> >> >>> pass, so there can be no consing. >>>> >> >>> >>>> >> >>> On 26.09.2024 01:55, Matt Kaufmann wrote: >>>> >> >>>> Thanks so much! >>>> >> >>>> >>>> >> >>>> I see that suitable THE declarations also avoid consing. But >>>> >> >>>> inserting a function call can cause consing, whether using THE >>>> or your >>>> >> >>>> declaim form, as illustrated below. I'd be interested in any >>>> insights >>>> >> >>>> about why that function call causes consing. >>>> >> >>>> >>>> >> >>>> (declaim (optimize (compilation-speed 0) (debug 0) (speed 3) >>>> (space 0) >>>> >> >>>> (safety 0))) >>>> >> >>>> >>>> >> >>>> ; Optional: >>>> >> >>>> ; (declaim (type (simple-array double-float (5000)) *ar*)) >>>> >> >>>> >>>> >> >>>> (defvar *ar* (make-array '(5000) >>>> >> >>>> :element-type 'double-float >>>> >> >>>> :initial-element 0.0d0)) >>>> >> >>>> >>>> >> >>>> (loop with i of-type (integer 0 *) = 0 do >>>> >> >>>> (cond ((>= i 5000) >>>> >> >>>> (return)) >>>> >> >>>> (t (progn (setf (aref *ar* i) >>>> >> >>>> (float i 0.0d0)) >>>> >> >>>> (setq i (1+ i)))))) >>>> >> >>>> >>>> >> >>>> (defun foo (ar) >>>> >> >>>> (loop with i = 0 do >>>> >> >>>> (cond >>>> >> >>>> ((>= i 4999) ; <-- for i from 0 to 4999 ... >>>> >> >>>> (return)) >>>> >> >>>> (t (setf (aref (the (simple-array double-float (*)) ar) >>>> >> >>>> i) >>>> >> >>>> (the double-float >>>> >> >>>> (+ 1.0d0 >>>> >> >>>> (the double-float >>>> >> >>>> (aref (the (simple-array >>>> double-float >>>> >> *) ar) >>>> >> >>>> i))))) >>>> >> >>>> (setq i (1+ i)))))) >>>> >> >>>> >>>> >> >>>> (time (foo *ar*)) ; 0 bytes consed >>>> >> >>>> >>>> >> >>>> ; Optional: >>>> >> >>>> (declaim (inline my-update)) >>>> >> >>>> >>>> >> >>>> (defun my-update (ar i v) >>>> >> >>>> (declare (type (simple-array double-float (*)) ar) >>>> >> >>>> (type double-float v)) >>>> >> >>>> (setf (aref (the (simple-array double-float (*)) ar) >>>> >> >>>> i) >>>> >> >>>> v)) >>>> >> >>>> >>>> >> >>>> (defun foo2 (ar) >>>> >> >>>> (loop with i = 0 do >>>> >> >>>> (cond >>>> >> >>>> ((>= i 4999) ; <-- for i from 0 to 4999 ... >>>> >> >>>> (return)) >>>> >> >>>> (t (my-update ar >>>> >> >>>> i >>>> >> >>>> (the double-float >>>> >> >>>> (+ 1.0d0 >>>> >> >>>> (the double-float >>>> >> >>>> (aref (the (simple-array >>>> >> double-float *) >>>> >> >>>> ar) >>>> >> >>>> i))))) >>>> >> >>>> (setq i (1+ i)))))) >>>> >> >>>> >>>> >> >>>> (time (foo2 *ar*)) ; 65,536 bytes consed if not inlined, 0 >>>> otherwise >>>> >> >>>> >>>> >> >>>> Thanks, >>>> >> >>>> Matt >>>> >> >>>> Michał "phoe" Herda <[email protected]> writes: >>>> >> >>>> >>>> >> >>>>> (declaim (type (simple-array double-float (5000)) *ar*)) >>>> >> >>>>> >>>> >> >>>>> On 25.09.2024 21:44, Matt Kaufmann wrote: >>>> >> >>>>>> Hi, >>>> >> >>>>>> >>>> >> >>>>>> Is there a way to modify the example below so that the final >>>> form >>>> >> does >>>> >> >>>>>> not allocate memory in SBCL? (To be fair, I tried several >>>> other >>>> >> Lisps >>>> >> >>>>>> as well, and all of them allocated memory.) >>>> >> >>>>>> >>>> >> >>>>>> (declaim (optimize (compilation-speed 0) (debug 0) (speed 3) >>>> (space >>>> >> 0) >>>> >> >>>>>> (safety 0))) >>>> >> >>>>>> >>>> >> >>>>>> (defvar *ar* (make-array '(5000) >>>> >> >>>>>> :element-type 'double-float >>>> >> >>>>>> :initial-element 0.0d0)) >>>> >> >>>>>> >>>> >> >>>>>> (loop with i of-type (integer 0 *) = 0 do >>>> >> >>>>>> (cond ((>= i 5000) >>>> >> >>>>>> (return)) >>>> >> >>>>>> (t (progn (setf (aref *ar* i) >>>> >> >>>>>> (float i 0.0d0)) >>>> >> >>>>>> (setq i (1+ i)))))) >>>> >> >>>>>> >>>> >> >>>>>> (defun foo () >>>> >> >>>>>> (loop with i of-type fixnum = 0 do >>>> >> >>>>>> (cond >>>> >> >>>>>> ((>= i 4999) ; <-- for i from 0 to 4999 ... >>>> >> >>>>>> (return)) >>>> >> >>>>>> (t (setf (aref *ar* i) >>>> >> >>>>>> (the double-float >>>> >> >>>>>> (+ 1.0d0 >>>> >> >>>>>> (the double-float (aref *ar* i))))) >>>> >> >>>>>> (setq i (the fixnum (1+ i))))))) >>>> >> >>>>>> >>>> >> >>>>>> (time (foo)) >>>> >> >>>>>> >>>> >> >>>>>> Thanks, >>>> >> >>>>>> Matt >>>> >> >>>>>> >>>> >> >>>>>> >>>> >> >>>>>> _______________________________________________ >>>> >> >>>>>> Sbcl-help mailing list >>>> >> >>>>>> [email protected] >>>> >> >>>>>> https://lists.sourceforge.net/lists/listinfo/sbcl-help >>>> >> >> >>>> >> >> >>>> >> >> _______________________________________________ >>>> >> >> Sbcl-help mailing list >>>> >> >> [email protected] >>>> >> >> https://lists.sourceforge.net/lists/listinfo/sbcl-help >>>> >> > >>>> >> > >>>> >> > _______________________________________________ >>>> >> > Sbcl-help mailing list >>>> >> > [email protected] >>>> >> > https://lists.sourceforge.net/lists/listinfo/sbcl-help >>>> >> >>>> >> >>>> >> _______________________________________________ >>>> >> Sbcl-help mailing list >>>> >> [email protected] >>>> >> https://lists.sourceforge.net/lists/listinfo/sbcl-help >>>> >> >>>> > >>>> > [1/2:text/html Show Save:noname (38kB)] >>>> > >>>> > >>>> > [2:text/plain Hide] >>>> > >>>> > >>>> > [3:text/plain Hide] >>>> > >>>> > _______________________________________________ >>>> > Sbcl-help mailing list >>>> > [email protected] >>>> > https://lists.sourceforge.net/lists/listinfo/sbcl-help >>>> >>>> >>>> _______________________________________________ >>>> Sbcl-help mailing list >>>> [email protected] >>>> https://lists.sourceforge.net/lists/listinfo/sbcl-help >>>> >>> > > [2:text/html Show Save:noname (54kB)] _______________________________________________ Sbcl-help mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-help