Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize writing numeric values. #1635

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

vbabanin
Copy link
Member

@vbabanin vbabanin commented Feb 20, 2025

Summary

This PR improves BSON encoding by replacing byte manipulations and bound checks with ByteBuffer’s optimized methods (putInt, putLong, putDouble). These methods are optimized for bulk operations and often intrinsified by the JVM using efficient CPU opcodes, leading to reduced overhead and better performance.

Key Changes:

  • Reduces constant factor of buffer lookups in writeInt32(int absolutePosition, int value) from 4 to 1 by preferring a single putInt call when capacity allows, minimizing overhead. Adds a fallback for edge cases (e.g., buffer boundaries) with O(1) buffer switches instead of repeated O(n) lookups.
  • Interface Extensions: Adds putInt(int), putInt(int, int), putDouble(double), and putLong(long) to ByteBuf, implemented in ByteBufNIO and NettyByteBuf, with no-op stubs in CompositeByteBuf.
  • Updates ByteBufferBsonOutput to: Use putInt, putLong, and putDouble for single-call writes when capacity allows, reducing overhead.

Performance analysis

To ensure accurate performance comparison and reduce noise, 11 versions (Comparison Versions) were aggregated and compared against a stable region of data around the Base Mainline Version. The percentage difference and z-score of the mean of the Comparison Versions were calculated relative to the Base Mainline Version’s stable region mean.

Test Base Stable Mean (ops/sec) Comparison Versions Mean (ops/sec) Diff Z-Score
Deep BSON Encoding 47.45 60.15 +26.8% 5.02
Flat BSON Encoding 104.94 131.79 +25.6% 1.33
Full BSON Encoding 110.44 141.49 +28.1% 1.98
Large Doc Bulk Insert 46.53 64.59 +38.8% 3.44
Large Doc InsertOne 50.38 67.20 +33.4% 3.07
Small Doc Bulk Insert 25.07 30.08 +20.0% 3.19

Perf analyzer results: Link

JAVA-5800

@vbabanin vbabanin changed the title Optimize writing numeric values with putInt, putLong, and putDouble. Optimize writing numeric values/ Feb 20, 2025
@vbabanin vbabanin changed the title Optimize writing numeric values/ Optimize writing numeric values. Feb 20, 2025
@vbabanin vbabanin self-assigned this Feb 20, 2025
@franz1981
Copy link

I like this, it looks similar to my PR at #1629 which try writing byte per byte if there is available space to straight use the same buffer ❤️

* @throws java.nio.BufferOverflowException if there are fewer than 4 bytes remaining in this buffer
* @throws java.nio.ReadOnlyBufferException if this buffer is read-only
*/
ByteBuf putInt(int b);
Copy link
Member Author

@vbabanin vbabanin Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the interface includes the warning:

This interface is not frozen yet, and methods may be added in a minor release, so beware implementing this yourself we are justified in adding new methods to this class.

it is permissible to add new methods to this class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @since to the javadoc for all the new methods.

@vbabanin vbabanin requested a review from rozza March 5, 2025 07:12
Copy link
Member

@rozza rozza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the changes - just a couple of nits.

* @throws java.nio.BufferOverflowException if there are fewer than 4 bytes remaining in this buffer
* @throws java.nio.ReadOnlyBufferException if this buffer is read-only
*/
ByteBuf putInt(int b);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @since to the javadoc for all the new methods.

class ByteBufTest {

static Stream<BufferProvider> bufferProviders() {
return Stream.of(new ByteBufSpecification.NettyBufferProvider(), new SimpleBufferProvider());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@vbabanin vbabanin marked this pull request as ready for review March 6, 2025 15:36
vbabanin and others added 4 commits March 6, 2025 12:38
…rBsonOutput.java

Co-authored-by: Ross Lawley <ross.lawley@gmail.com>
…rBsonOutput.java

Co-authored-by: Ross Lawley <ross.lawley@gmail.com>
…rBsonOutput.java

Co-authored-by: Ross Lawley <ross.lawley@gmail.com>
@vbabanin vbabanin requested a review from rozza March 6, 2025 22:04
Copy link
Collaborator

@jyemin jyemin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran ByteBufferBsonOutputTest with Coverage, and noticed that ByteBufferBsonOutput#write(int absolutePosition, int value) is no longer covered by test due to the optimizations that were introduced. This method should either be covered by tests or removed (it seems like it will never be called)

Here's one way to do it: https://github.com/jyemin/mongo-java-driver/pull/new/jeff-wip

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] As @stIncMale suggested, lets put Evolving annotation here.

Copy link
Member

@rozza rozza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good - just javadocs and jeffs comment to address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants