Performance of ByteBuffers vs Arrays

9 views
Skip to first unread message

byhisdeeds

unread,
Feb 20, 2009, 5:13:08 AM2/20/09
to JVM Languages
I have the following code that was ported from C that copies ints from
one array to another. Can someone tell me whether they think
that I can gain any performance using another method. I use
ByteBuffers
because the data is originaly read as bytes (RGBA) and the COPY
function
rearranges the order during the copying process.


private void COPY(ByteBuffer d, ByteBuffer s, int TILE_SIZE, int I0,
int J0,
int U0, int V0, int I1, int J1, int U1, int V1, int I2, int J2, int
U2, int V2)
{
int i,j,u,v,i0,j0,u0,v0,di0,dj0,du0,dv0,di,dj,du,dv,k0,k;

IntBuffer rps = s.asIntBuffer();
IntBuffer rpd = d.asIntBuffer();
i0=I0; j0=J0; u0=U0; v0=V0;
int TS1 = TILE_SIZE-1;
di0=(I2-I0)/TS1; dj0=(J2-J0)/TS1;
du0=(U2-U0)/TS1; dv0=(V2-V0)/TS1;
di=(I1-I0)/TS1; dj=(J1-J0)/TS1;
du=(U1-U0)/TS1; dv=(V1-V0)/TS1;
for (k0=(TILE_SIZE-1);k0>=0;k0--)
{
i=i0; j=j0; u=u0; v=v0;
for (k=k0;k>=0;k--)
{
rpd.put((v>>1)*TILE_SIZE+(u>>1), rps.get(j*TILE_SIZE+i));
i+=di; j+=dj; u+=du; v+=dv;
}
i0+=di0; j0+=dj0; u0+=du0; v0+=dv0;
}
}

Rémi Forax

unread,
Feb 20, 2009, 5:15:43 AM2/20/09
to jvm-la...@googlegroups.com
byhisdeeds a écrit :

> I have the following code that was ported from C that copies ints from
> one array to another. Can someone tell me whether they think
> that I can gain any performance using another method. I use
> ByteBuffers
> because the data is originaly read as bytes (RGBA) and the COPY
> function
> rearranges the order during the copying process.
>
I don't know if there is anothert method but you can improve the
following code,
remove the two asInBuffer() because they allocate a new Java object
and use getInt()/putInt() instead of get()/put().

>
> private void COPY(ByteBuffer d, ByteBuffer s, int TILE_SIZE, int I0,
> int J0,
> int U0, int V0, int I1, int J1, int U1, int V1, int I2, int J2, int
> U2, int V2)
> {
> int i,j,u,v,i0,j0,u0,v0,di0,dj0,du0,dv0,di,dj,du,dv,k0,k;
>
> IntBuffer rps = s.asIntBuffer();
> IntBuffer rpd = d.asIntBuffer();
> i0=I0; j0=J0; u0=U0; v0=V0;
> int TS1 = TILE_SIZE-1;
> di0=(I2-I0)/TS1; dj0=(J2-J0)/TS1;
> du0=(U2-U0)/TS1; dv0=(V2-V0)/TS1;
> di=(I1-I0)/TS1; dj=(J1-J0)/TS1;
> du=(U1-U0)/TS1; dv=(V1-V0)/TS1;
> for (k0=(TILE_SIZE-1);k0>=0;k0--)
> {
> i=i0; j=j0; u=u0; v=v0;
> for (k=k0;k>=0;k--)
> {
> rpd.put((v>>1)*TILE_SIZE+(u>>1), rps.get(j*TILE_SIZE+i));
> i+=di; j+=dj; u+=du; v+=dv;
> }
> i0+=di0; j0+=dj0; u0+=du0; v0+=dv0;
> }
> }
>
Cheers,
Rémi

Bill Robertson

unread,
Feb 22, 2009, 4:58:26 AM2/22/09
to JVM Languages
All it does is copy from one buffer to the other? Have you compared
the performance against System.arraycopy()?

byhisdeeds

unread,
Feb 25, 2009, 11:40:15 AM2/25/09
to JVM Languages
On Feb 22, 4:58 am, Bill Robertson <billrobertso...@gmail.com> wrote:
> All it does is copy from one buffer to the other?  Have you compared
> the performance against System.arraycopy()?
The array indices are rearranged during the copy so I can't just use a
straight copy.

On Feb 20, 5:15 am, Rémi Forax <fo...@univ-mlv.fr> wrote:
> I don't know if there is another method but you can improve the
> following code,
> remove the two asInBuffer() because they allocate a new Java object
> and use getInt()/putInt() instead of get()/put().
I take the point and I think this will give me a little boost. I'll
post the
profile soon.

Thanks all.

John

Philip Jenvey

unread,
Feb 28, 2009, 5:39:00 PM2/28/09
to jvm-la...@googlegroups.com

On Feb 25, 2009, at 8:40 AM, byhisdeeds wrote:

>
> On Feb 20, 5:15 am, Rémi Forax <fo...@univ-mlv.fr> wrote:
>> I don't know if there is another method but you can improve the
>> following code,
>> remove the two asInBuffer() because they allocate a new Java object
>> and use getInt()/putInt() instead of get()/put().
> I take the point and I think this will give me a little boost. I'll
> post the
> profile soon.

Bill's reply allured to this -- if the ByteBuffers hasArray(), you can
access the underlying backing arrays via array().

Directly accessing the arrays avoids the bounds checking of get/put.
Don't forget to take arrayOffset() into account.

--
Philip Jenvey

Randall R Schulz

unread,
Feb 28, 2009, 5:52:19 PM2/28/09
to jvm-la...@googlegroups.com
On Saturday February 28 2009, Philip Jenvey wrote:
> On Feb 25, 2009, at 8:40 AM, byhisdeeds wrote:
> > ...

> >
> > I take the point and I think this will give me a little boost. I'll
> > post the profile soon.
>
> Bill's reply allured to this -- if the ByteBuffers hasArray(), you
> can access the underlying backing arrays via array().
>
> Directly accessing the arrays avoids the bounds checking of get/put.
> ...

The JVM still does array bounds checks, of course.


> --
> Philip Jenvey


Randall Schulz

John Cowan

unread,
Mar 2, 2009, 12:26:18 AM3/2/09
to jvm-la...@googlegroups.com
On Sat, Feb 28, 2009 at 5:52 PM, Randall R Schulz <rsc...@sonic.net> wrote:

>> Directly accessing the arrays avoids the bounds checking of get/put.
>

> The JVM still does array bounds checks, of course.

Unless they are optimized away by the JIT.

--
GMail doesn't have rotating .sigs, but you can see mine at
http://www.ccil.org/~cowan/signatures

John Rose

unread,
Mar 2, 2009, 1:59:45 AM3/2/09
to jvm-la...@googlegroups.com
On Mar 1, 2009, at 9:26 PM, John Cowan wrote:

> On Sat, Feb 28, 2009 at 5:52 PM, Randall R Schulz
> <rsc...@sonic.net> wrote:
>
>>> Directly accessing the arrays avoids the bounds checking of get/put.
>>
>> The JVM still does array bounds checks, of course.
>
> Unless they are optimized away by the JIT.

Which happens when...

I started to reply to this, as far as HotSpot is concerned, and moved
my reply here:
http://wikis.sun.com/display/HotSpotInternals/RangeCheckElimination

Enjoy!

-- John

Randall R Schulz

unread,
Mar 2, 2009, 12:42:20 PM3/2/09
to jvm-la...@googlegroups.com

Thank you for that.

Which versions of JVM include this optimization?


> Enjoy!
>
> -- John


Randall Schulz

John Rose

unread,
Mar 2, 2009, 12:46:21 PM3/2/09
to jvm-la...@googlegroups.com
It's original with the server compiler. -- John

byhisdeeds

unread,
Mar 2, 2009, 10:53:59 PM3/2/09
to JVM Languages
OK. I tried removing the IntBuffer rps = s.asIntBuffer(), and
IntBuffer rpd = d.asIntBuffer() and access the data using the original
ByteBuffer getInt and putInt code as follows.

i0=I0; j0=J0; u0=U0; v0=V0;
int TS1 = TILE_SIZE-1;
di0=(I2-I0)/TS1; dj0=(J2-J0)/TS1;
du0=(U2-U0)/TS1; dv0=(V2-V0)/TS1;
di=(I1-I0)/TS1; dj=(J1-J0)/TS1;
du=(U1-U0)/TS1; dv=(V1-V0)/TS1;
for (k0=(TILE_SIZE-1);k0>=0;k0--)
{
i=i0; j=j0; u=u0; v=v0;
for (k=k0;k>=0;k--)
{
rpd.putInt(((v>>1)*TILE_SIZE+(u>>1))<<2, rps.getInt((j*TILE_SIZE+i)
<<2));
i+=di; j+=dj; u+=du; v+=dv;
}
i0+=di0; j0+=dj0; u0+=du0; v0+=dv0;
}

Strange thing is it took longer. The average original benchmark was
161 microseconds, while the code above gave an average of 182
microseconds.
Could this be the bounds checking is worse in the bytebuffer mode for
getInt and putInt than the asIntBuffer mode. Also are u sure there is
a copy when using asIntBuffer. The tile_size in my case is 128.

I didn't try the -server flag and the application is run via java
webstart.

John
Reply all
Reply to author
Forward
0 new messages