Primitive to crop a ByteArray?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Primitive to crop a ByteArray?

Mariano Martinez Peck
 
Hi guys. I have the following scenario. I have a buffer (ByteArray)
that I pass by FFI to a function of size N. This function puts data in
the array and answers me the M number of bytes that it put. M <= N.
Finally, I need to copy the array of size N to the accuare size M.
To do that, I am using #copyFrom:to:. If the ByteArray is large (which
could be the case), this function takes significant time because it
needs to allocate space for the new large resulting array. So...is
there a destructive primitive where I can "crop" the existing array,
modify its size field and mark the remaining bytes as "free space for
the heap".

Do we have a primitive for that?

Thanks,

--
Mariano
http://marianopeck.wordpress.com
Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Bert Freudenberg

On 2012-11-08, at 16:22, Mariano Martinez Peck <[hidden email]> wrote:

> Hi guys. I have the following scenario. I have a buffer (ByteArray)
> that I pass by FFI to a function of size N. This function puts data in
> the array and answers me the M number of bytes that it put. M <= N.
> Finally, I need to copy the array of size N to the accuare size M.
> To do that, I am using #copyFrom:to:. If the ByteArray is large (which
> could be the case), this function takes significant time because it
> needs to allocate space for the new large resulting array. So...is
> there a destructive primitive where I can "crop" the existing array,
> modify its size field and mark the remaining bytes as "free space for
> the heap".
>
> Do we have a primitive for that?

We do not have any primitive that changes an object's size.

However, if your problem is indeed the time for allocating the new array, then maybe there should be a primitive for that? E.g. one that copies a portion of one array to a new object. This would avoid having to initialize the memory of the new array - this is what's taking time, otherwise allocation is normally constant in time.

OTOH it seems unusual that you would have to use extremely large buffers where initialization time matters. E.g. if you were to use this for reading from a file or stream then it might make more sense to use many smaller buffers rather than a single huge one, no?

- Bert -

Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Mariano Martinez Peck

On Thu, Nov 8, 2012 at 4:38 PM, Bert Freudenberg <[hidden email]> wrote:

>
> On 2012-11-08, at 16:22, Mariano Martinez Peck <[hidden email]> wrote:
>
>> Hi guys. I have the following scenario. I have a buffer (ByteArray)
>> that I pass by FFI to a function of size N. This function puts data in
>> the array and answers me the M number of bytes that it put. M <= N.
>> Finally, I need to copy the array of size N to the accuare size M.
>> To do that, I am using #copyFrom:to:. If the ByteArray is large (which
>> could be the case), this function takes significant time because it
>> needs to allocate space for the new large resulting array. So...is
>> there a destructive primitive where I can "crop" the existing array,
>> modify its size field and mark the remaining bytes as "free space for
>> the heap".
>>
>> Do we have a primitive for that?
>
> We do not have any primitive that changes an object's size.

:(

>
> However, if your problem is indeed the time for allocating the new array, then maybe there should be a primitive for that? E.g. one that copies a portion of one array to a new object. This would avoid having to initialize the memory of the new array - this is what's taking time, otherwise allocation is normally constant in time.
>
> OTOH it seems unusual that you would have to use extremely large buffers where initialization time matters. E.g. if you were to use this for reading from a file or stream then it might make more sense to use many smaller buffers rather than a single huge one, no?
>

Hi Bert. I should have explained better. The library I am wrapping is
LZ4, a fast compressor: http://code.google.com/p/lz4/
The function to compress looks like this:

int LZ4_compress   (const char* source, char* dest, int isize);

/*
LZ4_compress() :
    Compresses 'isize' bytes from 'source' into 'dest'.
    Destination buffer must be already allocated,
    and must be sized to handle worst cases situations (input data not
compressible)
    Worst case size evaluation is provided by macro LZ4_compressBound()

    isize  : is the input size. Max supported value is ~1.9GB
    return : the number of bytes written in buffer dest


So, from the image side, I am doing (summarized):

dest := ByteArray new: (self funcCompressBound: aByteArray size) + 4.
bytesCompressedOrError := self funcCompress: aByteArray
byteArrayDestination: dest isize: aByteArray size maxOutputSize:
maxOutputSize .
compressed := dest copyFrom: 1 to: bytesCompressedOrError + 4.

But a normal scenario of compression is when the bytearray is indeed
quite large. The function requires that "dest" is already allocated.
And then I need to do the #copyFrom:to:, and that is what I was trying
to avoid.


> - Bert -
>



--
Mariano
http://marianopeck.wordpress.com
Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Mariano Martinez Peck

On Thu, Nov 8, 2012 at 4:48 PM, Mariano Martinez Peck
<[hidden email]> wrote:

> On Thu, Nov 8, 2012 at 4:38 PM, Bert Freudenberg <[hidden email]> wrote:
>>
>> On 2012-11-08, at 16:22, Mariano Martinez Peck <[hidden email]> wrote:
>>
>>> Hi guys. I have the following scenario. I have a buffer (ByteArray)
>>> that I pass by FFI to a function of size N. This function puts data in
>>> the array and answers me the M number of bytes that it put. M <= N.
>>> Finally, I need to copy the array of size N to the accuare size M.
>>> To do that, I am using #copyFrom:to:. If the ByteArray is large (which
>>> could be the case), this function takes significant time because it
>>> needs to allocate space for the new large resulting array. So...is
>>> there a destructive primitive where I can "crop" the existing array,
>>> modify its size field and mark the remaining bytes as "free space for
>>> the heap".
>>>
>>> Do we have a primitive for that?
>>
>> We do not have any primitive that changes an object's size.
>
> :(
>
>>
>> However, if your problem is indeed the time for allocating the new array, then maybe there should be a primitive for that? E.g. one that copies a portion of one array to a new object. This would avoid having to initialize the memory of the new array - this is what's taking time, otherwise allocation is normally constant in time.
>>
>> OTOH it seems unusual that you would have to use extremely large buffers where initialization time matters. E.g. if you were to use this for reading from a file or stream then it might make more sense to use many smaller buffers rather than a single huge one, no?
>>
>
> Hi Bert. I should have explained better. The library I am wrapping is
> LZ4, a fast compressor: http://code.google.com/p/lz4/
> The function to compress looks like this:
>
> int LZ4_compress   (const char* source, char* dest, int isize);
>
> /*
> LZ4_compress() :
>     Compresses 'isize' bytes from 'source' into 'dest'.
>     Destination buffer must be already allocated,
>     and must be sized to handle worst cases situations (input data not
> compressible)
>     Worst case size evaluation is provided by macro LZ4_compressBound()
>
>     isize  : is the input size. Max supported value is ~1.9GB
>     return : the number of bytes written in buffer dest
>
>
> So, from the image side, I am doing (summarized):
>
> dest := ByteArray new: (self funcCompressBound: aByteArray size) + 4.
> bytesCompressedOrError := self funcCompress: aByteArray
> byteArrayDestination: dest isize: aByteArray size maxOutputSize:
> maxOutputSize .
> compressed := dest copyFrom: 1 to: bytesCompressedOrError + 4.
>
> But a normal scenario of compression is when the bytearray is indeed
> quite large. The function requires that "dest" is already allocated.
> And then I need to do the #copyFrom:to:, and that is what I was trying
> to avoid.
>
>

maybe there is something faster than #copyFrom:to:  for this case?

>> - Bert -
>>
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com



--
Mariano
http://marianopeck.wordpress.com
Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Bert Freudenberg


On 08.11.2012, at 22:42, Mariano Martinez Peck <[hidden email]> wrote:

>
> On Thu, Nov 8, 2012 at 4:48 PM, Mariano Martinez Peck
> <[hidden email]> wrote:
>> On Thu, Nov 8, 2012 at 4:38 PM, Bert Freudenberg <[hidden email]> wrote:
>>>
>>> On 2012-11-08, at 16:22, Mariano Martinez Peck <[hidden email]> wrote:
>>>
>>>> Hi guys. I have the following scenario. I have a buffer (ByteArray)
>>>> that I pass by FFI to a function of size N. This function puts data in
>>>> the array and answers me the M number of bytes that it put. M <= N.
>>>> Finally, I need to copy the array of size N to the accuare size M.
>>>> To do that, I am using #copyFrom:to:. If the ByteArray is large (which
>>>> could be the case), this function takes significant time because it
>>>> needs to allocate space for the new large resulting array. So...is
>>>> there a destructive primitive where I can "crop" the existing array,
>>>> modify its size field and mark the remaining bytes as "free space for
>>>> the heap".
>>>>
>>>> Do we have a primitive for that?
>>>
>>> We do not have any primitive that changes an object's size.
>>
>> :(
>>
>>>
>>> However, if your problem is indeed the time for allocating the new array, then maybe there should be a primitive for that? E.g. one that copies a portion of one array to a new object. This would avoid having to initialize the memory of the new array - this is what's taking time, otherwise allocation is normally constant in time.
>>>
>>> OTOH it seems unusual that you would have to use extremely large buffers where initialization time matters. E.g. if you were to use this for reading from a file or stream then it might make more sense to use many smaller buffers rather than a single huge one, no?
>>
>> Hi Bert. I should have explained better. The library I am wrapping is
>> LZ4, a fast compressor: http://code.google.com/p/lz4/
>> The function to compress looks like this:
>>
>> int LZ4_compress   (const char* source, char* dest, int isize);
>>
>> /*
>> LZ4_compress() :
>>    Compresses 'isize' bytes from 'source' into 'dest'.
>>    Destination buffer must be already allocated,
>>    and must be sized to handle worst cases situations (input data not
>> compressible)
>>    Worst case size evaluation is provided by macro LZ4_compressBound()
>>
>>    isize  : is the input size. Max supported value is ~1.9GB
>>    return : the number of bytes written in buffer dest
>>
>>
>> So, from the image side, I am doing (summarized):
>>
>> dest := ByteArray new: (self funcCompressBound: aByteArray size) + 4.
>> bytesCompressedOrError := self funcCompress: aByteArray
>> byteArrayDestination: dest isize: aByteArray size maxOutputSize:
>> maxOutputSize .
>> compressed := dest copyFrom: 1 to: bytesCompressedOrError + 4.
>>
>> But a normal scenario of compression is when the bytearray is indeed
>> quite large. The function requires that "dest" is already allocated.
>> And then I need to do the #copyFrom:to:, and that is what I was trying
>> to avoid.
>
> maybe there is something faster than #copyFrom:to:  for this case?

Not yet. There was a discussion some time ago to add an "uninitialized allocation" primitive (i.e. a ByteArray/WordArray not initialized to 0) but I think we didn't follow up on that.

Are you actually keeping that huge array in memory? If not, e.g you are sending it to disk or network, then just keeping a count around (like OrderedCollection), or putting it into a read stream) would suffice.

- Bert -
Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Levente Uzonyi-2
In reply to this post by Mariano Martinez Peck
 
On Thu, 8 Nov 2012, Mariano Martinez Peck wrote:

>
> On Thu, Nov 8, 2012 at 4:48 PM, Mariano Martinez Peck
> <[hidden email]> wrote:
>> On Thu, Nov 8, 2012 at 4:38 PM, Bert Freudenberg <[hidden email]> wrote:
>>>
>>> On 2012-11-08, at 16:22, Mariano Martinez Peck <[hidden email]> wrote:
>>>
>>>> Hi guys. I have the following scenario. I have a buffer (ByteArray)
>>>> that I pass by FFI to a function of size N. This function puts data in
>>>> the array and answers me the M number of bytes that it put. M <= N.
>>>> Finally, I need to copy the array of size N to the accuare size M.
>>>> To do that, I am using #copyFrom:to:. If the ByteArray is large (which
>>>> could be the case), this function takes significant time because it
>>>> needs to allocate space for the new large resulting array. So...is
>>>> there a destructive primitive where I can "crop" the existing array,
>>>> modify its size field and mark the remaining bytes as "free space for
>>>> the heap".
>>>>
>>>> Do we have a primitive for that?
>>>
>>> We do not have any primitive that changes an object's size.
>>
>> :(
>>
>>>
>>> However, if your problem is indeed the time for allocating the new array, then maybe there should be a primitive for that? E.g. one that copies a portion of one array to a new object. This would avoid having to initialize the memory of the new array - this is what's taking time, otherwise allocation is normally constant in time.
>>>
>>> OTOH it seems unusual that you would have to use extremely large buffers where initialization time matters. E.g. if you were to use this for reading from a file or stream then it might make more sense to use many smaller buffers rather than a single huge one, no?
>>>
>>
>> Hi Bert. I should have explained better. The library I am wrapping is
>> LZ4, a fast compressor: http://code.google.com/p/lz4/
>> The function to compress looks like this:
>>
>> int LZ4_compress   (const char* source, char* dest, int isize);
>>
>> /*
>> LZ4_compress() :
>>     Compresses 'isize' bytes from 'source' into 'dest'.
>>     Destination buffer must be already allocated,
>>     and must be sized to handle worst cases situations (input data not
>> compressible)
>>     Worst case size evaluation is provided by macro LZ4_compressBound()
>>
>>     isize  : is the input size. Max supported value is ~1.9GB
>>     return : the number of bytes written in buffer dest
>>
>>
>> So, from the image side, I am doing (summarized):
>>
>> dest := ByteArray new: (self funcCompressBound: aByteArray size) + 4.
>> bytesCompressedOrError := self funcCompress: aByteArray
>> byteArrayDestination: dest isize: aByteArray size maxOutputSize:
>> maxOutputSize .
>> compressed := dest copyFrom: 1 to: bytesCompressedOrError + 4.
>>
>> But a normal scenario of compression is when the bytearray is indeed
>> quite large. The function requires that "dest" is already allocated.
>> And then I need to do the #copyFrom:to:, and that is what I was trying
>> to avoid.
>>
>>
>
> maybe there is something faster than #copyFrom:to:  for this case?

Do you think #copyFrom:to: is slow because it shows up in the profiler? If
yes, then try running the same code without calling the compression
function to see how "slow" #copyFrom:to: really is.
Also, calling #funcCompressBound: is just silly. Reimplement it in
Smalltalk, it's easy and probably more efficient.
If it turns out that it's really #copyFrom:to: what's slow, then consider
compressing your data in smaller chunks (at most a few MiB each). In this
case you can even precalculate the upper bound.


Levente

P.S.: And please don't propose VM changes for such a marginal issue.
P.P.S.: I still doubt that using LZ4 will give you any benefit.


>
>>> - Bert -
>>>
>>
>>
>>
>> --
>> Mariano
>> http://marianopeck.wordpress.com
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>
Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Igor Stasenko
In reply to this post by Bert Freudenberg

On 8 November 2012 19:51, Bert Freudenberg <[hidden email]> wrote:

>
>
> On 08.11.2012, at 22:42, Mariano Martinez Peck <[hidden email]> wrote:
>
>>
>> On Thu, Nov 8, 2012 at 4:48 PM, Mariano Martinez Peck
>> <[hidden email]> wrote:
>>> On Thu, Nov 8, 2012 at 4:38 PM, Bert Freudenberg <[hidden email]> wrote:
>>>>
>>>> On 2012-11-08, at 16:22, Mariano Martinez Peck <[hidden email]> wrote:
>>>>
>>>>> Hi guys. I have the following scenario. I have a buffer (ByteArray)
>>>>> that I pass by FFI to a function of size N. This function puts data in
>>>>> the array and answers me the M number of bytes that it put. M <= N.
>>>>> Finally, I need to copy the array of size N to the accuare size M.
>>>>> To do that, I am using #copyFrom:to:. If the ByteArray is large (which
>>>>> could be the case), this function takes significant time because it
>>>>> needs to allocate space for the new large resulting array. So...is
>>>>> there a destructive primitive where I can "crop" the existing array,
>>>>> modify its size field and mark the remaining bytes as "free space for
>>>>> the heap".
>>>>>
>>>>> Do we have a primitive for that?
>>>>
>>>> We do not have any primitive that changes an object's size.
>>>
>>> :(
>>>
>>>>
>>>> However, if your problem is indeed the time for allocating the new array, then maybe there should be a primitive for that? E.g. one that copies a portion of one array to a new object. This would avoid having to initialize the memory of the new array - this is what's taking time, otherwise allocation is normally constant in time.
>>>>
>>>> OTOH it seems unusual that you would have to use extremely large buffers where initialization time matters. E.g. if you were to use this for reading from a file or stream then it might make more sense to use many smaller buffers rather than a single huge one, no?
>>>
>>> Hi Bert. I should have explained better. The library I am wrapping is
>>> LZ4, a fast compressor: http://code.google.com/p/lz4/
>>> The function to compress looks like this:
>>>
>>> int LZ4_compress   (const char* source, char* dest, int isize);
>>>
>>> /*
>>> LZ4_compress() :
>>>    Compresses 'isize' bytes from 'source' into 'dest'.
>>>    Destination buffer must be already allocated,
>>>    and must be sized to handle worst cases situations (input data not
>>> compressible)
>>>    Worst case size evaluation is provided by macro LZ4_compressBound()
>>>
>>>    isize  : is the input size. Max supported value is ~1.9GB
>>>    return : the number of bytes written in buffer dest
>>>
>>>
>>> So, from the image side, I am doing (summarized):
>>>
>>> dest := ByteArray new: (self funcCompressBound: aByteArray size) + 4.
>>> bytesCompressedOrError := self funcCompress: aByteArray
>>> byteArrayDestination: dest isize: aByteArray size maxOutputSize:
>>> maxOutputSize .
>>> compressed := dest copyFrom: 1 to: bytesCompressedOrError + 4.
>>>
>>> But a normal scenario of compression is when the bytearray is indeed
>>> quite large. The function requires that "dest" is already allocated.
>>> And then I need to do the #copyFrom:to:, and that is what I was trying
>>> to avoid.
>>
>> maybe there is something faster than #copyFrom:to:  for this case?
>
> Not yet. There was a discussion some time ago to add an "uninitialized allocation" primitive (i.e. a ByteArray/WordArray not initialized to 0) but I think we didn't follow up on that.
>
> Are you actually keeping that huge array in memory? If not, e.g you are sending it to disk or network, then just keeping a count around (like OrderedCollection), or putting it into a read stream) would suffice.
>

right, i also said that to Mariano: usually you split data on smaller
chunks and compress them.
And the compressed output you pipe to output stream.
So, yes, you can't avoid copying things around (because of piping to stream)..
but you cannot squeeze out of it much at this point.
And since you using stream, you don't really need to crop anything.

> - Bert -



--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: Primitive to crop a ByteArray?

Andreas.Raab
Igor Stasenko wrote
right, i also said that to Mariano: usually you split data on smaller
chunks and compress them.
And the compressed output you pipe to output stream.
So, yes, you can't avoid copying things around (because of piping to stream)..
but you cannot squeeze out of it much at this point.
And since you using stream, you don't really need to crop anything.
Plus, unless the estimate is wildly wrong you can just wrap your result into a stream; say:

  compressed := ReadWriteStream on: dest from: 1 to: bytesCompressedOrError + 4.

Cheers,
  - Andreas