From 3a50aeb25d3cd5fa9dfc7a9f9682e6d35d870fb1 Mon Sep 17 00:00:00 2001 From: Christian Despres Date: Wed, 10 Jul 2024 18:31:10 +0000 Subject: [PATCH] Send cached J9ROMClass hashes to JITServer 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 --- .../control/JITServerCompilationThread.cpp | 2 +- runtime/compiler/control/JITServerHelpers.cpp | 25 +++++--- runtime/compiler/control/JITServerHelpers.hpp | 5 +- runtime/compiler/net/CommunicationStream.hpp | 2 +- .../compiler/runtime/JITServerAOTCache.cpp | 64 +++++++++++-------- .../runtime/JITServerAOTDeserializer.cpp | 21 ++++++ .../runtime/JITServerAOTDeserializer.hpp | 2 + .../runtime/JITServerSharedROMClassCache.cpp | 4 +- .../runtime/JITServerSharedROMClassCache.hpp | 4 +- 9 files changed, 88 insertions(+), 41 deletions(-) diff --git a/runtime/compiler/control/JITServerCompilationThread.cpp b/runtime/compiler/control/JITServerCompilationThread.cpp index d82aa388991..e52c6b25426 100644 --- a/runtime/compiler/control/JITServerCompilationThread.cpp +++ b/runtime/compiler/control/JITServerCompilationThread.cpp @@ -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 { diff --git a/runtime/compiler/control/JITServerHelpers.cpp b/runtime/compiler/control/JITServerHelpers.cpp index 7623a49d951..95169d2057f 100644 --- a/runtime/compiler/control/JITServerHelpers.cpp +++ b/runtime/compiler/control/JITServerHelpers.cpp @@ -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); @@ -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) @@ -1100,7 +1109,7 @@ JITServerHelpers::getRemoteROMClass(J9Class *clazz, JITServer::ServerStream *str stream->write(JITServer::MessageType::ResolvedMethod_getRemoteROMClassAndMethods, clazz); auto recv = stream->read(); 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. @@ -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); } @@ -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); @@ -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; } @@ -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]); } } diff --git a/runtime/compiler/control/JITServerHelpers.hpp b/runtime/compiler/control/JITServerHelpers.hpp index 0caa6f0c371..2465c9c754d 100644 --- a/runtime/compiler/control/JITServerHelpers.hpp +++ b/runtime/compiler/control/JITServerHelpers.hpp @@ -87,7 +87,8 @@ class JITServerHelpers std::vector, // 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. @@ -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, diff --git a/runtime/compiler/net/CommunicationStream.hpp b/runtime/compiler/net/CommunicationStream.hpp index e3042992966..c43f0bfd441 100644 --- a/runtime/compiler/net/CommunicationStream.hpp +++ b/runtime/compiler/net/CommunicationStream.hpp @@ -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; diff --git a/runtime/compiler/runtime/JITServerAOTCache.cpp b/runtime/compiler/runtime/JITServerAOTCache.cpp index ce2ce087ef3..14f1464ee10 100644 --- a/runtime/compiler/runtime/JITServerAOTCache.cpp +++ b/runtime/compiler/runtime/JITServerAOTCache.cpp @@ -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); @@ -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; diff --git a/runtime/compiler/runtime/JITServerAOTDeserializer.cpp b/runtime/compiler/runtime/JITServerAOTDeserializer.cpp index ef761a16aa9..bf57876cbbb 100644 --- a/runtime/compiler/runtime/JITServerAOTDeserializer.cpp +++ b/runtime/compiler/runtime/JITServerAOTDeserializer.cpp @@ -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 std::string(); + 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 diff --git a/runtime/compiler/runtime/JITServerAOTDeserializer.hpp b/runtime/compiler/runtime/JITServerAOTDeserializer.hpp index 00779275655..f3a3646d369 100644 --- a/runtime/compiler/runtime/JITServerAOTDeserializer.hpp +++ b/runtime/compiler/runtime/JITServerAOTDeserializer.hpp @@ -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; diff --git a/runtime/compiler/runtime/JITServerSharedROMClassCache.cpp b/runtime/compiler/runtime/JITServerSharedROMClassCache.cpp index be814e6b551..90f74bf9868 100644 --- a/runtime/compiler/runtime/JITServerSharedROMClassCache.cpp +++ b/runtime/compiler/runtime/JITServerSharedROMClassCache.cpp @@ -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); } diff --git a/runtime/compiler/runtime/JITServerSharedROMClassCache.hpp b/runtime/compiler/runtime/JITServerSharedROMClassCache.hpp index 0745ba8f23f..2a877c8fa96 100644 --- a/runtime/compiler/runtime/JITServerSharedROMClassCache.hpp +++ b/runtime/compiler/runtime/JITServerSharedROMClassCache.hpp @@ -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