Re: memory usage issue for double-float operations
Matt Kaufmann <[email protected]> Sun, 29 Sep 2024 14:26:42 -0500
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <[email protected]> |
Regarding: > You might try block compilation instead. Thank you for the suggestion. I tried it with the attached file bar.lsp, compiling as follows. (setq *block-compile-default* t) (compile-file "bar.lsp") I didn't understand the warning shown below; I'd appreciate any help eliminating it, or better yet, avoiding consing, because in a new session, I still get "32,768 bytes consed:" with: (load "bar.fasl") (time (f2 1.0d0)) Here's the compilation warning. ; in: DEFUN F1 ; (DEFUN F1 (V) (DECLARE (TYPE DOUBLE-FLOAT V)) (THE DOUBLE-FLOAT (+ V V))) ; --> SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA ; ==> ; #'(SB-INT:NAMED-LAMBDA F1 ; (V) ; (DECLARE (SB-C::TOP-LEVEL-FORM)) ; (DECLARE (TYPE DOUBLE-FLOAT V)) ; (BLOCK F1 (THE DOUBLE-FLOAT (+ V V)))) ; ; note: doing float to pointer coercion (cost 13) to "<return value>" Thanks, Matt Stas Boukarev <[email protected]> writes: > [1:text/plain Hide] > > 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 (49kB)] _______________________________________________ Sbcl-help mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-help
bar.lsp
(application/octet-stream, 1010 B) - not displayed