Re: memory usage issue for double-float operations
Matt Kaufmann <[email protected]> Sun, 29 Sep 2024 16:43:58 -0500
| Newsgroups | gmane.lisp.steel-bank.general |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your replies; I'll reply to each point in turn. In short, I still don't know how to avoid consing with block compilation, for functions that return double-floats (but I know that I can use inlining or arrays). 1. I tried explicit blocks as you suggest, where before compiling I evaluated (setq *block-compile-default* :specified) to avoid a warning. But there was the same consing. I don't think the blocks are supposed to be necessary anyhow when *block-compile-default* is t. I also tried (compile-file "bar.lsp" :block-compile t :entry-points nil) but that also didn't help to avoid consing. 2. Yes, inlining works as I'd mentioned, and it may be necessary as noted by replies on this list. But I was following up on what Stas Boukarev suggested, that I "might try block compilation instead". 3. I understand that my use of THE and DECLARE may have been excessive, but it seemed harmless and I was trying to rule out the possibility of missing one that was necessary. 4. Good point, but I need to stick to double precision. Thanks, Matt Vasily Postnicov <[email protected]> writes: > [1:text/plain Hide] > > 1. There are no blocks in that file. Check CMUCL manual about it: > https://cmucl.org/docs/cmu-user/html/Block-Compilation.html > FIXME: SBCL manual has little information about it (yet). To keep it short: > you start a block with (DECLAIM (SB-EXT:START-BLOCK ...)) and end it with > (DECLAIM SB-EXT:END-BLOCK) > 2. There is no way you can avoid consing when returning a double precision > floating point number. From what DISASSEMBLE tells me, SBCL returns the > first value in RDX, and it's only 64 bits wide. It simply cannot hold a > DOUBLE-FLOAT + tag. By inlining, though, you can avoid tagging (as long as > you are inside an uninlined callee). > 3. Your use of THE and DECLARE seems to be extremely redundant. SBCL > already can guess types from FTYPE declarations. > 4. If you can, stick to single precision. A single precision number can be > stored in the upper half of RDX, and the lower half will contain the tag > (#b11001 AFAIK) > > вс, 29 сент. 2024 г., 22:27 Matt Kaufmann <[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 >> > > [2:text/html Show Save:noname (63kB)] _______________________________________________ Sbcl-help mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-help