Re: memory usage issue for double-float operations
Stas Boukarev <[email protected]> Tue, 8 Oct 2024 00:17:19 +0300
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <CAF63=11XWLDtQcffBXERDL8dqmS2nNOwa3KC9+SaiqEw02usFA@mail.gmail.com> |
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 >> > _______________________________________________ Sbcl-help mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-help