java.nio.CharBuffer

View: New views
5 Messages — Rating Filter:   Alert me  

java.nio.CharBuffer

by Jeremias Maerki-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I noticed that Andreas used CharBuffer in his initial patch for #45390.
I was curious about the performance implications, so I wrote a little
micro-benchmark. The results:

Sun Java 1.4.2_16:
StringBuffer def: 6594 ms
StringBuffer 1024: 6609 ms
CharBuffer: 5250 ms

Sun Java 1.5.0_14:
StringBuffer def: 5375 ms
StringBuffer 1024: 5375 ms
CharBuffer: 5594 ms

Sun Java 6.0_03:
StringBuffer def: 2750 ms
StringBuffer 1024: 2750 ms
CharBuffer: 4719 ms

Apache Harmony r618795:
StringBuffer def: 4687 ms
StringBuffer 1024: 4672 ms
CharBuffer: 7766 ms

So this is a single-threaded test. It might perform differently in a
heavy multi-threading environment. Anyway, it looks it doesn't make much
sense to use the CharBuffer instead of the more familiar StringBuffer
for simple string concatenation. I'm sure there's a benefit in using
CharBuffer in scenarios where nio can really show its muscles.

Jeremias Maerki


CharBufferSpeedTest.java (3K) Download Attachment

Re: java.nio.CharBuffer

by Andreas Delmelle-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 14, 2008, at 08:44, Jeremias Maerki wrote:

> I noticed that Andreas used CharBuffer in his initial patch for  
> #45390.
> I was curious about the performance implications, so I wrote a little
> micro-benchmark. The results:
> <snip />
> So this is a single-threaded test. It might perform differently in a
> heavy multi-threading environment. Anyway, it looks it doesn't make  
> much
> sense to use the CharBuffer instead of the more familiar StringBuffer
> for simple string concatenation. I'm sure there's a benefit in using
> CharBuffer in scenarios where nio can really show its muscles.

Yeah, it was OK for FOText, I think, but for the smaller portions,  
it's probably more overkill...
I'll look into replacing what's unnecessary.

nio.CharBuffer is very suitable if there's a lot of bulk get() and put
() (like when removing leading white-space characters)

While implementing it in FOText, I noticed that if you use  
CharBuffer.wrap(), you actually don't even create a new char array.  
You get a CharBuffer instance that is literally wrapped around a  
portion of the parameter char array).
Unfortunately, this caused issues when I started shifting characters  
due to white-space-removal (as the char array was the very same one  
that the parser was using to store the chars from the source XML)

I did a small test myself, before committing the changes, but that  
was more focused on CharSequence.charAt() and the difference in  
timing with simple index-based array fetches (for TextLayoutManager).  
In that case, the difference was really negligeable, even for  
millions of calls/fetches, I only got a few milliseconds difference  
in total.


Cheers

Andreas


Re: java.nio.CharBuffer

by Andreas Delmelle-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 14, 2008, at 18:15, Andreas Delmelle wrote:

<snip />

Just quickly ran Jeremias' test-app myself, and on Apple JVM (1.5),  
the difference is +/-300ms for a million iterations, but not very  
consistent. Sometimes StringBuffer operates slightly faster, other  
times it's CharBuffer that wins. I guess the backing implementations  
are very closely related anyway, so it's not all that surprising.

It would most definitely be a huge overkill if it is /only/ used for  
simple String concatenation. In the context of catching SAX characters
() events, I think the penalty is bound to be limited (maybe even on  
the contrary: see below). That is, I don't think I've ever seen a  
parser that reports characters one at a time (which would make the  
current implementation using CharBuffer very slow). Most SAX parsers  
report the characters in reasonably large chunks (as much as possible).

Just for fun, make it:

...
private static final char[] prefix = {' ', 'm', 'y', 'V', 'a', 'l',  
'u', 'e', '='};
...
public String runCharBuffer() {
   CharBuffer buf = CharBuffer.allocate(1024);
   for (int i = 0; i < STEPS; i++) {
     buf.put(prefix).put(Integer.toString(i).toCharArray());
   }
   return buf.rewind().toString();
}
...

On my end, this runs noticeably faster than when passing Strings  
(almost 20%). When switching StringBuffer.append() to use char[]  
parameters, it runs a tiny bit slower than with Strings... No idea if  
this also holds for the Sun, IBM or Apache implementations.

Qua flexibility, the API for a CharBuffer (optionally) offers the  
possibility to get a reference to the backing array. For  
StringBuffer, we'd have to do something like: sb.toString
().toCharArray(), and IIC, this always yields an independent copy of  
the StringBuffer's array, not the array itself. (Note that this  
obviously also has its drawbacks; sometimes, you just /need/ an  
independent copy...)


Cheers

Andreas

Re: java.nio.CharBuffer

by Peter B. West :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Andreas Delmelle wrote:

> On Jul 14, 2008, at 18:15, Andreas Delmelle wrote:
>
> <snip />
>
> Just quickly ran Jeremias' test-app myself, and on Apple JVM (1.5), the
> difference is +/-300ms for a million iterations, but not very
> consistent. Sometimes StringBuffer operates slightly faster, other times
> it's CharBuffer that wins. I guess the backing implementations are very
> closely related anyway, so it's not all that surprising.
>
> It would most definitely be a huge overkill if it is /only/ used for
> simple String concatenation. In the context of catching SAX characters()
> events, I think the penalty is bound to be limited (maybe even on the
> contrary: see below). That is, I don't think I've ever seen a parser
> that reports characters one at a time (which would make the current
> implementation using CharBuffer very slow). Most SAX parsers report the
> characters in reasonably large chunks (as much as possible).
>
> Just for fun, make it:
>
> ...
> private static final char[] prefix = {' ', 'm', 'y', 'V', 'a', 'l', 'u',
> 'e', '='};
> ...
> public String runCharBuffer() {
>   CharBuffer buf = CharBuffer.allocate(1024);
>   for (int i = 0; i < STEPS; i++) {
>     buf.put(prefix).put(Integer.toString(i).toCharArray());
>   }
>   return buf.rewind().toString();
> }
> ...
>
> On my end, this runs noticeably faster than when passing Strings (almost
> 20%). When switching StringBuffer.append() to use char[] parameters, it
> runs a tiny bit slower than with Strings... No idea if this also holds
> for the Sun, IBM or Apache implementations.
>
> Qua flexibility, the API for a CharBuffer (optionally) offers the
> possibility to get a reference to the backing array. For StringBuffer,
> we'd have to do something like: sb.toString().toCharArray(), and IIC,
> this always yields an independent copy of the StringBuffer's array, not
> the array itself. (Note that this obviously also has its drawbacks;
> sometimes, you just /need/ an independent copy...)

Come 1.5, you get StringBuilder.

--
Peter B. West <http://cv.pbw.id.au/>
Folio <http://defoe.sourceforge.net/folio/>

Re: java.nio.CharBuffer

by Andreas Delmelle-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Jul 15, 2008, at 09:16, Peter B. West wrote:

> Andreas Delmelle wrote:
>> <snip />
> Come 1.5, you get StringBuilder.

Yep, this indeed becomes /the/ weapon of choice for building strings  
(in single-threaded context), if that's the goal.
For FOText, I don't think that is the goal. We're simply buffering  
accumulating characters there, and in that case, a CharBuffer seems  
much more appropriate (even in Java 1.5+).

Not sure what explains the drop in performance in Sun Java 1.6  
though... For Harmony, I guess the implementation has not yet been  
optimized. Understandable, especially if CharBuffer is not commonly  
used.


Cheers

Andreas
LightInTheBox - Buy quality products at wholesale price