Re: I wonder if I'm missing something...
"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]>
| Newsgroups | gmane.lisp.lispworks.general |
|---|---|
| Message-ID | <[email protected]> |
Well, bad idea… Doing the shortcut, assuming that buffer doesn’t move under GC, seems to be incorrect. I am seeing sporadic errors that could only be attributable to the presumed buffer pointer being incorrect, and furnishing :NAN and other nasty surprises on rare occasions. > On Nov 8, 2025, at 15:18, David McClain (as dbm at refined-audiometrics dot com) <[email protected]> wrote: > > I found that by using some unmentioned details about the LWM implementation, I could avoid one whole buffer copy in the operation. The high level Lisp way uses 2 whole buffer copies - Lisp to FLI, FLI back to Lisp, to effect the transformation from byte vector to float vector. > > But here are details you aren’t supposed to care about: > > (let ((buf (make-array 1 > :element-type '(unsigned-byte 8) > :initial-element #xAA))) > (declare (dynamic-extent buf)) > (loenc:dump (sys:object-address buf) 40)) > > ____ 0 1 2 3 4 5 6 7 8 9 A B C D E F > 0000 36 2B 00 00 08 00 00 00 AA AA AA AA AA AA AA AA 6+......ªªªªªªªª > 0010 36 2B 00 00 40 01 00 00 55 55 55 55 55 55 55 55 [email protected] > 0020 55 55 55 55 55 55 55 55 UUUUUUUU > > Byte #4 shows the length of the array, here just 1 element. There must be 3 tag bits on Fixnums. But the array arena has 8 of them, all initialized to my initial element #xAA, starting at offset 8 from the object address. > > So the interesting thing is that you can’t allocate anything but chunks of memory 8 bytes long. And even though my array has only one element, the system allocated 8 of them and initialized them too. > > But the takeaway is that a simple raw array has an 8 byte prefix at the address given by SYS:OBJECT-ADDRESS. And by declaring the buffer to have DYNAMIC-EXTENT, we force the array to live on the system stack, and not move due to GC (unless the stack gets relocated….) > > So now, I can read :UINT8 bytes from a Socket stream, directly into a stack allocated octet buffer, then turn around and use the FLI:REPLACE-FOREIGN-ARRAY to convert that buffer of octets into a buffer of single-float values in just one copy operation: > > (let ((buf (make-array 16 > :element-type ‘(unsigned-byte 8)))) > (declare (dynamic-extent buf)) > (READ-SEQUENCE buf socket-stream) > (FLI:REPLACE-FOREIGN-ARRAY my-float-vec (fli:make-pointer :type :FLOAT > :address (+ 8 (SYS:OBJECT-ADDRESS buf))) > :end2 4)) > >