Thread: 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.