Skip to content

Commit 771739e

Browse files
Update TLAB logic to JDK 25+25.
Fix gcWaste computation.
1 parent 795663f commit 771739e

File tree

2 files changed

+38
-44
lines changed

2 files changed

+38
-44
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ThreadLocalAllocation.java

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,11 @@
2525
package com.oracle.svm.core.genscavenge;
2626

2727
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28-
import static com.oracle.svm.core.genscavenge.TlabSupport.computeMinSizeOfNewTlab;
29-
import static com.oracle.svm.core.genscavenge.TlabSupport.computeSizeOfNewTlab;
30-
import static com.oracle.svm.core.genscavenge.TlabSupport.fillTlab;
31-
import static com.oracle.svm.core.genscavenge.TlabSupport.recordSlowAllocation;
32-
import static com.oracle.svm.core.genscavenge.TlabSupport.retireTlabBeforeAllocation;
33-
import static com.oracle.svm.core.genscavenge.TlabSupport.shouldRetainTlab;
3428
import static com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.TLAB_END_IDENTITY;
3529
import static com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.TLAB_START_IDENTITY;
3630
import static com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets.TLAB_TOP_IDENTITY;
3731

32+
import org.graalvm.nativeimage.CurrentIsolate;
3833
import org.graalvm.nativeimage.IsolateThread;
3934
import org.graalvm.nativeimage.Platform;
4035
import org.graalvm.nativeimage.Platforms;
@@ -371,6 +366,7 @@ private static Pointer allocateRawMemory(UnsignedWord size, BooleanPointer alloc
371366
return allocateRawMemoryOutsideTlab(size, allocatedOutsideTlab);
372367
}
373368

369+
// TEMP (chaeubl): move this to TlabSupport and make most TlabSupport methods private
374370
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/gc/shared/memAllocator.cpp#L257-L329")
375371
@Uninterruptible(reason = "Holds uninitialized memory.")
376372
private static Pointer allocateRawMemoryInTlabSlow(UnsignedWord size) {
@@ -380,19 +376,18 @@ private static Pointer allocateRawMemoryInTlabSlow(UnsignedWord size) {
380376
* Retain tlab and allocate object as an heap allocation if the amount free in the tlab is
381377
* too large to discard.
382378
*/
383-
if (shouldRetainTlab(tlab)) {
384-
recordSlowAllocation();
379+
if (TlabSupport.shouldRetainTlab(tlab)) {
380+
TlabSupport.recordSlowAllocation();
385381
return Word.nullPointer();
386382
}
387383

388-
/*
389-
* Discard tlab and allocate a new one. To minimize fragmentation, the last tlab may be
390-
* smaller than the rest.
391-
*/
392-
UnsignedWord newTlabSize = computeSizeOfNewTlab(size);
384+
/* Discard tlab and allocate a new one. */
393385

394-
retireTlabBeforeAllocation();
386+
TlabSupport.recordRefillWaste();
387+
TlabSupport.retireTlab(CurrentIsolate.getCurrentThread(), false);
395388

389+
/* To minimize fragmentation, the last tlab may be smaller than the rest. */
390+
UnsignedWord newTlabSize = TlabSupport.computeSizeOfNewTlab(size);
396391
if (newTlabSize.equal(0)) {
397392
return Word.nullPointer();
398393
}
@@ -401,8 +396,7 @@ private static Pointer allocateRawMemoryInTlabSlow(UnsignedWord size) {
401396
* Allocate a new TLAB requesting newTlabSize. Any size between minimal and newTlabSize is
402397
* accepted.
403398
*/
404-
405-
UnsignedWord computedMinSize = computeMinSizeOfNewTlab(size);
399+
UnsignedWord computedMinSize = TlabSupport.computeMinSizeOfNewTlab(size);
406400

407401
WordPointer allocatedTlabSize = StackValue.get(WordPointer.class);
408402
Pointer memory = YoungGeneration.getHeapAllocation().allocateNewTlab(computedMinSize, newTlabSize, allocatedTlabSize);
@@ -412,7 +406,7 @@ private static Pointer allocateRawMemoryInTlabSlow(UnsignedWord size) {
412406
}
413407
assert Word.unsigned(0).notEqual(allocatedTlabSize.read()) : "Allocation succeeded but actual size not updated.";
414408

415-
fillTlab(memory, memory.add(size), allocatedTlabSize);
409+
TlabSupport.fillTlab(memory, memory.add(size), allocatedTlabSize);
416410
return memory;
417411
}
418412

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/TlabSupport.java

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
* and another thread allocates nothing. Between GC 23 and GC 24 the allocation behaviour of these
7171
* two threads switches. The allocation average and the TLAB size adapt to the new allocation
7272
* behavior.
73-
*
73+
*
7474
* <pre>
7575
* +-----+---------------------------------------++---------------------------------------+
7676
* | #GC | Thread 1 || Thread 2 |
@@ -87,7 +87,7 @@
8787
* | 29 | 0B | 270,44kB | 5,41kB || 3,55MB | 3,28MB | 67,14kB |
8888
* +-----+--------------+------------+-----------++--------------+------------+-----------+
8989
* </pre>
90-
*
90+
* <p>
9191
* A thread allocating a very large amount of memory will also have a high
9292
* {@link #allocatedBytesAvg}. If such a thread later changes its allocation behaviour and only
9393
* allocates a small amount of memory the {@link #allocatedBytesAvg} starts decreasing with the next
@@ -109,25 +109,23 @@ public class TlabSupport {
109109
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-23-ga/src/hotspot/share/gc/shared/tlab_globals.hpp#L82-L85")//
110110
private static final long TLAB_WASTE_INCREMENT = 4;
111111

112-
// The desired size of the TLAB, including the reserve for filling the unused memory.
112+
/* The desired size of the TLAB, including the reserve for filling the unused memory. */
113113
private static final FastThreadLocalWord<UnsignedWord> desiredSize = FastThreadLocalFactory.createWord("TlabSupport.desiredSize");
114-
115114
private static final FastThreadLocalWord<UnsignedWord> tlabAllocatedAlignedBytesBeforeLastGC = FastThreadLocalFactory.createWord("TlabSupport.tlabAllocatedAlignedBytesBeforeLastGC");
116-
117115
private static final FastThreadLocalInt numberOfRefills = FastThreadLocalFactory.createInt("TlabSupport.numberOfRefills");
118116
private static final FastThreadLocalInt refillWaste = FastThreadLocalFactory.createInt("TlabSupport.refillWaste");
119117
private static final FastThreadLocalInt gcWaste = FastThreadLocalFactory.createInt("TlabSupport.gcWaste");
120118

121-
// Average of allocated bytes in TLABs of this thread.
119+
/* Average of allocated bytes in TLABs of this thread. */
122120
private static final FastThreadLocalBytes<AdaptiveWeightedAverageStruct.Data> allocatedBytesAvg = FastThreadLocalFactory
123121
.createBytes(() -> SizeOf.get(AdaptiveWeightedAverageStruct.Data.class), "TlabSupport.allocatedBytesAvg");
124122

125-
// Hold onto the TLAB if availableTlabMemory() is larger than this.
123+
/* Hold onto the TLAB if availableTlabMemory() is larger than this. */
126124
private static final FastThreadLocalWord<UnsignedWord> refillWasteLimit = FastThreadLocalFactory.createWord("TlabSupport.refillWasteLimit");
127125

128126
private static final FastThreadLocalInt slowAllocations = FastThreadLocalFactory.createInt("TlabSupport.slowAllocations");
129127

130-
// Expected number of refills between GCs.
128+
/* Expected number of refills between GCs. */
131129
private static UnsignedWord targetRefills = Word.unsigned(1);
132130

133131
private static boolean initialized;
@@ -160,9 +158,11 @@ public static void initialize(IsolateThread thread) {
160158
resetStatistics(thread);
161159
}
162160

161+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/runtime/thread.cpp#L168-L174")
163162
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-23-ga/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L183-L195")
164163
@Uninterruptible(reason = "Accesses TLAB")
165164
static void fillTlab(Pointer start, Pointer top, WordPointer newSize) {
165+
/* Fill the TLAB. */
166166
numberOfRefills.set(numberOfRefills.get() + 1);
167167

168168
Pointer hardEnd = start.add(newSize.read());
@@ -172,39 +172,38 @@ static void fillTlab(Pointer start, Pointer top, WordPointer newSize) {
172172

173173
initialize(getTlab(), start, top, end);
174174

175-
// Reset amount of internal fragmentation
175+
/* Reset amount of internal fragmentation. */
176176
refillWasteLimit.set(initialRefillWasteLimit());
177177
}
178178

179179
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L143-L145")
180180
@Uninterruptible(reason = "Accesses TLAB")
181-
static void retireTlabBeforeAllocation() {
181+
static void recordRefillWaste() {
182182
long availableTlabMemory = availableTlabMemory(getTlab()).rawValue();
183183
refillWaste.set(refillWaste.get() + UninterruptibleUtils.NumUtil.safeToInt(availableTlabMemory));
184-
retireCurrentTlab(CurrentIsolate.getCurrentThread(), false);
185184
}
186185

186+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/runtime/thread.cpp#L157-L166")
187187
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+25/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L131-L141")
188188
@Uninterruptible(reason = "Accesses TLAB")
189-
private static void retireCurrentTlab(IsolateThread thread, boolean calculateStats) {
189+
static void retireTlab(IsolateThread thread, boolean calculateStats) {
190+
/* Sampling and serviceability support. */
190191
ThreadLocalAllocation.Descriptor tlab = getTlab(thread);
191-
192192
if (tlab.getAllocationEnd(TLAB_END_IDENTITY).isNonNull()) {
193-
assert checkInvariants(tlab);
194-
195-
UnsignedWord usedTlabSize = getUsedTlabSize(tlab);
196-
allocatedAlignedBytes.set(thread, allocatedAlignedBytes.get(thread).add(usedTlabSize));
197-
insertFiller(tlab);
198-
initialize(tlab, Word.nullPointer(), Word.nullPointer(), Word.nullPointer());
193+
UnsignedWord usedBytes = getUsedTlabSize(tlab);
194+
allocatedAlignedBytes.set(thread, allocatedAlignedBytes.get(thread).add(usedBytes));
199195
}
200196

201-
/*
202-
* Collect statistics after the TLAB has been retired. Otherwise, the current TLAB is
203-
* excluded from the statistics.
204-
*/
197+
/* Retire the TLAB. */
205198
if (calculateStats) {
206199
accumulateAndResetStatistics(thread);
207200
}
201+
202+
if (tlab.getAllocationEnd(TLAB_END_IDENTITY).isNonNull()) {
203+
assert checkInvariants(tlab);
204+
insertFiller(tlab);
205+
initialize(tlab, Word.nullPointer(), Word.nullPointer(), Word.nullPointer());
206+
}
208207
}
209208

210209
@Uninterruptible(reason = "Accesses TLAB")
@@ -238,7 +237,7 @@ private static boolean checkInvariants(Descriptor tlab) {
238237
@Uninterruptible(reason = "Accesses TLAB")
239238
static void suspendAllocationInCurrentThread() {
240239
/* The statistics for this thread will be updated later. */
241-
retireCurrentTlab(CurrentIsolate.getCurrentThread(), false);
240+
retireTlab(CurrentIsolate.getCurrentThread(), false);
242241
}
243242

244243
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
@@ -268,7 +267,7 @@ static void disableAndFlushForThread(IsolateThread vmThread) {
268267
private static void retireTlabToEden(IsolateThread thread) {
269268
VMThreads.guaranteeOwnsThreadMutex("Otherwise, we wouldn't be allowed to access the space.", true);
270269

271-
retireCurrentTlab(thread, true);
270+
retireTlab(thread, true);
272271

273272
Descriptor tlab = getTlab(thread);
274273
UnalignedHeapChunk.UnalignedHeader unalignedChunk = tlab.getUnalignedChunk();
@@ -436,15 +435,16 @@ static UnsignedWord maxSize() {
436435
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-23-ga/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp#L76-L117")
437436
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
438437
private static void accumulateAndResetStatistics(IsolateThread thread) {
439-
gcWaste.set(thread, gcWaste.get() + UninterruptibleUtils.NumUtil.safeToInt(availableTlabMemory(getTlab(thread)).rawValue()));
438+
UnsignedWord remaining = availableTlabMemory(getTlab());
439+
gcWaste.set(thread, gcWaste.get() + UnsignedUtils.safeToInt(remaining));
440+
440441
UnsignedWord totalAlignedAllocated = ThreadLocalAllocation.getAlignedAllocatedBytes(thread);
441442
UnsignedWord allocatedAlignedSinceLastGC = totalAlignedAllocated.subtract(tlabAllocatedAlignedBytesBeforeLastGC.get(thread));
442443
tlabAllocatedAlignedBytesBeforeLastGC.set(thread, totalAlignedAllocated);
443444

444445
AdaptiveWeightedAverageStruct.sample(allocatedBytesAvg.getAddress(thread), allocatedAlignedSinceLastGC.rawValue());
445446

446447
printStats(thread, allocatedAlignedSinceLastGC);
447-
448448
resetStatistics(thread);
449449
}
450450

0 commit comments

Comments
 (0)