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

Use byte padding to avoid fields re-ordering on JDK 15 and above #3168

Merged
merged 12 commits into from Aug 29, 2022
Merged

Use byte padding to avoid fields re-ordering on JDK 15 and above #3168

merged 12 commits into from Aug 29, 2022

Conversation

lantalex
Copy link
Contributor

@lantalex lantalex commented Aug 25, 2022

Same thing as previous PR but for 3.4.x

On modern JDK (15+) good old trick using long fields as padding is no longer reliable. To prevent false-sharing we could use byte padding

@lantalex lantalex changed the title Enhancement/improve spsc queue padding Replace 'long' padding by 'byte' padding to avoid fields re-ordering on modern JDK Aug 25, 2022
@lantalex lantalex marked this pull request as ready for review August 25, 2022 13:00
@lantalex lantalex requested a review from a team as a code owner August 25, 2022 13:00
@simonbasle simonbasle added this to the 3.4.23 milestone Aug 26, 2022
@simonbasle simonbasle added the type/enhancement A general enhancement label Aug 26, 2022
@simonbasle
Copy link
Member

simonbasle commented Aug 26, 2022

fixes #2057.

@simonbasle
Copy link
Member

@lantalex I tried to come up with a simple JOL-based test to validate the layout but it didn't fail even with original long padding in Java 17:

	@Test
	@Tag("slow")
	void objectPadding() {
		ClassLayout layout = ClassLayout.parseClass(SpscArrayQueue.class);

		AtomicLong currentPaddingSize = new AtomicLong();
		List<String> interestingFields = new ArrayList<>();

		layout.fields().forEach(f -> {
			if (f.name().startsWith("pad")) {
				currentPaddingSize.addAndGet(f.size());
			}
			else {
				if (currentPaddingSize.get() > 0) {
					interestingFields.add("padding of " + currentPaddingSize.getAndSet(0));
				}
				interestingFields.add(f.name());
			}
		});
		if (currentPaddingSize.get() > 0) {
			interestingFields.add("padding of " + currentPaddingSize.getAndSet(0));
		}

		assertThat(interestingFields).containsExactly(
			"array",
			"mask",
			"padding of 120",
			"producerIndex",
			"padding of 120",
			"consumerIndex",
			"padding of 120"
		);
	}

Compare to a similar test in another class that has padding (and could be also modified in your PR btw), QueueDrainSubscriber:

	@Test
	@Tag("slow")
	void objectPadding2() {
		ClassLayout layout = ClassLayout.parseClass(QueueDrainSubscriber.class);

		AtomicLong currentPaddingSize = new AtomicLong();
		List<String> interestingFields = new ArrayList<>();

		layout.fields().forEach(f -> {
			if (f.name().startsWith("pad")) {
				currentPaddingSize.addAndGet(f.size());
			}
			else {
				if (currentPaddingSize.get() > 0) {
					interestingFields.add("padding of " + currentPaddingSize.getAndSet(0));
				}
				interestingFields.add(f.name());
			}
		});
		if (currentPaddingSize.get() > 0) {
			interestingFields.add("padding of " + currentPaddingSize.getAndSet(0));
		}

		assertThat(interestingFields).containsExactly(
			"padding of 120",
			"wip",
			"padding of 120",
			"requested",
			"padding of 120",
			"cancelled",
			"done",
			"actual",
			"queue",
			"error"
		);
	}

which fails on Java 17, having this layout detected instead:

"wip",
        "padding of 240",
        "requested",
        "padding of 120",
        "cancelled",
        "done",
        "actual",
        "queue",
        "error"

Note that in both cases I've renamed the padding fields for better identification to all use pad prefix rather than q/p/b

Copy link
Member

@simonbasle simonbasle left a comment

Choose a reason for hiding this comment

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

looking like a good start, but see my comment in PR discussion.

in addition, I would:

  • use pad prefix instead of b
  • add the objectLayout() test (see PR comment, needs edition for 128 padding instead of 120)
  • make a similar change in QueueDrainSubscriber (using pad prefix too)
  • replace the QueueDrainSubscriber#objectLayout() test with the simplified one (see objectLayout2() in my PR comment)

@lantalex
Copy link
Contributor Author

lantalex commented Aug 26, 2022

@simonbasle
Should I revert my changes for SpscArrayQueue? Looks like long padding still works for this class, test for object layout was added (passing both for JDK17/JDK11)

@simonbasle
Copy link
Member

@lantalex nah, I'd say let's keep it that way, just in case it becomes the inspiration for a future padded class 😜

Copy link
Member

@simonbasle simonbasle left a comment

Choose a reason for hiding this comment

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

nice ! I wouldn't filter on the paddingSizes assertions but otherwise LGTM

@lantalex
Copy link
Contributor Author

lantalex commented Aug 28, 2022

Hello @simonbasle !
PR was updated. I changed a little bit SpscArrayQueueP1 padding (added extra 4 bytes) to make SpscArrayQueue object fields layout consistent on modern (JDK15+) and classic versions of JDK

@simonbasle simonbasle changed the title Replace 'long' padding by 'byte' padding to avoid fields re-ordering on modern JDK Use byte padding to avoid fields re-ordering on JDK 15 and above Aug 29, 2022
@simonbasle simonbasle merged commit ba08c27 into reactor:3.4.x Aug 29, 2022
@reactorbot
Copy link

@simonbasle this PR seems to have been merged on a maintenance branch, please ensure the change is merge-forwarded to intermediate maintenance branches and up to main 🙇

simonbasle added a commit that referenced this pull request Aug 29, 2022
@simonbasle
Copy link
Member

thanks for the PR @lantalex 🎁 🙇

@lantalex lantalex deleted the enhancement/improve_spsc_queue_padding_3_4_x branch August 29, 2022 14:51
@lantalex
Copy link
Contributor Author

thanks for the PR @lantalex gift bow

Thank you for review and fast feedback! 😀

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

Successfully merging this pull request may close these issues.

None yet

3 participants