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

refactor: replace old MPSC/SPSC queues with JCTools (simplified) #1434

Merged
merged 2 commits into from
Jan 31, 2024

Conversation

jponge
Copy link
Member

@jponge jponge commented Nov 17, 2023

An alternative to #1413 with no handling of native compilation issues which we know how to handle in Quarkus (see the Netty extension).

@jponge jponge changed the title feat/use jctools no native handling Replace old MPSC/SPSC queues with JCTools Nov 17, 2023
@jponge jponge changed the title Replace old MPSC/SPSC queues with JCTools Replace old MPSC/SPSC queues with JCTools (simplified) Nov 17, 2023
@jponge jponge force-pushed the feat/use-jctools-no-native-handling branch 2 times, most recently from 40f5592 to 7de1c9e Compare November 17, 2023 14:28
Copy link

codecov bot commented Nov 17, 2023

Codecov Report

Attention: 6 lines in your changes are missing coverage. Please review.

Comparison is base (dded2d6) 89.34% compared to head (9c17a6e) 89.21%.
Report is 6 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main    #1434      +/-   ##
============================================
- Coverage     89.34%   89.21%   -0.13%     
+ Complexity     3365     3270      -95     
============================================
  Files           459      456       -3     
  Lines         13434    13198     -236     
  Branches       1635     1621      -14     
============================================
- Hits          12002    11775     -227     
+ Misses          808      791      -17     
- Partials        624      632       +8     
Files Coverage Δ
...n/java/io/smallrye/mutiny/groups/MultiFlatten.java 100.00% <100.00%> (ø)
...smallrye/mutiny/infrastructure/Infrastructure.java 72.03% <100.00%> (+2.29%) ⬆️
...e/mutiny/operators/multi/MultiCombineLatestOp.java 86.02% <100.00%> (+0.07%) ⬆️
...llrye/mutiny/operators/multi/MultiConcatMapOp.java 87.41% <100.00%> (+0.08%) ⬆️
...smallrye/mutiny/operators/multi/MultiEmitOnOp.java 92.38% <100.00%> (ø)
...mallrye/mutiny/operators/multi/MultiGroupByOp.java 83.25% <100.00%> (ø)
...smallrye/mutiny/operators/multi/MultiWindowOp.java 91.66% <100.00%> (ø)
...ny/operators/multi/builders/EmitterBasedMulti.java 94.33% <100.00%> (ø)
...y/operators/multi/processors/UnicastProcessor.java 95.68% <100.00%> (ø)
...erators/multi/builders/BufferItemMultiEmitter.java 89.87% <93.75%> (-2.24%) ⬇️
... and 2 more

... and 12 files with indirect coverage changes

@jponge
Copy link
Member Author

jponge commented Nov 22, 2023

JCTools 4.0.2 has been released so we can go back to the upstream

@jponge jponge added enhancement New feature or request noteworthy-feature Noteworthy feature internal Some internal enhancement technical-debt Technical debt reduction labels Nov 25, 2023
@jponge jponge force-pushed the feat/use-jctools-no-native-handling branch from 781ae68 to 7c9807b Compare November 30, 2023 20:30
@jponge jponge added this to the 2.7.0 (or 3.0.0?) milestone Dec 1, 2023
@jponge jponge force-pushed the feat/use-jctools-no-native-handling branch from 7c9807b to 50d840a Compare January 19, 2024 17:48
- Refactored the Queues class and made all queue creations converge to it (except for tests).
- We use the unpadded variants to relieve memory pressure.

Issue: #1330

BREAKING CHANGE: constants and methods have been removed from
io.smallrye.mutiny.helpers.queues.Queues as well as previous MPSC/SPSC classes
in the io.smallrye.mutiny.helpers.queues package.
@jponge jponge force-pushed the feat/use-jctools-no-native-handling branch from 50d840a to 9c17a6e Compare January 22, 2024 13:21
@jponge jponge marked this pull request as ready for review January 22, 2024 14:11
@jponge
Copy link
Member Author

jponge commented Jan 22, 2024

This is ready for review 👍

I found breaking changes to Smallrye Reactive Messaging, the fix is easy: jponge/smallrye-reactive-messaging@443a925

@jponge jponge changed the title Replace old MPSC/SPSC queues with JCTools (simplified) refactor: replace old MPSC/SPSC queues with JCTools (simplified) Jan 22, 2024
@jponge
Copy link
Member Author

jponge commented Jan 22, 2024

Also @franz1981 if you could do one more review, that'd be great 🙏

Copy link
Contributor

@cescoffier cescoffier left a comment

Choose a reason for hiding this comment

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

Did you ask Ozan to run the reactive messaging test with it?

implementation/pom.xml Show resolved Hide resolved
@jponge
Copy link
Member Author

jponge commented Jan 23, 2024

Did you ask Ozan to run the reactive messaging test with it?

No but I'd be happy to 🤣

@ozangunalp
Copy link
Collaborator

👍 I'll take a look for reactive messaging

Copy link
Collaborator

@ozangunalp ozangunalp left a comment

Choose a reason for hiding this comment

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

Code looks good and Reactive Messaging tests run green locally.

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

Code looks good and Reactive Messaging tests run green locally.

I like that 🤣

Thanks Ozan

@ozangunalp
Copy link
Collaborator

It is the new "it works on my machine"

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

Note to others: I'll merge myself (I'm looking at Quarkus tweaks for native support)

@franz1981
Copy link
Contributor

franz1981 commented Jan 24, 2024

oki @jponge I didn't had yet the chance to re-review it, sorry :(

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

I'm struggling with the support of unpadded variants in native.

I ended up with the following Quarkus build items -- they are in fact symmetric to those from the Quarkus Netty extension (but shaded and on the base queue variants):

new UnsafeAccessedFieldBuildItem(
        "org.jctools.queues.unpadded.MpscUnpaddedArrayQueueProducerIndexField",
        "producerIndex"),
new UnsafeAccessedFieldBuildItem(
        "org.jctools.queues.unpadded.MpscUnpaddedArrayQueueProducerLimitField",
        "producerLimit"),
new UnsafeAccessedFieldBuildItem(
        "org.jctools.queues.unpadded.MpscUnpaddedArrayQueueConsumerIndexField",
        "consumerIndex"),
new UnsafeAccessedFieldBuildItem(
        "org.jctools.queues.unpadded.BaseMpscLinkedUnpaddedArrayQueueColdProducerFields",
        "producerLimit"),
new UnsafeAccessedFieldBuildItem(
        "org.jctools.queues.unpadded.BaseMpscLinkedUnpaddedArrayQueueProducerFields",
        "producerIndex"),
new UnsafeAccessedFieldBuildItem(
        "org.jctools.queues.unpadded.BaseMpscLinkedUnpaddedArrayQueueConsumerFields",
        "consumerIndex"));

Writing an integration test I end up segfaulting on:

Stacktrace for the failing thread 0x0000000131304200 (A=AOT compiled, J=JIT compiled, D=deoptimized, i=inlined):
  A  SP 0x00000001702129d0 IP 0x000000010100d618 size=64    org.jctools.queues.unpadded.BaseMpscLinkedUnpaddedArrayQueue.offer(BaseMpscLinkedUnpaddedArrayQueue.java)
  A  SP 0x0000000170212a10 IP 0x000000010100f658 size=48    org.jctools.queues.unpadded.MpscUnboundedUnpaddedArrayQueue.offer(MpscUnboundedUnpaddedArrayQueue.java:27)
  A  SP 0x0000000170212a40 IP 0x000000010062fb80 size=96    io.quarkus.it.mutiny.nativejctools.MyResource.lambda$createQueues$0(MyResource.java:28)
  A  SP 0x0000000170212aa0 IP 0x000000010062eaf8 size=48    io.quarkus.it.mutiny.nativejctools.MyResource$$Lambda$9d7ef37a889a56d8a9dcf67834116cfa6fc37755.accept(Unknown Source)
  A  SP 0x0000000170212ad0 IP 0x000000010096be64 size=96    java.lang.Iterable.forEach(Iterable.java:75)
  A  SP 0x0000000170212b30 IP 0x000000010062f0c8 size=96    io.quarkus.it.mutiny.nativejctools.MyResource.createQueues(MyResource.java:26)
  A  SP 0x0000000170212b90 IP 0x000000010062ec5c size=48    io.quarkus.it.mutiny.nativejctools.MyResource$quarkusrestinvoker$createQueues_a4780c8b1dd461d14b3978d89b401e4e442b7033.invoke(Unknown Source)
  A  SP 0x0000000170212bc0 IP 0x0000000100ff55f0 size=64    org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
  A  SP 0x0000000170212c00 IP 0x0000000100635c58 size=48    io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141)
  A  SP 0x0000000170212c30 IP 0x0000000100fbd020 size=112   org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
  A  SP 0x0000000170212ca0 IP 0x00000001006da3bc size=96    io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:582)
  A  SP 0x0000000170212d00 IP 0x00000001010045c0 size=80    org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
  A  SP 0x0000000170212d50 IP 0x000000010100545c size=112   org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
  i  SP 0x0000000170212dc0 IP 0x000000010100af14 size=48    org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
  A  SP 0x0000000170212dc0 IP 0x000000010100af14 size=48    org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
  A  SP 0x0000000170212df0 IP 0x0000000100573324 size=48    io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
  i  SP 0x0000000170212e20 IP 0x00000001009b0eb0 size=48    java.lang.Thread.runWith(Thread.java:1596)
  A  SP 0x0000000170212e20 IP 0x00000001009b0eb0 size=48    java.lang.Thread.run(Thread.java:1583)
  A  SP 0x0000000170212e50 IP 0x0000000100242594 size=64    com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:833)
  A  SP 0x0000000170212e90 IP 0x00000001001f2b0c size=48    com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211)
  A  SP 0x0000000170212ec0 IP 0x000000010015681c size=272   com.oracle.svm.core.code.IsolateEnterStub.PosixPlatformThreads_pthreadStartRoutine_38d96cbc1a188a6051c29be1299afe681d67942e(IsolateEnterStub.java:0)

with the following notable compilation warning:

Warning: RecomputeFieldValue.ArrayIndexScale automatic substitution failed. The automatic substitution registration was attempted because a call to jdk.internal.misc.Unsafe.arrayIndexScale(Class) was detected in the static initializer of org.jctools.util.UnsafeRefArrayAccess. Detailed failure reason(s): Could not determine the field where the value produced by the call to jdk.internal.misc.Unsafe.arrayIndexScale(Class) for the array index scale computation is stored. The call is not directly followed by a field store or by a sign extend node followed directly by a field store.

Unless someone sees an easy fix, we could either:

  1. wait for Unpadded variants could avoid using Unsafe JCTools/JCTools#387 from @franz1981 and a new JCTools release to get unpadded / Unsafe-free variants, or
  2. just switch to the Unsafe-free variants that are padded, provided the memory overhead is reasonable, and eventually take advantage of unpadded Unsafe-free variants in the future

WDYT?

@cescoffier
Copy link
Contributor

cescoffier commented Jan 24, 2024 via email

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

Ok, so I might have a fix 🤣

I get all used queues working with just:

new UnsafeAccessedFieldBuildItem(
  "org.jctools.util.UnsafeRefArrayAccess",
  "REF_ELEMENT_SHIFT")

and not doing anything special for MpscUnpaddedArrayQueueProducerIndexField and BaseMpscLinkedUnpaddedArrayQueueColdProducerFields and BaseMpscLinkedUnpaddedArrayQueueProducerFields.

Go figure....

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

Note: I'm on GraalVM CE 21.0.2+13.1 (sdk install java 21.0.2-graalce)

@cescoffier
Copy link
Contributor

Hum... we will need to try with GraalVM EE (the non ce version), as it is slightly more picky about these things.

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

Hum... we will need to try with GraalVM EE (the non ce version), as it is slightly more picky about these things.

Works with 21.0.2-graal as well

@jponge
Copy link
Member Author

jponge commented Jan 24, 2024

@jponge
Copy link
Member Author

jponge commented Jan 26, 2024

I met today with @franz1981

  • we will go with these unpadded + Unsafe queues until JCTools has unpadded + atomic variants,
  • I will check a few native compilation things on the Quarkus Netty extension now, then I will proceed and merge this PR.

jponge added a commit to jponge/quarkus that referenced this pull request Jan 26, 2024
… queues

GraalVM now seems to have good heuristics to spot the classic Unsafe usage patterns.
I removed some UnsafeAccessedFieldBuildItem and added one for UnsafeRefArrayAccess as this class
has a problematic static field (REF_ELEMENT_SHIFT).

For there record I found about this while working on smallrye/smallrye-mutiny#1434
@jponge jponge merged commit 26f87e7 into main Jan 31, 2024
7 checks passed
@jponge jponge deleted the feat/use-jctools-no-native-handling branch January 31, 2024 13:30
@jponge
Copy link
Member Author

jponge commented Jan 31, 2024

Let's go 😄

@jponge jponge mentioned this pull request Feb 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request internal Some internal enhancement noteworthy-feature Noteworthy feature technical-debt Technical debt reduction
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants