HDDS-15485 Avoid ByteBuffer.wrap on ChunkBuffer.put(byte[]) path#10438
HDDS-15485 Avoid ByteBuffer.wrap on ChunkBuffer.put(byte[]) path#10438yandrey321 wants to merge 1 commit into
Conversation
|
I read the Javadoc and ByteBuffer.wrap does not copy the bytes but more like creating a view. I assume this means there is no expensive copy operation. Is the motivation for this PR about performance improvement or something else? |
I updated the description: before this change every put(byte[], offset, length ): Allocates a new ByteBuffer view (HeapByteBuffer over the same backing array). On the client write path, BlockOutputStream.write(byte[], …) calls currentBuffer.put(b, off, writeLen) once per slice that fits in the current chunk buffer. Large writes can do that many times per write() call. wrap itself is “cheap” (no array copy), but per call it still pays object allocation + dispatch into the ByteBuffer put path. On a hot path called for every slice of every write(byte[]), that cost is measurable under load. the fix is micro-optimization, but should reduce memory allocations on hot path and reduce number of objects for garbage collection. |
@yandrey321 , Could you justify the word "measurable"? In Java, we usually don't care about (short live) object allocations. Otherwise, all the classes such as String, Integer, etc cannot be used. |
Its around ~0.5-1% on the real system, in microbenchmark it shows ~7% better throughput. It also slightly reduce work for GC (hard to measure). It is not a major performance improvement but a small optimization that improves write path for a scenario when client passes a byte array. |
@yandrey321 , Please post the actual numbers and how to reproduce it. Thanks.
BTW, ByteBuffer.warp here is very similar to Java auto-boxing for primitive types; see https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html |
What changes were proposed in this pull request?
Avoid ByteBuffer.wrap on ChunkBuffer.put(byte[]) path
before this change every put(byte[], offset, length ):
Allocates a new ByteBuffer view (HeapByteBuffer over the same backing array).
Dispatches to put(ByteBuffer), which for list/incremental buffers runs a segment loop that adjusts the wrapper’s position/limit and copies via ByteBuffer.put(ByteBuffer).
On the client write path, BlockOutputStream.write(byte[], …) calls currentBuffer.put(b, off, writeLen) once per slice that fits in the current chunk buffer. Large writes can do that many times per write() call.
wrap itself is “cheap” (no array copy), but per call it still pays object allocation + dispatch into the ByteBuffer put path. On a hot path called for every slice of every write(byte[]), that cost is measurable under load.
the fix is micro-optimization, but should reduce memory allocations on hot path and reduce number of objects for garbage collection.
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-15485
How was this patch tested?
ozone freon, existing unit tests