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