From: Tamas K Papp on
On Thu, 29 Apr 2010 15:13:30 +0000, Peter Keller wrote:

> RG <rNOSPAMon(a)flownet.com> wrote:
>> You want a displaced (and adjustable) array.
>>
>> ? (setf a1 (make-array 30))
>> #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) ?
>> (dotimes (i 30) (setf (aref a1 i) i)) ...
>> ? a1
>> #(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
>> 26 27 28 29)
>> ? (setf a2 (make-array 10 :displaced-to a1 :displaced-index-offset 15
>> :adjustable t))
>> #(15 16 17 18 19 20 21 22 23 24)
>> ? (adjust-array a1 '(15) :displaced-to a1 :displaced-index-offset 10)
>> #(10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
>
> I see.
>
> If I knew how big the final sizes of the arrays were I could use this
> method, but sadly I don't. I'll file away the method for another day. It
> looks like under my circumstances, a new array into which I copy all of
> my disparate pieces looks to be one of the only solutions.

Sometimes I face a similar problem (collecting an number of items that
are either unknown a prior, or I am lazy to calculate). I usually
solve it the following way: create array with extra elements, keep
using them until I run out, then create a new array with a buffer of
extra elements, copy and continue. This way, you will copy
occasionally, but not all the time. Example:

(use-package '(:bind))

(defun prepend-elements (vector n &optional (extra 256))
(bind (((:values displaced-to index-offset) (array-displacement vector))
(new-length (+ n (length vector))))
(if (and displaced-to (<= n index-offset))
(make-array new-length
:displaced-index-offset (- index-offset n)
:displaced-to displaced-to)
(let ((new-vector (make-array (+ extra new-length))))
(replace new-vector vector :start1 (+ extra n))
(make-array new-length
:displaced-index-offset extra
:displaced-to new-vector)))))

(defparameter *a* #(1 2 3))
(setf *a* (prepend-elements *a* 7))
(array-displacement *a*) ; #(0 0 0 ...), 256

You can add bells and whistles, eg prepended element initialization,
etc.

Tamas
From: Peter Keller on
Tamas K Papp <tkpapp(a)gmail.com> wrote:
> Sometimes I face a similar problem (collecting an number of items that
> are either unknown a prior, or I am lazy to calculate). I usually
> solve it the following way: create array with extra elements, keep
> using them until I run out, then create a new array with a buffer of
> extra elements, copy and continue. This way, you will copy
> occasionally, but not all the time. Example:

Yeah, I thought of that. But it turns out the layering in my code base makes
that difficult to acheive.

My use case is I'm writing a master/worker style communication system
which can handle 10,000 to 50,000 clients. Buffer management for me is
a serious issue and I need to really conserve memory and not grind the
allocator too much.

The context is that when writing a data array to a client, the buffer
management layer needs to wrap a header around the data before sending it.
I thought about not doing the wrapping at all--just write the small header
then the payload, but then that leads to alternating writes of a very
small amount of data and then a large amount of data. That oscillation
sucks from a network scheduling/bandwidth perspective. I need to write
as many bytes as I can as often as I can.

If it really looks like the write buffering will be problematic from
a memory allocation point of view, I can make pools of buffers which
are reusable for the assembling of the data. I don't want to do that
initially since it is more code.

I was just wondering if I had missed something in Lisp's array management
which would allow me to grow an array at the head of the array. The
answer is somewhat yes, but I'd have to preallocate the array and that
means the application code would have to use a special abstraction of
make-array. There are problems with that I'd rather avoid.

I guess at this point, I'll just assemble the arrays naively and if the
profiler tells me there is a problem there, I'll look into it deeper.

Thank you.

-pete
From: Giovanni Gigante on

> My question is: This adjustment happens at the _end_ of the array, can I
> expand the array at the beginning?


Naive idea:
what about building a list (you can cons to the beginning of that) and
mapping it to an array only when you are done?
From: Mirko on
On Apr 29, 12:12 pm, Peter Keller <psil...(a)merlin.cs.wisc.edu> wrote:
> Tamas K Papp <tkp...(a)gmail.com> wrote:
>
> > Sometimes I face a similar problem (collecting an number of items that
> > are either unknown a prior, or I am lazy to calculate).  I usually
> > solve it the following way: create array with extra elements, keep
> > using them until I run out, then create a new array with a buffer of
> > extra elements, copy and continue.  This way, you will copy
> > occasionally, but not all the time.  Example:
>
> Yeah, I thought of that. But it turns out the layering in my code base makes
> that difficult to acheive.
>
> My use case is I'm writing a master/worker style communication system
> which can handle 10,000 to 50,000 clients. Buffer management for me is
> a serious issue and I need to really conserve memory and not grind the
> allocator too much.
>
> The context is that when writing a data array to a client, the buffer
> management layer needs to wrap a header around the data before sending it..
> I thought about not doing the wrapping at all--just write the small header
> then the payload, but then that leads to alternating writes of a very
> small amount of data and then a large amount of data. That oscillation
> sucks from a network scheduling/bandwidth perspective. I need to write
> as many bytes as I can as often as I can.
>
> If it really looks like the write buffering will be problematic from
> a memory allocation point of view, I can make pools of buffers which
> are reusable for the assembling of the data.  I don't want to do that
> initially since it is more code.
>
> I was just wondering if I had missed something in Lisp's array management
> which would allow me to grow an array at the head of the array. The
> answer is somewhat yes, but I'd have to preallocate the array and that
> means the application code would have to use a special abstraction of
> make-array. There are problems with that I'd rather avoid.
>
> I guess at this point, I'll just assemble the arrays naively and if the
> profiler tells me there is a problem there, I'll look into it deeper.
>
> Thank you.
>
> -pete

Could it be that a different data structure would be more
appropriate? What about a tree? (also, until recently, I had not
realized how many different kinds of tree there are (2-3, 2-3-4, left
leaning, etc). That would impact your access time, but in your case it
may be manageable, or you could first store in tree, and then transfer
into array.

Mirko
From: RG on
In article <4bd9afe9$0$9898$80265adb(a)spool.cs.wisc.edu>,
Peter Keller <psilord(a)merlin.cs.wisc.edu> wrote:

> Tamas K Papp <tkpapp(a)gmail.com> wrote:
> > Sometimes I face a similar problem (collecting an number of items that
> > are either unknown a prior, or I am lazy to calculate). I usually
> > solve it the following way: create array with extra elements, keep
> > using them until I run out, then create a new array with a buffer of
> > extra elements, copy and continue. This way, you will copy
> > occasionally, but not all the time. Example:
>
> Yeah, I thought of that. But it turns out the layering in my code base makes
> that difficult to acheive.
>
> My use case is I'm writing a master/worker style communication system
> which can handle 10,000 to 50,000 clients. Buffer management for me is
> a serious issue and I need to really conserve memory and not grind the
> allocator too much.
>
> The context is that when writing a data array to a client, the buffer
> management layer needs to wrap a header around the data before sending it.
> I thought about not doing the wrapping at all--just write the small header
> then the payload, but then that leads to alternating writes of a very
> small amount of data and then a large amount of data. That oscillation
> sucks from a network scheduling/bandwidth perspective. I need to write
> as many bytes as I can as often as I can.

Seems to me then that what you want is not a growable array but rather
smarter write buffering.

> If it really looks like the write buffering will be problematic from
> a memory allocation point of view, I can make pools of buffers which
> are reusable for the assembling of the data. I don't want to do that
> initially since it is more code.
>
> I was just wondering if I had missed something in Lisp's array management
> which would allow me to grow an array at the head of the array. The
> answer is somewhat yes, but I'd have to preallocate the array and that
> means the application code would have to use a special abstraction of
> make-array. There are problems with that I'd rather avoid.
>
> I guess at this point, I'll just assemble the arrays naively and if the
> profiler tells me there is a problem there, I'll look into it deeper.

That sounds like a fine plan. Premature optimization and all that.
Memcpy is pretty frickin' fast, particularly when compared to network
I/O.

rg