Skip to content

Commit 3fe691e

Browse files
authored
Merge pull request #19789 from mpirvu/disclaim_fix
Fixes to code cache disclaiming
2 parents dd108db + 6841463 commit 3fe691e

File tree

2 files changed

+76
-30
lines changed

2 files changed

+76
-30
lines changed

runtime/compiler/runtime/J9CodeCache.cpp

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -153,38 +153,76 @@ J9::CodeCache::initialize(TR::CodeCacheManager *manager,
153153
{
154154
J9JavaVM * javaVM = jitConfig->javaVM;
155155
PORT_ACCESS_FROM_JAVAVM(javaVM); // for j9vmem_supported_page_sizes
156+
uintptr_t round = (uintptr_t)(j9vmem_supported_page_sizes()[0] - 1);
157+
158+
// The code cache segment start must be page aligned because it was allocated with mmap
159+
// _warmCodeAllocBase may not be at the very beginning of the segment though (and not page alinged)
160+
// Align on page boundary going backwards if needed.
161+
uintptr_t warmSectionStart = (uintptr_t)_warmCodeAllocBase & ~round;
162+
// The cold section may be followed by trampolines and helpers, so it may not be page aligned.
163+
// Align it going forward. This will not go past the end of the segment which is page aligned.
164+
uintptr_t coldSectionEnd = ((uintptr_t)_coldCodeAllocBase + round) & ~round;
165+
// Find the split point between the warm area (using large pages) and the cold area (using small pages).
166+
// Experiments have shown that warm/cold code is about 50/50, so we need to find the middle point.
167+
uintptr_t middle = warmSectionStart + (coldSectionEnd - warmSectionStart) / 2;
168+
uintptr_t coldSectionStart = middle;
169+
// Since we want to use large pages for the warm area, its end needs to be large page aligned.
170+
// We cannot determine the size of the THP page with j9vmem_supported_page_sizes(),
171+
// but we know that on x86, the size of a THP page is 2 MB. Round up/down as needed.
172+
#if defined(TR_TARGET_X86)
173+
static const uintptr_t THP_SIZE = 2 * 1024 * 1024; // 2 MB
174+
#elif defined(TR_TARGET_S390)
175+
static const uintptr_t THP_SIZE = 1 * 1024 * 1024; // 1 MB
176+
#else
177+
// Power has 64 KB and 16 MB pages (16 MB is too large to be useful for disclaiming)
178+
// ARM can have many sizes for its large pages: 64 K, 1 MB, 2 MB, 16 MB)
179+
static const uintptr_t THP_SIZE = 65536; // 64K
180+
#endif
181+
static const uintptr_t ROUNDING_VALUE = THP_SIZE/2 - 1;
182+
if (codeCacheSegment->segmentTop() - codeCacheSegment->segmentBase() >= 2 * THP_SIZE)
183+
{
184+
coldSectionStart = (middle + ROUNDING_VALUE) & ~ROUNDING_VALUE;
185+
}
186+
TR_ASSERT_FATAL(coldSectionEnd > coldSectionStart, "A code cache can't be smaller than a page");
187+
_smallPageAreaStart = (uint8_t *)coldSectionStart;
188+
_smallPageAreaEnd = (uint8_t *)coldSectionEnd;
156189

157-
uint8_t *middle = _warmCodeAlloc + (_coldCodeAllocBase - _warmCodeAlloc) / 2;
158-
size_t round = j9vmem_supported_page_sizes()[0] - 1;
159-
middle = (uint8_t *)(((size_t)(middle + round)) & ~round);
160-
161-
TR_ASSERT_FATAL(_coldCodeAlloc > middle, "A code cache can't be smaller than a page");
190+
size_t coldCacheSize = coldSectionEnd - coldSectionStart;
162191

163-
size_t coldCacheSize = _coldCodeAlloc - middle;
164-
coldCacheSize = (coldCacheSize + round) & ~round;
192+
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance))
193+
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "Code cache warm area %p - %p (size=%zu); cold area %p - %p (size=%zu)",
194+
(uint8_t*)warmSectionStart, _smallPageAreaStart, _smallPageAreaStart - (uint8_t*)warmSectionStart,
195+
_smallPageAreaStart, _smallPageAreaEnd, coldCacheSize);
165196

166-
if (madvise(middle, coldCacheSize, MADV_NOHUGEPAGE) != 0)
197+
if (madvise(_smallPageAreaStart, coldCacheSize, MADV_NOHUGEPAGE) != 0)
167198
{
168199
const char *error = strerror(errno);
169200
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance))
170-
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "Failed to set MADV_NOHUGEPAGE for code cache: %s: %p %zu", error, middle, coldCacheSize);
201+
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "Failed to set MADV_NOHUGEPAGE for code cache: %s: %p %zu", error, _smallPageAreaStart, coldCacheSize);
171202
}
172203
else if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance))
173204
{
174-
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "Forcing code cache cold region %p-%p to use default size memory pages", middle, middle + coldCacheSize);
205+
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "Forcing code cache cold region %p-%p of size %zu to use default size memory pages",
206+
_smallPageAreaStart, _smallPageAreaStart + coldCacheSize, coldCacheSize);
175207
}
176208

177209
// If the memory segment is backed by a file, disable read-ahead
178210
// so that touching one byte brings a single page in
179211
if (codeCacheSegment->j9segment()->vmemIdentifier.allocator == OMRPORT_VMEM_RESERVE_USED_MMAP_SHM)
180212
{
181-
if (madvise(middle, coldCacheSize, MADV_RANDOM) != 0)
213+
if (madvise(_smallPageAreaStart, coldCacheSize, MADV_RANDOM) != 0)
182214
{
183215
if (TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance))
184216
TR_VerboseLog::writeLineLocked(TR_Vlog_INFO, "Failed to set MADV_RANDOM for cold code cache");
185217
}
186218
}
187219
}
220+
else // Disclaim is not allowed
221+
{
222+
// Note: if _smallPageAreaStart and _smallPageAreaEnd are the same, there will be no disclaim attempted
223+
_smallPageAreaStart = _coldCodeAllocBase;
224+
_smallPageAreaEnd = _coldCodeAllocBase;
225+
}
188226
#endif // ifdef LINUX
189227

190228
_manager->reportCodeLoadEvents();
@@ -822,31 +860,35 @@ J9::CodeCache::disclaim(TR::CodeCacheManager *manager, bool canDisclaimOnSwap)
822860
int32_t disclaimDone = 0;
823861

824862
#ifdef LINUX
825-
J9JavaVM * javaVM = jitConfig->javaVM;
826-
PORT_ACCESS_FROM_JAVAVM(javaVM); // for j9vmem_supported_page_sizes
863+
if ((uintptr_t)_smallPageAreaStart >= (uintptr_t)_smallPageAreaEnd)
864+
return disclaimDone;
865+
uint8_t *disclaimStart = _smallPageAreaStart;
866+
// Some of the warm code could have been written into the small page area.
867+
// We don't want to disclaim warm code.
868+
if ((uintptr_t)_warmCodeAlloc > (uintptr_t)_smallPageAreaStart)
869+
{
870+
J9JavaVM * javaVM = jitConfig->javaVM;
871+
PORT_ACCESS_FROM_JAVAVM(javaVM); // for j9vmem_supported_page_sizes
872+
uintptr_t round = (uintptr_t)(j9vmem_supported_page_sizes()[0] - 1);
873+
disclaimStart = (uint8_t *)(((uintptr_t)_warmCodeAlloc + round) & ~round);
874+
if ((uintptr_t)disclaimStart >= (uintptr_t)_smallPageAreaEnd) // Nothing to disclaim
875+
return disclaimDone;
876+
}
877+
TR_ASSERT_FATAL((uintptr_t)_smallPageAreaEnd >= (uintptr_t)disclaimStart, "disclaimStart is past the cold area end");
827878

879+
size_t disclaimSize = _smallPageAreaEnd - disclaimStart;
828880
bool trace = TR::Options::getCmdLineOptions()->getVerboseOption(TR_VerbosePerformance);
829-
uint8_t *disclaim_start = _coldCodeAlloc;
830-
size_t pageSize = j9vmem_supported_page_sizes()[0];
831-
size_t round = pageSize - 1;
832-
disclaim_start = (uint8_t *)(((size_t)(disclaim_start + round)) & ~round);
833-
834-
if (_coldCodeAllocBase <= disclaim_start)
835-
return 0;
836-
837-
size_t disclaim_size = (_coldCodeAllocBase - disclaim_start + round) & ~round;
838-
839881
if (trace)
840882
{
841-
size_t warm_size = _warmCodeAlloc - _segment->segmentBase() + sizeof(this);
883+
size_t warm_size = _warmCodeAlloc - _warmCodeAllocBase;
842884
size_t cold_size = _coldCodeAllocBase - _coldCodeAlloc;
843885

844-
TR_VerboseLog::writeLineLocked(TR_Vlog_PERF, "Will disclaim cold code cache %p : coldStart=%p coldBase=%p warm_size=%zuB cold_size=%zuB cold_size/(cold_size + warm_size)=%5.2f%%",
845-
this, _coldCodeAlloc, _coldCodeAllocBase,
846-
warm_size, cold_size, cold_size * 100.0/(cold_size + warm_size));
886+
TR_VerboseLog::writeLineLocked(TR_Vlog_PERF, "Disclaim code cache %p between Start=%p End=%p. coldStart=%p coldBase=%p warm_size=%zuB cold_size=%zuB cold_size/(cold_size + warm_size)=%5.2f%%",
887+
this, disclaimStart, _smallPageAreaEnd, _coldCodeAlloc, _coldCodeAllocBase,
888+
warm_size, cold_size, cold_size * 100.0/(cold_size + warm_size));
847889
}
848890

849-
int32_t ret = madvise((void *)disclaim_start, disclaim_size, MADV_PAGEOUT);
891+
int32_t ret = madvise((void *)disclaimStart, disclaimSize, MADV_PAGEOUT);
850892

851893
if (ret != 0)
852894
{

runtime/compiler/runtime/J9CodeCache.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,12 @@ class OMR_EXTENSIBLE CodeCache : public OMR::CodeCacheConnector
119119
*/
120120
void resetAllocationPointers();
121121

122-
uint8_t * _warmCodeAllocBase; // used to reset the allocation pointers to initial values
123-
uint8_t * _coldCodeAllocBase;
122+
uint8_t *_warmCodeAllocBase; // used to reset the allocation pointers to initial values
123+
uint8_t *_coldCodeAllocBase;
124+
#ifdef LINUX
125+
uint8_t *_smallPageAreaStart; // used for code cache disclaiming to remember where the small page area starts/ends
126+
uint8_t *_smallPageAreaEnd;
127+
#endif
124128
};
125129

126130

0 commit comments

Comments
 (0)