Skip to content

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

Merged
simonbasle merged 12 commits intoreactor:3.4.xfrom
lantalex:enhancement/improve_spsc_queue_padding_3_4_x
Aug 29, 2022
Merged

Use byte padding to avoid fields re-ordering on JDK 15 and above#3168
simonbasle merged 12 commits intoreactor:3.4.xfrom
lantalex:enhancement/improve_spsc_queue_padding_3_4_x

Conversation

@lantalex
Copy link
Copy Markdown
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
Copy Markdown
Contributor

simonbasle commented Aug 26, 2022

fixes #2057.

@simonbasle
Copy link
Copy Markdown
Contributor

@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
Copy Markdown
Contributor

@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
Copy Markdown
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
Copy Markdown
Contributor

@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
Copy Markdown
Contributor

@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
Copy Markdown
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

@lantalex lantalex requested a review from simonbasle August 29, 2022 08:14
@lantalex lantalex requested a review from simonbasle August 29, 2022 08:19
@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
Copy Markdown

@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
Copy Markdown
Contributor

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
Copy Markdown
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.

3 participants