Re: memory usage issue for double-float operations

Stas Boukarev <[email protected]> Tue, 8 Oct 2024 18:17:31 +0300
Newsgroups gmane.lisp.steel-bank.general
Message-ID <CAF63=13FCdghB2V90dbki5VXQyuGW6w59hB6td782YyR7C+fBA@mail.gmail.com>
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)]
>

_______________________________________________
Sbcl-help mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-help