This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push: new 4e84ba3728 ByteBufferLib: use bulk get/put APIs new 4933549244 Merge pull request #1800 from lucasvr/main 4e84ba3728 is described below commit 4e84ba3728746e5d40c8892e09177887bf62d467 Author: Lucas C. Villa Real <luca...@gmail.com> AuthorDate: Thu Mar 16 12:02:52 2023 -0300 ByteBufferLib: use bulk get/put APIs CPU profiling of a brand new installation of jena-fuseki shows that ~75% of the time spent by `s-put` (when ingesting Turtle tuples via SPARQL) relates to the execution of `ByteBufferLib.bbcopy2()` -- often as part of B+tree operations such as `BPTreeNode.internalDelete()`. `bbcopy2()` and `bbcopy1()` perform data copy from a source ByteBuffer to a destination ByteBuffer by reading/writing one byte at a time, which is not very efficient. In addition, `bbcopy1()` makes a poor use of data cache prefetches, as it iterates the ByteBuffers in reverse order. This commit replaces the implementation of these two functions by one that reads the input data in bulk mode into a dynamically allocated byte array and then writes its contents to the destination buffer using a bulk `put()` operation. The speedup gains introduced by these code changes are consistent regardless of the number of triples being ingested into Jena: Input file: 1.2GB with 1.75M triples Original ingestion time: 544 secs After changes to bbcopy: 454 secs (1.19x speedup) Input file: 21MB with 154k triples Original ingestion time: 7.4 secs After changes to bbcopy: 6.0 secs (1.24x speedup) Refs #1800 --- .../org/apache/jena/atlas/lib/ByteBufferLib.java | 42 ++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/jena-base/src/main/java/org/apache/jena/atlas/lib/ByteBufferLib.java b/jena-base/src/main/java/org/apache/jena/atlas/lib/ByteBufferLib.java index 54a542a169..42714491a0 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/lib/ByteBufferLib.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/lib/ByteBufferLib.java @@ -122,28 +122,24 @@ public class ByteBufferLib { return ; } - if ( src < dst ) - bbcopy1(bb, src, dst, length, slotLen) ; - else - bbcopy2(bb, src, dst, length, slotLen) ; + bbcopyBulk(bb, src, dst, length, slotLen) ; } - private final static void bbcopy1(ByteBuffer bb, int src, int dst, int length, int slotLen) { + private final static void bbcopyBulk(ByteBuffer bb, int src, int dst, int length, int slotLen) { int bDst = dst * slotLen ; int bSrc = src * slotLen ; int bLen = length * slotLen ; - // src < dst so top dst is not in the overlap : work backwards - for ( int i = bLen - 1 ; i >= 0 ; i-- ) - bb.put(bDst + i, bb.get(bSrc + i)) ; - } - private final static void bbcopy2(ByteBuffer bb, int src, int dst, int length, int slotLen) { - int bDst = dst * slotLen ; - int bSrc = src * slotLen ; - int bLen = length * slotLen ; - // src > dst so dst[0] is not in the overlap - for ( int i = 0 ; i < bLen ; i++ ) - bb.put(bDst + i, bb.get(bSrc + i)) ; + byte[] srcBytes = new byte[bLen]; + + int pos = bb.position(); + bb.position(bSrc); + bb.get(srcBytes, 0, bLen); + + bb.position(bDst); + bb.put(srcBytes, 0, bLen); + bb.position(pos); + } public final static void bbcopy(ByteBuffer bb1, int src, ByteBuffer bb2, int dst, int length, int slotLen) { @@ -158,8 +154,18 @@ public class ByteBufferLib { int bDst = dst * slotLen ; int bLen = length * slotLen ; - for ( int i = 0 ; i < bLen ; i++ ) - bb2.put(bDst + i, bb1.get(bSrc + i)) ; + // Use bulk get/put to speed up data copy + byte[] srcBytes = new byte[bLen]; + + int pos1 = bb1.position(); + bb1.position(bSrc); + bb1.get(srcBytes, 0, bLen); + bb1.position(pos1); + + int pos2 = bb2.position(); + bb2.position(bDst); + bb2.put(srcBytes, 0, bLen); + bb2.position(pos2); } final public static void bbfill(ByteBuffer bb, int fromIdx, int toIdx, byte fillValue, int slotLen) {