Skip to content

Commit

Permalink
Send cached J9ROMClass hashes to JITServer
Browse files Browse the repository at this point in the history
If a JITServer client has a cached hash for a ROMClass, it may now send
this hash to the server to avoid the server having to re-hash (and
possibly re-pack) the ROMClass received from the client. The server will
store this cached hash in its shared ROMClass cache. Currently, only the
stored hashes of generated classes are sent to the server.

Signed-off-by: Christian Despres <despresc@ibm.com>
  • Loading branch information
cjjdespres committed Jul 16, 2024
1 parent d2b02cf commit 6f7cfc7
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 41 deletions.
2 changes: 1 addition & 1 deletion runtime/compiler/control/JITServerCompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ TR::CompilationInfoPerThreadRemote::processEntry(TR_MethodToBeCompiled &entry, J
// If the client sent us the desired information in the compilation request, use that.
if(!(std::get<0>(classInfoTuple).empty()))
{
romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), clientSession->persistentMemory());
romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), std::get<25>(classInfoTuple), clientSession->persistentMemory());
}
else
{
Expand Down
25 changes: 17 additions & 8 deletions runtime/compiler/control/JITServerHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,12 +1052,17 @@ JITServerHelpers::packRemoteROMClassInfo(J9Class *clazz, J9VMThread *vmThread, T
}

std::string packedROMClassStr;
std::string romClassHash;
if (serializeClass)
{
TR::StackMemoryRegion stackMemoryRegion(*trMemory);
size_t hashedSize;
J9ROMClass *packedROMClass = packROMClass(clazz->romClass, trMemory, fe, hashedSize);
packedROMClassStr = std::string((const char *)packedROMClass, packedROMClass->romSize);

auto deserializer = fe->_compInfo->getJITServerAOTDeserializer();
if (deserializer)
romClassHash = deserializer->findGeneratedClassHash((J9ClassLoader *)classLoader, clazz, fe, vmThread);
}

int32_t arrayElementSize = vmThread->javaVM->internalVMFunctions->arrayElementSize((J9ArrayClass*)clazz);
Expand All @@ -1076,15 +1081,19 @@ JITServerHelpers::packRemoteROMClassInfo(J9Class *clazz, J9VMThread *vmThread, T
TR::Compiler->cls.getITable((TR_OpaqueClassBlock *)clazz), methodTracingInfo,
classHasFinalFields, classDepthAndFlags, classInitialized, byteOffsetToLockword, leafComponentClass,
classLoader, hostClass, componentClass, arrayClass, totalInstanceSize, clazz->romClass,
cp, classFlags, classChainOffsetIdentifyingLoader, origROMMethods, classNameIdentifyingLoader, arrayElementSize, defaultValueSlotAddress
cp, classFlags, classChainOffsetIdentifyingLoader, origROMMethods, classNameIdentifyingLoader, arrayElementSize,
defaultValueSlotAddress, romClassHash
);
}

J9ROMClass *
JITServerHelpers::romClassFromString(const std::string &romClassStr, TR_PersistentMemory *persistentMemory)
JITServerHelpers::romClassFromString(const std::string &romClassStr, const std::string &romClassHashStr, TR_PersistentMemory *persistentMemory)
{
if (auto cache = TR::CompilationInfo::get()->getJITServerSharedROMClassCache())
return cache->getOrCreate((const J9ROMClass *)romClassStr.data());
{
auto hash = romClassHashStr.empty() ? NULL : (const JITServerROMClassHash *)romClassHashStr.data();
return cache->getOrCreate((const J9ROMClass *)romClassStr.data(), hash);
}

auto romClass = (J9ROMClass *)persistentMemory->allocatePersistentMemory(romClassStr.size(), TR_Memory::ROMClass);
if (!romClass)
Expand All @@ -1100,7 +1109,7 @@ JITServerHelpers::getRemoteROMClass(J9Class *clazz, JITServer::ServerStream *str
stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz);
auto recv = stream->read<ClassInfoTuple>();
classInfoTuple = std::get<0>(recv);
return romClassFromString(std::get<0>(classInfoTuple), persistentMemory);
return romClassFromString(std::get<0>(classInfoTuple), std::get<25>(classInfoTuple), persistentMemory);
}

// Return true if able to get data from cache, return false otherwise.
Expand Down Expand Up @@ -1129,7 +1138,7 @@ JITServerHelpers::getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *cli
auto it = clientSessionData->getROMClassMap().find(clazz);
if (it == clientSessionData->getROMClassMap().end())
{
auto romClass = romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());
auto romClass = romClassFromString(std::get<0>(classInfoTuple), std::get<25>(classInfoTuple), clientSessionData->persistentMemory());
auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
JITServerHelpers::getROMClassData(classInfoStruct, dataType, data);
}
Expand Down Expand Up @@ -1168,7 +1177,7 @@ JITServerHelpers::getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *cli
auto it = clientSessionData->getROMClassMap().find(clazz);
if (it == clientSessionData->getROMClassMap().end())
{
auto romClass = romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());
auto romClass = romClassFromString(std::get<0>(classInfoTuple), std::get<25>(classInfoTuple), clientSessionData->persistentMemory());
auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
JITServerHelpers::getROMClassData(classInfoStruct, dataType1, data1);
JITServerHelpers::getROMClassData(classInfoStruct, dataType2, data2);
Expand Down Expand Up @@ -1408,7 +1417,7 @@ JITServerHelpers::getRemoteClassDepthAndFlagsWhenROMClassNotCached(J9Class *claz
auto it = clientSessionData->getROMClassMap().find(clazz);
if (it == clientSessionData->getROMClassMap().end())
{
auto romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), clientSessionData->persistentMemory());
auto romClass = JITServerHelpers::romClassFromString(std::get<0>(classInfoTuple), std::get<25>(classInfoTuple), clientSessionData->persistentMemory());
auto &classInfoStruct = JITServerHelpers::cacheRemoteROMClass(clientSessionData, clazz, romClass, classInfoTuple);
return classInfoStruct._classDepthAndFlags;
}
Expand Down Expand Up @@ -1467,7 +1476,7 @@ JITServerHelpers::cacheRemoteROMClassBatch(ClientSessionData *clientData, const

for (size_t i = 0; i < ramClasses.size(); ++i)
{
auto romClass = romClassFromString(std::get<0>(classInfoTuples[i]), clientData->persistentMemory());
auto romClass = romClassFromString(std::get<0>(classInfoTuples[i]), std::get<25>(classInfoTuples[i]), clientData->persistentMemory());
cacheRemoteROMClassOrFreeIt(clientData, ramClasses[i], romClass, classInfoTuples[i]);
}
}
Expand Down
5 changes: 3 additions & 2 deletions runtime/compiler/control/JITServerHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ class JITServerHelpers
std::vector<J9ROMMethod *>, // 21: _origROMMethods
std::string, // 22: _classNameIdentifyingLoader
int32_t, // 23: _arrayElementSize
j9object_t * // 24: _defaultValueSlotAddress
j9object_t *, // 24: _defaultValueSlotAddress
std::string // 25: optional hash of packedROMClass
>;

// Packs a ROMClass to be transferred to the server.
Expand All @@ -107,7 +108,7 @@ class JITServerHelpers
static J9ROMClass *getRemoteROMClassIfCached(ClientSessionData *clientSessionData, J9Class *clazz);
static J9ROMClass *getRemoteROMClass(J9Class *clazz, JITServer::ServerStream *stream,
TR_PersistentMemory *persistentMemory, ClassInfoTuple &classInfoTuple);
static J9ROMClass *romClassFromString(const std::string &romClassStr, TR_PersistentMemory *persistentMemory);
static J9ROMClass *romClassFromString(const std::string &romClassStr, const std::string &romClassHashStr, TR_PersistentMemory *persistentMemory);
static bool getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *clientSessionData,
JITServer::ServerStream *stream, ClassInfoDataType dataType, void *data);
static bool getAndCacheRAMClassInfo(J9Class *clazz, ClientSessionData *clientSessionData,
Expand Down
2 changes: 1 addition & 1 deletion runtime/compiler/net/CommunicationStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class CommunicationStream
// likely to lose an increment when merging/rebasing/etc.
//
static const uint8_t MAJOR_NUMBER = 1;
static const uint16_t MINOR_NUMBER = 64; // ID: EbRgDu72oycJkc90HtnO
static const uint16_t MINOR_NUMBER = 65; // ID: YxVkiLqD7B1LhYMv58y8
static const uint8_t PATCH_NUMBER = 0;
static uint32_t CONFIGURATION_FLAGS;

Expand Down
64 changes: 38 additions & 26 deletions runtime/compiler/runtime/JITServerAOTCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,48 +814,55 @@ JITServerAOTCache::getClassRecord(const AOTCacheClassLoaderRecord *classLoaderRe
auto cache = compInfo->getJITServerSharedROMClassCache();

JITServerROMClassHash hash;
size_t size = 0;
//NOTE: Assuming array classes are not runtime-generated
size_t prefixLength = numDimensions ? 0 : JITServerHelpers::getGeneratedClassNamePrefixLength(romClass);
if (prefixLength)

if (cache)
{
hash = cache->getHash(romClass);
}
else
{
// The class is runtime-generated. Re-pack the romClass to compute its deterministic hash.
J9ROMClass *packedROMClass;
if (scratchSegmentProvider)
const J9ROMClass *packedROMClass;
if (prefixLength)
{
// Called from outside of a compilation. Use supplied scratchSegmentProvider for scratch memory allocations.
size_t segmentSize = scratchSegmentProvider->getPreferredSegmentSize();
if (!segmentSize)
segmentSize = 1 << 24/*16 MB*/;
TR::RawAllocator rawAllocator(compInfo->getJITConfig()->javaVM);
J9::SystemSegmentProvider segmentProvider(1 << 16/*64 KB*/, segmentSize, TR::Options::getScratchSpaceLimit(),
*scratchSegmentProvider, rawAllocator);
TR::Region region(segmentProvider, rawAllocator);
TR_Memory trMemory(*compInfo->persistentMemory(), region);
packedROMClass = JITServerHelpers::packROMClass(romClass, &trMemory, NULL, size, 0, prefixLength);
// The class is runtime-generated. Re-pack the romClass to compute its deterministic hash.
if (scratchSegmentProvider)
{
// Called from outside of a compilation. Use supplied scratchSegmentProvider for scratch memory allocations.
size_t segmentSize = scratchSegmentProvider->getPreferredSegmentSize();
if (!segmentSize)
segmentSize = 1 << 24/*16 MB*/;
TR::RawAllocator rawAllocator(compInfo->getJITConfig()->javaVM);
J9::SystemSegmentProvider segmentProvider(1 << 16/*64 KB*/, segmentSize, TR::Options::getScratchSpaceLimit(),
*scratchSegmentProvider, rawAllocator);
TR::Region region(segmentProvider, rawAllocator);
TR_Memory trMemory(*compInfo->persistentMemory(), region);
size_t packedSize = 0;
packedROMClass = JITServerHelpers::packROMClass(romClass, &trMemory, NULL, packedSize, 0, prefixLength);
}
else
{
TR_ASSERT(TR::comp(), "Must be inside a compilation");
TR_Memory *trMemory = TR::comp()->trMemory();
TR::StackMemoryRegion region(*trMemory);
size_t packedSize = 0;
packedROMClass = JITServerHelpers::packROMClass(romClass, trMemory, NULL, packedSize, 0, prefixLength);
}
}
else
{
TR_ASSERT(TR::comp(), "Must be inside a compilation");
TR_Memory *trMemory = TR::comp()->trMemory();
TR::StackMemoryRegion region(*trMemory);
packedROMClass = JITServerHelpers::packROMClass(romClass, trMemory, NULL, size, 0, prefixLength);
packedROMClass = romClass;
}

hash = JITServerROMClassHash(packedROMClass);
}
else
{
hash = cache ? cache->getHash(romClass) : JITServerROMClassHash(romClass);
size = romClass->romSize;
}

if (numDimensions)
{
TR_ASSERT(baseComponent, "Invalid arguments");
JITServerROMClassHash baseHash = cache ? cache->getHash(baseComponent) : JITServerROMClassHash(baseComponent);
hash = JITServerROMClassHash(hash, baseHash, numDimensions);
size = romClass->romSize;
}

OMR::CriticalSection cs(_classMonitor);
Expand All @@ -867,7 +874,12 @@ JITServerAOTCache::getClassRecord(const AOTCacheClassLoaderRecord *classLoaderRe
if (!JITServerAOTCacheMap::cacheHasSpace())
return NULL;

auto record = AOTCacheClassRecord::create(_nextClassId, classLoaderRecord, hash, size,
// The romSize of the packed romClass received from the client is used as the size in the
// AOTCacheClassRecord. This will be slightly larger than the deterministic packed size if the romClass
// is runtime-generated, but this won't matter as long as we are consistent in what size is used.
// This also doesn't currently matter at the client, as runtime-generated classes are looked up by hash
// during deserialization, and the size in their class record is never examined.
auto record = AOTCacheClassRecord::create(_nextClassId, classLoaderRecord, hash, romClass->romSize,
prefixLength != 0, romClass, baseComponent, numDimensions);
addToMap(_classMap, _classHead, _classTail, it, getRecordKey(record), record);
++_nextClassId;
Expand Down
21 changes: 21 additions & 0 deletions runtime/compiler/runtime/JITServerAOTDeserializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,27 @@ JITServerAOTDeserializer::findGeneratedClass(J9ClassLoader *loader, const uint8_
return (h_it != n_it->second._classHashMap.end()) ? h_it->second : NULL;
}

std::string
JITServerAOTDeserializer::findGeneratedClassHash(J9ClassLoader *loader, J9Class *ramClass, TR_J9VM *fe, J9VMThread *vmThread)
{
assertSharedVmAccess(vmThread);

size_t namePrefixLength = JITServerHelpers::getGeneratedClassNamePrefixLength(ramClass->romClass);
if (namePrefixLength == 0)
return NULL;
const uint8_t *name = J9UTF8_DATA(J9ROMCLASS_CLASSNAME(ramClass->romClass));

OMR::CriticalSection cs(_generatedClassesMonitor);

auto n_it = _generatedClasses.find({ loader, StringKey(name, namePrefixLength) });
if (n_it == _generatedClasses.end())
return std::string();

auto h_it = n_it->second._classPtrMap.find(ramClass);
if (h_it == n_it->second._classPtrMap.end())
return std::string();
return std::string((const char *)&h_it->second, sizeof(h_it->second));
}

void
JITServerAOTDeserializer::printStats(FILE *f) const
Expand Down
2 changes: 2 additions & 0 deletions runtime/compiler/runtime/JITServerAOTDeserializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ class JITServerAOTDeserializer
// Find a runtime-generated class for given class loader, deterministic class name prefix, and ROMClass hash
J9Class *findGeneratedClass(J9ClassLoader *loader, const uint8_t *namePrefix, size_t namePrefixLength,
const JITServerROMClassHash &hash, J9VMThread *vmThread);
// Find the stored hash for ramClass loaded by loader if it exists in the generated classes map.
std::string findGeneratedClassHash(J9ClassLoader *loader, J9Class *ramClass, TR_J9VM *fe, J9VMThread *vmThread);
// Get the RAMClass for a previously deserialized ROMClass offset for a runtime-generated class
virtual J9Class *getGeneratedClass(J9ClassLoader *loader, uintptr_t romClassSccOffset, TR::Compilation *comp) = 0;

Expand Down
4 changes: 2 additions & 2 deletions runtime/compiler/runtime/JITServerSharedROMClassCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ JITServerSharedROMClassCache::shutdown(bool lastClient)


J9ROMClass *
JITServerSharedROMClassCache::getOrCreate(const J9ROMClass *packedROMClass)
JITServerSharedROMClassCache::getOrCreate(const J9ROMClass *packedROMClass, const JITServerROMClassHash *packedROMClassHash)
{
JITServerROMClassHash hash(packedROMClass);
JITServerROMClassHash hash = packedROMClassHash ? *packedROMClassHash : JITServerROMClassHash(packedROMClass);
return getPartition(hash).getOrCreate(packedROMClass, hash);
}

Expand Down
4 changes: 3 additions & 1 deletion runtime/compiler/runtime/JITServerSharedROMClassCache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ class JITServerSharedROMClassCache
// Releases memory used by the cache. Must be called when the last client session is destroyed.
void shutdown(bool lastClient = true);

J9ROMClass *getOrCreate(const J9ROMClass *packedROMClass);
// Get an existing cache entry for packedROMClass or create one. The packedROMClassHash may be NULL; if not,
// it will be the cached deterministic hash of packedROMClass received from the client.
J9ROMClass *getOrCreate(const J9ROMClass *packedROMClass, const JITServerROMClassHash *packedROMClassHash);
void release(J9ROMClass *romClass);

// Get precomputed hash of a shared ROMClass
Expand Down

0 comments on commit 6f7cfc7

Please sign in to comment.