Re: memory usage issue for double-float operations
Stas Boukarev <[email protected]> Tue, 8 Oct 2024 18:24:42 +0300
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <CAF63=139Pnbr_+_KZ+cWe1vPUHN5CX0HfYx7H4Mpz94eA=AQcg@mail.gmail.com> |
It could be made to work without any intervention at all, but it's probably not a good idea to automatically generate extra entry points when not needed. ftype seems reasonable and standard, for now. On Tue, Oct 8, 2024 at 6:19 PM Michał Herda | Keepit <[email protected]> wrote: > Thanks for that optimization. One more question from me: is this going to > work automatically with *DERIVE-FUNCTION-TYPES*, or are manual ftype > proclamations still necessary in that case? > ------------------------------ > *From:* Stas Boukarev <[email protected]> > *Sent:* Tuesday, October 8, 2024 5:17 PM > *To:* Matt Kaufmann <[email protected]> > *Cc:* [email protected] <[email protected]>; > [email protected] <[email protected]> > *Subject:* Re: [Sbcl-help] memory usage issue for double-float operations > > No block compilation is needed, or any other non-standard feature. > > On Tue, Oct 8, 2024 at 6:15 PM Matt Kaufmann <[email protected]> > wrote: > > 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)] > > > > > This e-mail is sent to you from Keepit A/S. Dedicated SaaS Data Protection. > VAT: DK30806883, Per Henrik Lings Allé 4, 7., DK-2100 Copenhagen Ø, > Denmark. > > This e-mail is sent to you directly and is meant for nobody else. If the > e-mail contains personal data that Keepit is responsible for and the e-mail > was not meant for you, please do not forward, distribute, or copy, i.e. but > return the e-mail to sender. Also, do not send the e-mail to a third party > without making sure that you have our prior consent. Distribution of this > e-mail to unauthorized receivers may have legal consequences. > If you have received an e-mail from us and you don’t know why, then please > refer to our Privacy Policy <https://www.keepit.com/privacy-policy/>. > If you do not want to receive more e-mails from us, please contact > [email protected]. > _______________________________________________ Sbcl-help mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-help