Обсуждение: Performance tweaks
I'm running some tests with PostgreSQL 8.0, JDK 1.5.0, and the CVS head JDBC driver to see if I can squeeze some performance out of it. I'm using an old JDBCBench program (http://developer.mimer.com/features/feature_16.htm) as a test harness. It seems this program's major goal is to measure the server's response to a load, but the JDBC driver will play some part in the measurement. I was able to get over 5% increase on my setup with a few small changes. First, in PGStream, I "unrolled" SendInteger4 and SendInteger2, like this: private static final byte[] B4 = new byte[4]; public void SendInteger4(int val) throws IOException { B4[0] = (byte) ((val >> 24)&255); B4[1] = (byte) ((val >> 16)&255); B4[2] = (byte) ((val >> 8)&255); B4[3] = (byte) (val&255); pg_output.write(B4, 0, 4); } Between the two of these, I got a ~4% increase. The code is slightly uglier, but it might be worth some performance. The sneakier (and less likely to be controversial) one was also in PGStream. I changed the line byte[][] answer = new byte[l_nf][0]; to byte[][] answer = new byte[l_nf][]; This gave ~1% increase on the benchmark I was running. I'll keep you posted if I find anything else to improve. On your to-do list, I am really looking forward to the "Allow binary data transfers for all datatypes not just bytea." Ken Geis
Ken Geis wrote: > I changed the line > > byte[][] answer = new byte[l_nf][0]; > to > byte[][] answer = new byte[l_nf][]; > > This gave ~1% increase on the benchmark I was running. Gah?! What JVM? Aren't the two forms equivalent? -O
Oliver Jowett wrote: > Ken Geis wrote: > >> I changed the line >> >> byte[][] answer = new byte[l_nf][0]; >> to >> byte[][] answer = new byte[l_nf][]; >> >> This gave ~1% increase on the benchmark I was running. > > > Gah?! What JVM? Aren't the two forms equivalent? No. They aren't. The first is l_nf+1 objects being created (and array of byte[] with l_nf byte[0] entries) and the second is just a single object (an array of byte[], with null entries). Any JVM. It's the language definition. -- Alan
Oliver Jowett wrote:
> Ken Geis wrote:
>
>> I changed the line
>>
>> byte[][] answer = new byte[l_nf][0];
>> to
>> byte[][] answer = new byte[l_nf][];
>>
>> This gave ~1% increase on the benchmark I was running.
>
>
> Gah?! What JVM? Aren't the two forms equivalent?
Hmm, after some experimentation, they do produce different bytecode
(multianewarray vs. anewarray):
public void testit() {
byte[][] dummy = new byte[10][0];
byte[][] dummy2 = new byte[10][];
}
public void testit();
Code:
0: bipush 10
2: iconst_0
3: multianewarray #2, 2; //class "[[B"
7: astore_1
8: bipush 10
10: anewarray #3; //class "[B"
13: astore_2
14: return
Interesting to know it makes a performance difference. What JVM did you
test on?
-O
On Tuesday 22 February 2005 16:30, Oliver Jowett wrote:
> > I changed the line
> >
> > byte[][] answer = new byte[l_nf][0];
> > to
> > byte[][] answer = new byte[l_nf][];
> >
> > This gave ~1% increase on the benchmark I was running.
>
> Gah?! What JVM? Aren't the two forms equivalent?
javap says it's "multianewarray" vs. "anewarray":
| $ cat Test1.java
| public class Test1 {
| byte[][] answer = new byte[42][0];
| }
|
| $ cat Test2.java
| public class Test2 {
| byte[][] answer = new byte[42][];
| }
|
| $ javap -c -classpath . Test1
| Compiled from "Test1.java"
| public class Test1 extends java.lang.Object{
| byte[][] answer;
|
| public Test1();
| Code:
| 0: aload_0
| 1: invokespecial #1; //Method java/lang/Object."<init>":()V
| 4: aload_0
| 5: bipush 42
| 7: iconst_0
| 8: multianewarray #2, 2; //class "[[B"
| 12: putfield #3; //Field answer:[[B
| 15: return
|
| }
|
| $ javap -c -classpath . Test2
| Compiled from "Test2.java"
| public class Test2 extends java.lang.Object{
| byte[][] answer;
|
| public Test2();
| Code:
| 0: aload_0
| 1: invokespecial #1; //Method java/lang/Object."<init>":()V
| 4: aload_0
| 5: bipush 42
| 7: anewarray #2; //class "[B"
| 10: putfield #3; //Field answer:[[B
| 13: return
|
| }
Alan Stange wrote: > Oliver Jowett wrote: > >> Ken Geis wrote: >> >>> byte[][] answer = new byte[l_nf][0]; >>> to >>> byte[][] answer = new byte[l_nf][]; >> >> Gah?! What JVM? Aren't the two forms equivalent? > > No. They aren't. > > The first is l_nf+1 objects being created (and array of byte[] with l_nf > byte[0] entries) and the second is just a single object (an array of > byte[], with null entries). > > Any JVM. It's the language definition. Ah, right. The Java multidimensional-array stuff always makes my head hurt.. The change seems obviously better, then, since we promptly go and replace all the top-level array entries with new values. -O
Ken Geis wrote:
> First, in PGStream, I "unrolled" SendInteger4 and SendInteger2, like this:
>
> private static final byte[] B4 = new byte[4];
> public void SendInteger4(int val) throws IOException
> {
> B4[0] = (byte) ((val >> 24)&255);
> B4[1] = (byte) ((val >> 16)&255);
> B4[2] = (byte) ((val >> 8)&255);
> B4[3] = (byte) (val&255);
> pg_output.write(B4, 0, 4);
> }
This isn't safe across multiple PGStreams. Can you try benchmarking
again with "private final" instead of "private static final"? If that's
still a win it is probably worth changing.
-O
Ken Geis wrote: > The sneakier (and less > likely to be controversial) one was also in PGStream. I changed the line > > byte[][] answer = new byte[l_nf][0]; > to > byte[][] answer = new byte[l_nf][]; > > This gave ~1% increase on the benchmark I was running. I have applied this change (and some surrounding rearrangements to avoid an assignment in the null case, since the initial elements are already null) to CVS HEAD. -O
Oliver Jowett wrote:
> Ken Geis wrote:
>
>> First, in PGStream, I "unrolled" SendInteger4 and SendInteger2, like
>> this:
>>
>> private static final byte[] B4 = new byte[4];
>> public void SendInteger4(int val) throws IOException
>> {
>> B4[0] = (byte) ((val >> 24)&255);
>> B4[1] = (byte) ((val >> 16)&255);
>> B4[2] = (byte) ((val >> 8)&255);
>> B4[3] = (byte) (val&255);
>> pg_output.write(B4, 0, 4);
>> }
>
>
> This isn't safe across multiple PGStreams. Can you try benchmarking
> again with "private final" instead of "private static final"? If that's
> still a win it is probably worth changing.
I missed that glaringly obvious point!
My computer is tied up right now in a computational task. I'll get back
to you tomorrow.
Oliver Jowett wrote:
> Ken Geis wrote:
>
>> First, in PGStream, I "unrolled" SendInteger4 and SendInteger2, like
>> this:
>>
>> private static final byte[] B4 = new byte[4];
>> public void SendInteger4(int val) throws IOException
>> {
>> B4[0] = (byte) ((val >> 24)&255);
>> B4[1] = (byte) ((val >> 16)&255);
>> B4[2] = (byte) ((val >> 8)&255);
>> B4[3] = (byte) (val&255);
>> pg_output.write(B4, 0, 4);
>> }
>
>
> This isn't safe across multiple PGStreams. Can you try benchmarking
> again with "private final" instead of "private static final"? If that's
> still a win it is probably worth changing.
I tested it more rigorously with this change. Not a win.