Skip to content

Conversation

minborg
Copy link
Contributor

@minborg minborg commented Nov 11, 2024

This PR proposes to add a new `MemorySegment::fill" benchmark where the byte size of the segments varies.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8343933: Add a MemorySegment::fill benchmark with varying sizes (Enhancement - P5)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/22010/head:pull/22010
$ git checkout pull/22010

Update a local copy of the PR:
$ git checkout pull/22010
$ git pull https://git.openjdk.org/jdk.git pull/22010/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 22010

View PR using the GUI difftool:
$ git pr show -t 22010

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/22010.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Nov 11, 2024

👋 Welcome back pminborg! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Nov 11, 2024

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk
Copy link

openjdk bot commented Nov 11, 2024

@minborg The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Nov 11, 2024
@minborg minborg marked this pull request as ready for review November 11, 2024 13:43
@minborg minborg changed the title 8343933: Add a MemorySegment::fill benchmark with varying sizesMs fill bench sizes 8343933: Add a MemorySegment::fill benchmark with varying sizes Nov 11, 2024
@openjdk openjdk bot added the rfr Pull request is ready for review label Nov 11, 2024
@mlbridge
Copy link

mlbridge bot commented Nov 11, 2024

Webrevs

@franz1981
Copy link

franz1981 commented Nov 11, 2024

Thanks @minborg for this :) Please remember to add the misprediction count if you can and avoid the bulk methods by having a nextMemorySegment() benchmark method which make a single fill call site to observe the different segments (types).

Having separate call-sites which observe always the same type(s) "could" be too lucky (and gentle) for the runtime (and CHA) and would favour to have a single address entry (or few ones, if we include any optimization for the fill size) in the Branch Target Buffer of the cpu.

@minborg
Copy link
Contributor Author

minborg commented Nov 11, 2024

Thanks @minborg for this :) Please remember to add the misprediction count if you can and avoid the bulk methods by having a nextMemorySegment() benchmark method which make a single fill call site to observe the different segments (types).

Having separate call-sites which observe always the same type(s) "could" be too lucky (and gentle) for the runtime (and CHA) and would favour to have a single address entry (or few ones, if we include any optimization for the fill size) in the Branch Target Buffer of the cpu.

I've added a "mixed" benchmark. I am not sure I understood all of your comments but given my changes, maybe you could elaborate a bit more?

@Benchmark
public void mixedSegmentFillUnsafe() {
for (int i = 0; i < INSTANCES; i++) {
MIXED_SEGMENTS[i].fill((byte) 0);
Copy link

@franz1981 franz1981 Nov 11, 2024

Choose a reason for hiding this comment

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

loop unrolling can defeat a bit the purpose of messing up with branch misprediction here so...one solution is to avoid loop unrolling OR

create a

@CompilerControl(DONTINLINE)
static void fillSegment(MemorySegment ms, byte value) {
    ms.fill(value);
}

which makes sure (at the cost of a very predictable call to the fillSegment method) that:

  • the inlining depth of fill is controlled and not dependent by the depth of the JMH infra caller
  • the call site for fill is always the same (in term of the address in the compiled blob)

Last point is slightly inaccurate because is what CHA will figure it out. Let's say instead that since the caller is not inlined, we make sure the method data of the fill invocation observe different receivers.

@mcimadamore
Copy link
Contributor

IIUC, this benchmark is designed to test what happens in the case where a bulk operation is executed on a segment whose type is not known e.g. through type profiling (e.g. polluted case). Note that in this case (MIXED) the fact that we can't rely on which segment it is (and hence on whether it has a certain scope or not, and what the base object is) would greatly dominate the cost of branch misprediction, which I saw mentioned here. In extreme cases of profile pollution it is very possible for a method to be optimized under the assumption that e.g. the method is always executed on off-heap segments, and then hit an on-heap segment, which will perform horribly.

We have test cases such as these in LoopOverPolluted[Segments/Buffer]. It makes sense to test something similar for bulk access too.

@franz1981
Copy link

franz1981 commented Nov 12, 2024

@mcimadamore I've added a suggestion (at #22010 (comment)) on how to make sure that the type profile is polluted and shared by all the fill invocations (although only perfasm + perfnorm or TypeProfile logging will tell us if it has worked as expected) - sadly I had to rely on DONTINLINE :"(
Said that, resetting the "inlining budget" with a not inlined frame is still brittle and should be verified by adding profiling or printinlining inspection (or just perfasm, searching for callq/call, manually)

@eme64
Copy link
Contributor

eme64 commented Nov 12, 2024

@minborg sent me some logs from his machine, and I'm analyzing them now.

Basically, I'm trying to see why your Java code is a bit faster than the Loop code.


  44.77%                c2, level 4  org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop, version 4, compile id 946
  24.43%                c2, level 4  org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop, version 4, compile id 946
  21.80%                c2, level 4  org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop, version 4, compile id 946

There seem to be 3 hot regions.

main-loop (region has 44.77%):

             ;; B33: #  out( B33 B34 ) &lt;- in( B32 B33 ) Loop( B33-B33 inner main of N116 strip mined) Freq: 4.62951e+10                                                          
   0.50%  ?   0x00000001149a23c0:   sxtw        x20, w4                                                                                                                             
          ?   0x00000001149a23c4:   add x22, x16, x20                                                                                                                               
   0.02%  ?   0x00000001149a23c8:   str q16, [x22]                                                                                                                                  
  16.33%  ?   0x00000001149a23cc:   str q16, [x22, #16]             ;*invokevirtual putByte {reexecute=0 rethrow=0 return_oop=0}                                                    
          ?                                                             ; - jdk.internal.misc.ScopedMemoryAccess::putByteInternal@15 (line 534)                                     
          ?                                                             ; - jdk.internal.misc.ScopedMemoryAccess::putByte@6 (line 522)                                              
          ?                                                             ; - java.lang.invoke.VarHandleSegmentAsBytes::set@38 (line 114)                                             
          ?                                                             ; - java.lang.invoke.LambdaForm$DMH/0x000000013a4d5800::invokeStatic@20                                     
          ?                                                             ; - java.lang.invoke.LambdaForm$MH/0x000000013a4d8070::invoke@37                                            
          ?                                                             ; - java.lang.invoke.VarHandleGuards::guard_LJI_V@134 (line 1017)                                           
          ?                                                             ; - jdk.internal.foreign.AbstractMemorySegmentImpl::set@10 (line 670)                                       
          ?                                                             ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@44 (line 101)            
          ?   0x00000001149a23d0:   add w4, w4, #0x20                                                                                                                               
   0.06%  ?   0x00000001149a23d4:   cmp w4, w10                                                                                                                                     
          ?   0x00000001149a23d8:   b.lt        0x00000001149a23c0  // b.tstop;*ifge {reexecute=0 rethrow=0 return_oop=0}

post-loops: the "vectorized post-loop" and the "single iteration post-loop" (region has 24.43%):
vectorized post-loop (inner post)

             ?   ? ;; B14: #    out( B14 B15 ) &lt;- in( B35 B14 ) Loop( B14-B14 inner post of N1915) Freq: 174420
   2.20%     ??  ?  0x00000001149a224c:   sxtw  x5, w4
   0.88%     ??  ?  0x00000001149a2250:   str   q16, [x16, x5]              ;*invokevirtual putByte {reexecute=0 rethrow=0 return_oop=0}
             ??  ?                                                            ; - jdk.internal.misc.ScopedMemoryAccess::putByteInternal@15 (line 534)
             ??  ?                                                            ; - jdk.internal.misc.ScopedMemoryAccess::putByte@6 (line 522)
             ??  ?                                                            ; - java.lang.invoke.VarHandleSegmentAsBytes::set@38 (line 114)
             ??  ?                                                            ; - java.lang.invoke.LambdaForm$DMH/0x000000013a4d5800::invokeStatic@20
             ??  ?                                                            ; - java.lang.invoke.LambdaForm$MH/0x000000013a4d8070::invoke@37
             ??  ?                                                            ; - java.lang.invoke.VarHandleGuards::guard_LJI_V@134 (line 1017)
             ??  ?                                                            ; - jdk.internal.foreign.AbstractMemorySegmentImpl::set@10 (line 670)
             ??  ?                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@44 (line 101)
             ??  ?  0x00000001149a2254:   add   w4, w4, #0x10
             ??  ?  0x00000001149a2258:   cmp   w4, w10
             ??  ?  0x00000001149a225c:   b.lt  0x00000001149a224c  // b.tstop;*ifge {reexecute=0 rethrow=0 return_oop=0}
             ?   ?                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@33 (line 100)
             ?   ? ;; B15: #    out( B16 ) &lt;- in( B14 )  Freq: 87210.2
   0.34%     ?   ?  0x00000001149a2260:   add   x10, x19, x5
             ?   ?  0x00000001149a2264:   add   x22, x10, #0x10             ;*ladd {reexecute=0 rethrow=0 return_oop=0}
             ?   ?                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@52 (line 100)
             ?   ? ;; B16: #    out( B20 B17 ) &lt;- in( B39 B15 B36 ) top-of-loop Freq: 174421
   0.78%     ?   ?  0x00000001149a2268:   cmp   w4, w3
             ? ? ?  0x00000001149a226c:   b.ge  0x00000001149a2294  // b.tcont
             ? ? ? ;; B17: #    out( B42 B18 ) &lt;- in( B16 )  Freq: 87210.3
             ? ? ?  0x00000001149a2270:   cmp   w4, w2
             ? ? ?  0x00000001149a2274:   b.cs  0x00000001149a24a4  // b.hs, b.nlast
             ? ? ?                                                            ;*aload {reexecute=0 rethrow=0 return_oop=0}
             ? ? ?                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@36 (line 101)

scalar post loop:

             ? ? ? ;; B18: #    out( B18 B19 ) &lt;- in( B17 B18 ) Loop( B18-B18 inner post of N1402) Freq: 174420
   0.56%     ? ???  0x00000001149a2278:   sxtw  x10, w4
   5.47%     ? ???  0x00000001149a227c:   strb  wzr, [x16, x10, lsl #0]     ;*invokevirtual putByte {reexecute=0 rethrow=0 return_oop=0}
             ? ???                                                            ; - jdk.internal.misc.ScopedMemoryAccess::putByteInternal@15 (line 534)
             ? ???                                                            ; - jdk.internal.misc.ScopedMemoryAccess::putByte@6 (line 522)
             ? ???                                                            ; - java.lang.invoke.VarHandleSegmentAsBytes::set@38 (line 114)
             ? ???                                                            ; - java.lang.invoke.LambdaForm$DMH/0x000000013a4d5800::invokeStatic@20
             ? ???                                                            ; - java.lang.invoke.LambdaForm$MH/0x000000013a4d8070::invoke@37
             ? ???                                                            ; - java.lang.invoke.VarHandleGuards::guard_LJI_V@134 (line 1017)
             ? ???                                                            ; - jdk.internal.foreign.AbstractMemorySegmentImpl::set@10 (line 670)
             ? ???                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@44 (line 101)
             ? ???  0x00000001149a2280:   add   w4, w4, #0x1
             ? ???  0x00000001149a2284:   cmp   w4, w3
             ? ???  0x00000001149a2288:   b.lt  0x00000001149a2278  // b.tstop

Not sure why we have this below... probably the check that leads to the post-loop?

             ? ? ? ;; B19: #    out( B20 ) &lt;- in( B18 )  Freq: 87210.2
   8.88%     ? ? ?  0x00000001149a228c:   add   x10, x10, x19
             ? ? ?  0x00000001149a2290:   add   x22, x10, #0x1              ;*ifge {reexecute=0 rethrow=0 return_oop=0}
             ? ? ?                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@33 (line 100)
             ? ? ? ;; B20: #    out( B2 B21 ) &lt;- in( B23 B19 B16 )  Freq: 174760
   0.78%     ? ? ?  0x00000001149a2294:   cmp   x22, x7
             ?   ?  0x00000001149a2298:   b.ge  0x00000001149a219c  // b.tcont

pre-loop (region has 21.80%):

             ;; B27: #  out( B29 B28 ) &lt;- in( B26 B28 ) Loop( B27-B28 inner pre of N1402) Freq: 348842
   0.10%   ?  0x00000001149a2364:   sxtw        x22, w10
   6.01%   ?  0x00000001149a2368:   strb        wzr, [x16, x22, lsl #0]     ;*invokevirtual putByte {reexecute=0 rethrow=0 return_oop=0}
           ?                                                            ; - jdk.internal.misc.ScopedMemoryAccess::putByteInternal@15 (line 534)
           ?                                                            ; - jdk.internal.misc.ScopedMemoryAccess::putByte@6 (line 522)
           ?                                                            ; - java.lang.invoke.VarHandleSegmentAsBytes::set@38 (line 114)
           ?                                                            ; - java.lang.invoke.LambdaForm$DMH/0x000000013a4d5800::invokeStatic@20
           ?                                                            ; - java.lang.invoke.LambdaForm$MH/0x000000013a4d8070::invoke@37
           ?                                                            ; - java.lang.invoke.VarHandleGuards::guard_LJI_V@134 (line 1017)
           ?                                                            ; - jdk.internal.foreign.AbstractMemorySegmentImpl::set@10 (line 670)
           ?                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@44 (line 101)
   0.08%   ?  0x00000001149a236c:   add w4, w10, #0x1
   0.56%   ?  0x00000001149a2370:   cmp w4, w20
   0.04%  ??  0x00000001149a2374:   b.ge        0x00000001149a2380  // b.tcont;*ifge {reexecute=0 rethrow=0 return_oop=0}
          ??                                                            ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillLoop@33 (line 100)
          ?? ;; B28: #  out( B27 ) &lt;- in( B27 )  Freq: 174421
   5.61%  ??  0x00000001149a2378:   mov w10, w4
          ??  0x00000001149a237c:   b   0x00000001149a2364

with a strange extra add that has some strange looking percentage (profile inaccuracy?):

   7.88%  ?   0x00000001149a2380:   add w10, w10, #0x20

Summary:

pre-loop:             22%, byte-store
main-loop:            40%  2x 16-byte-vector-store (profiling is a bit contradictory here - is it 16% or 44%?)
vectorized post-loop: 4%   1x 16-byte-vector-store (not super sure about profiling, but could be accurate)
post-loop:            12%  byte-store

The numbers don't quite add up - but they are still somewhat telling - and I think probably accurate enough to see what happens.

Basically: we waste a lot of time in the pre and post-loop: getting alignment and then finishing off at the end.


And to compare:

  58.00%                c2, level 4  org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava, version 5, compile id 848
  29.83%                c2, level 4  org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava, version 5, compile id 848

We have 2 hot regions.

main (58%):

             ;; B40: #  out( B40 B41 ) &lt;- in( B39 B40 ) Loop( B40-B40 inner main of N140 strip mined) Freq: 2.13696e+08
   0.26%  ?   0x000000011800f900:   add x4, x1, w3, sxtw
          ?  ;; merged str pair
          ?   0x000000011800f904:   stp xzr, xzr, [x4]
          ?   0x000000011800f908:   str xzr, [x4, #16]              ;*invokevirtual putLongUnaligned {reexecute=0 rethrow=0 return_oop=0}
          ?                                                             ; - jdk.internal.misc.Unsafe::putLongUnaligned@10 (line 3677)
          ?                                                             ; - jdk.internal.misc.ScopedMemoryAccess::putLongUnalignedInternal@17 (line 2605)
          ?                                                             ; - jdk.internal.misc.ScopedMemoryAccess::putLongUnaligned@8 (line 2593)
          ?                                                             ; - jdk.internal.foreign.SegmentBulkOperations::fill@133 (line 78)
          ?                                                             ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
          ?                                                             ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
          ?   0x000000011800f90c:   add w3, w3, #0x20               ;*iinc {reexecute=0 rethrow=0 return_oop=0}
          ?                                                             ; - jdk.internal.foreign.SegmentBulkOperations::fill@136 (line 77)
          ?                                                             ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
          ?                                                             ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
  21.73%  ?   0x000000011800f910:   str xzr, [x4, #24]              ;*invokevirtual putLongUnaligned {reexecute=0 rethrow=0 return_oop=0}
          ?                                                             ; - jdk.internal.misc.Unsafe::putLongUnaligned@10 (line 3677)
          ?                                                             ; - jdk.internal.misc.ScopedMemoryAccess::putLongUnalignedInternal@17 (line 2605)
          ?                                                             ; - jdk.internal.misc.ScopedMemoryAccess::putLongUnaligned@8 (line 2593)
          ?                                                             ; - jdk.internal.foreign.SegmentBulkOperations::fill@133 (line 78)
          ?                                                             ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
          ?                                                             ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
   0.17%  ?   0x000000011800f914:   cmp w3, w2
   2.58%  ?   0x000000011800f918:   b.lt        0x000000011800f900  // b.tstop;*if_icmpge {reexecute=0 rethrow=0 return_oop=0}
                                                                        ; - jdk.internal.foreign.SegmentBulkOperations::fill@98 (line 77)
                                                                        ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
                                                                        ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
             ;; B41: #  out( B39 B42 ) &lt;- in( B40 )  Freq: 3.29583e+06
  26.13%      0x000000011800f91c:   ldr x2, [x28, #48]              ; ImmutableOopMap {r12=Oop r14=Oop c_rarg1=Derived_oop_r14 r15=Oop r16=Oop }

Rest:
vectorized post-loop

                ;; B2: #        out( B2 B3 ) &lt;- in( B42 B2 ) Loop( B2-B2 inner post of N1701) Freq: 50831.6
   3.01%  ?      0x000000011800f728:   str      xzr, [x1, w3, sxtw]         ;*invokevirtual putLongUnaligned {reexecute=0 rethrow=0 return_oop=0}
          ?                                                                ; - jdk.internal.misc.Unsafe::putLongUnaligned@10 (line 3677)
          ?                                                                ; - jdk.internal.misc.ScopedMemoryAccess::putLongUnalignedInternal@17 (line 2605)
          ?                                                                ; - jdk.internal.misc.ScopedMemoryAccess::putLongUnaligned@8 (line 2593)
          ?                                                                ; - jdk.internal.foreign.SegmentBulkOperations::fill@133 (line 78)
          ?                                                                ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
          ?                                                                ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
          ?      0x000000011800f72c:   add      w3, w3, #0x8                ;*iinc {reexecute=0 rethrow=0 return_oop=0}
          ?                                                                ; - jdk.internal.foreign.SegmentBulkOperations::fill@136 (line 77)
          ?                                                                ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
          ?                                                                ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
          ?      0x000000011800f730:   cmp      w3, w10
          ?      0x000000011800f734:   b.lt     0x000000011800f728  // b.tstop;*if_icmpge {reexecute=0 rethrow=0 return_oop=0}
                                                                           ; - jdk.internal.foreign.SegmentBulkOperations::fill@98 (line 77)
                                                                           ; - jdk.internal.foreign.AbstractMemorySegmentImpl::fill@2 (line 184)
                                                                           ; - org.openjdk.bench.java.lang.foreign.SegmentBulkRandomFill::heapSegmentFillJava@14 (line 83)
                ;; B3: #        out( B5 B4 ) &lt;- in( B2 B43 B44 ) top-of-loop Freq: 51627.8

... and then the rest of the code I speculate is your long-int-short-byte wind-down code.


Conclusion:

Java: spends about 58% in well vectorized main-loop code (2x super-unrolled, i.e. 2x 16-byte-vectors)
Loop: only spends about 40% in main loop (also 2x 16-byte vectors) - the rest is spent in pre/post-loops

Hmm. This really makes me want to ditch the alignment-code - it may hurt more than we gain from it 🤔
And we should also consider such "wind-down" code: going from 16-element vectors to 8, 4, 2, 1 elements. Of course that is extra code and extra compile time...

@franz1981
Copy link

franz1981 commented Nov 12, 2024

@eme64 not an expert with ARM, but profiling skidding due to modern big pipelined OOO CPUs is rather frequent

with a strange extra add that has some strange looking percentage (profile inaccuracy?):

you should check some instr below it to get the real culprit

More info on this topic are:

If you uses Intel/AMD and PEBS/IBS (if supported by your cpu) you can run perfasm using precise events via perfasm:events=cycles:P IIRC (or adding more Ps? @shipilev likely knows) which should have way less skidding and will simplify these analysis.

@eme64
Copy link
Contributor

eme64 commented Nov 12, 2024

@franz1981 right. That is what I thought. I'm usually working on x64, and am not used to all the skidding of ARM.

@eme64
Copy link
Contributor

eme64 commented Nov 12, 2024

But I think the full count is done per block in profiling - and that should be reasonably accurate - though hard to attribute where in the block it came from exactly.

@bridgekeeper
Copy link

bridgekeeper bot commented Dec 10, 2024

@minborg This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@bridgekeeper
Copy link

bridgekeeper bot commented Jan 7, 2025

@minborg This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the /open pull request command.

@bridgekeeper bridgekeeper bot closed this Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org rfr Pull request is ready for review
Development

Successfully merging this pull request may close these issues.

4 participants