Path: blob/master/runtime/compiler/control/CompilationThread.hpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2022 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#ifndef COMPILATIONTHREAD_INCL23#define COMPILATIONTHREAD_INCL2425#include <ctime>26#include "control/CompilationPriority.hpp"27#include "env/RawAllocator.hpp"28#include "j9.h"29#include "j9thread.h"30#include "j9cfg.h"31#include "env/VMJ9.h"32#include "control/rossa.h"33#include "env/CpuUtilization.hpp"34#include "infra/Statistics.hpp"35#include "control/Recompilation.hpp"36#include "control/RecompilationInfo.hpp"37#include "runtime/DataCache.hpp"38#include "infra/Monitor.hpp"39#include "ilgen/IlGenRequest.hpp"40#include "infra/MonitorTable.hpp"41#include "infra/RWMonitor.hpp"42#include "infra/Link.hpp"43#include "env/IO.hpp"44#include "runtime/RelocationRuntime.hpp"45#include "env/J9SegmentCache.hpp"46#if defined(J9VM_OPT_JITSERVER)47#include "env/VMJ9Server.hpp"48#include "env/PersistentCollections.hpp"49#endif /* defined(J9VM_OPT_JITSERVER) */5051#define METHOD_POOL_SIZE_THRESHOLD 6452#define MAX_SAMPLING_FREQUENCY 0x7FFFFFFF5354// Reasons for interrupting a compilation55const uint8_t GC_COMP_INTERRUPT = 1;56const uint8_t SHUTDOWN_COMP_INTERRUPT = 2;5758const int32_t IDLE_THRESHOLD = 50; // % CPU5960namespace TR { class Monitor; }61namespace TR { class PersistentInfo; }62namespace TR { class SegmentAllocator; }63namespace TR { class CompilationInfoPerThreadBase; } // forward declaration64namespace TR { class CompilationInfoPerThread; } // forward declaration65namespace TR { class CompilationInfo; } // forward declaration66struct TR_MethodToBeCompiled;67class TR_ResolvedMethod;68class TR_RelocationRuntime;69#if defined(J9VM_OPT_JITSERVER)70class ClientSessionData;71namespace JITServer72{73class ClientStream;74class ServerStream;75}76#endif /* defined(J9VM_OPT_JITSERVER) */7778enum CompilationThreadState79{80COMPTHREAD_UNINITIALIZED, // comp thread has not yet initialized81COMPTHREAD_ACTIVE, // comp thread is actively processing queue entries82COMPTHREAD_SIGNAL_WAIT, // comp transitioning to waiting on the queue83COMPTHREAD_WAITING, // comp thread is waiting on the queue84COMPTHREAD_SIGNAL_SUSPEND, // comp thread received suspension request85COMPTHREAD_SUSPENDED, // comp thread is waiting on the compThreadMonitor86COMPTHREAD_SIGNAL_TERMINATE, // compthread will terminate87COMPTHREAD_STOPPING, // compthread is terminating88COMPTHREAD_STOPPED, // compthread has terminated89COMPTHREAD_ABORT // compthread failed to initialize90};9192struct CompileParameters93{94CompileParameters(95TR::CompilationInfoPerThreadBase *compilationInfo,96TR_J9VMBase* vm,97J9VMThread * vmThread,98TR_RelocationRuntime *reloRuntime,99TR_OptimizationPlan * optimizationPlan,100TR::SegmentAllocator &scratchSegmentProvider,101TR::Region &dispatchRegion,102TR_Memory &trMemory,103const TR::CompileIlGenRequest &ilGenRequest104) :105_compilationInfo(compilationInfo),106_vm(vm),107_vmThread(vmThread),108_reloRuntime(reloRuntime),109_optimizationPlan(optimizationPlan),110_scratchSegmentProvider(scratchSegmentProvider),111_dispatchRegion(dispatchRegion),112_trMemory(trMemory),113_ilGenRequest(ilGenRequest)114{}115116TR_Memory *trMemory() { return &_trMemory; }117118TR::CompilationInfoPerThreadBase *_compilationInfo;119TR_J9VMBase *_vm;120J9VMThread *_vmThread;121TR_RelocationRuntime *_reloRuntime;122TR_OptimizationPlan*_optimizationPlan;123TR::SegmentAllocator &_scratchSegmentProvider;124TR::Region &_dispatchRegion;125TR_Memory &_trMemory;126TR::CompileIlGenRequest _ilGenRequest;127};128129#if defined(TR_HOST_S390)130struct timeval;131#endif132133class TR_DataCache;134135namespace TR {136137class CompilationInfoPerThreadBase138{139TR_PERSISTENT_ALLOC(TR_Memory::CompilationInfoPerThreadBase);140friend class TR::CompilationInfo;141public:142CompilationInfoPerThreadBase(TR::CompilationInfo &compInfo, J9JITConfig *jitConfig, int32_t id, bool onSeparateThread);143144TR::CompilationInfo *getCompilationInfo() { return &_compInfo; }145J9JITConfig *getJitConfig() { return _jitConfig; }146TR_MethodToBeCompiled *getMethodBeingCompiled() { return _methodBeingCompiled; }147void setMethodBeingCompiled(TR_MethodToBeCompiled *m) { _methodBeingCompiled = m; }148149CompilationThreadState getCompilationThreadState() {return _compilationThreadState;}150virtual void setCompilationThreadState(CompilationThreadState v);151bool compilationThreadIsActive();152TR::Compilation *getCompilation() { return _compiler; }153void setCompilation(TR::Compilation *compiler);154void zeroCompilation();155void printCompilationThreadTime();156TR_MethodMetaData *getMetadata() {return _metadata;}157void setMetadata(TR_MethodMetaData *m) {_metadata = m;}158void *compile(J9VMThread *context, TR_MethodToBeCompiled *entry, J9::J9SegmentProvider &scratchSegmentProvider);159TR_MethodMetaData *compile(J9VMThread *context, TR::Compilation *,160TR_ResolvedMethod *compilee, TR_J9VMBase &, TR_OptimizationPlan*, TR::SegmentAllocator const &scratchSegmentProvider);161TR_MethodMetaData *performAOTLoad(J9VMThread *context, TR::Compilation *, TR_ResolvedMethod *compilee, TR_J9VMBase *vm, J9Method *method);162163void preCompilationTasks(J9VMThread * vmThread,164TR_MethodToBeCompiled *entry,165J9Method *method,166const void **aotCachedMethod,167TR_Memory &trMemory,168bool &canDoRelocatableCompile,169bool &eligibleForRelocatableCompile,170TR_RelocationRuntime *reloRuntime);171172void *postCompilationTasks(J9VMThread * vmThread,173TR_MethodToBeCompiled *entry,174J9Method *method,175const void *aotCachedMethod,176TR_MethodMetaData *metaData,177bool canDoRelocatableCompile,178bool eligibleForRelocatableCompile,179TR_RelocationRuntime *reloRuntime);180const void* findAotBodyInSCC(J9VMThread *vmThread, const J9ROMMethod *romMethod);181bool isMethodIneligibleForAot(J9Method *method);182183#if defined(J9VM_OPT_SHARED_CLASSES) && defined(J9VM_INTERP_AOT_RUNTIME_SUPPORT)184TR_MethodMetaData *installAotCachedMethod(185J9VMThread *vmThread,186const void *aotCachedMethod,187J9Method *method,188TR_FrontEnd *fe,189TR::Options *options,190TR_ResolvedMethod *compilee,191TR_MethodToBeCompiled *entry,192TR::Compilation *compiler193);194#endif195196/*197* LdTM: This should, pedantically speaking, be an 'extern "C"' friend function rather than a static member function (with C++ linkage).198* However a brief search reveals that such an approach is fraught with its own set of compiler-bug-related risk.199*/200static TR_MethodMetaData *wrappedCompile(J9PortLibrary *portLib, void * opaqueParameters);201202bool methodCanBeCompiled(TR_Memory *trMemory, TR_FrontEnd *fe, TR_ResolvedMethod *compilee, TR_FilterBST *&filter);203int32_t getCompThreadId() const { return _compThreadId; }204205/**206* \brief207*208* An RAII class used to scope an interruptible operation on a compilation thread.209*210* \details211*212* Interruptible (\see InterruptibleOperation) and Uninterruptible (\see UninterruptibleOperation) operations related213* classes expressing whether the current compilation thread can terminate the compilation at the next yield point.214* The two classes can be intertwined and the logic of what happens when scopes mix is as follows:215*216* - Nesting an InterruptibleOperation under an UninterruptibleOperation acts as a NOP217* - Nesting an UninterruptibleOperation under an InterruptibleOperation results in an UninterruptibleOperation that218* once gone out of scope results in an InterruptibleOperation219*220* Put simply, an UninterruptibleOperation takes higher precedence over an InterruptibleOperation.221*/222class InterruptibleOperation223{224friend class TR::CompilationInfoPerThreadBase;225226public:227InterruptibleOperation(TR::CompilationInfoPerThreadBase &compThread) :228_compThread(compThread)229{230if (_compThread._uninterruptableOperationDepth == 0)231{232_compThread._compilationCanBeInterrupted = true;233}234}235236~InterruptibleOperation()237{238if (_compThread._uninterruptableOperationDepth == 0)239{240_compThread._compilationCanBeInterrupted = false;241}242}243244private:245TR::CompilationInfoPerThreadBase & _compThread;246};247248/**249* \brief250*251* An RAII class used to scope an uninterruptible operation on a compilation thread.252*253* \details254*255* Interruptible (\see InterruptibleOperation) and Uninterruptible (\see UninterruptibleOperation) operations related256* classes expressing whether the current compilation thread can terminate the compilation at the next yield point.257* The two classes can be intertwined and the logic of what happens when scopes mix is as follows:258*259* - Nesting an InterruptibleOperation under an UninterruptibleOperation acts as a NOP260* - Nesting an UninterruptibleOperation under an InterruptibleOperation results in an UninterruptibleOperation that261* once gone out of scope results in an InterruptibleOperation262*263* Put simply, an UninterruptibleOperation takes higher precedence over an InterruptibleOperation.264*/265class UninterruptibleOperation266{267friend class TR::CompilationInfoPerThreadBase;268269public:270UninterruptibleOperation(TR::CompilationInfoPerThreadBase &compThread) :271_compThread(compThread), _originalValue(_compThread._compilationCanBeInterrupted)272{273_compThread._compilationCanBeInterrupted = false;274_compThread._uninterruptableOperationDepth++;275}276277~UninterruptibleOperation()278{279_compThread._compilationCanBeInterrupted = _originalValue;280_compThread._uninterruptableOperationDepth--;281}282283private:284TR::CompilationInfoPerThreadBase & _compThread;285286/// Represents the original value of whether the compilation can be interrupted before executing the287/// uninterruptable operation288bool _originalValue;289};290291uint8_t compilationShouldBeInterrupted() const292{293return _compilationCanBeInterrupted ? _compilationShouldBeInterrupted : 0;294}295296void setCompilationShouldBeInterrupted(uint8_t reason) { _compilationShouldBeInterrupted = reason; }297TR_DataCache* reservedDataCache() { return _reservedDataCache; }298void setReservedDataCache(TR_DataCache *dataCache) { _reservedDataCache = dataCache; }299int32_t getNumJITCompilations() const { return _numJITCompilations; }300void incNumJITCompilations() { _numJITCompilations++; }301int32_t getQszWhenCompStarted() const { return _qszWhenCompStarted; }302void generatePerfToolEntry(); // for Linux only303uintptr_t getTimeWhenCompStarted() const { return _timeWhenCompStarted; }304void setTimeWhenCompStarted(UDATA t) { _timeWhenCompStarted = t; }305306TR_RelocationRuntime *reloRuntime();307static TR::FILE *getPerfFile() { return _perfFile; } // used on Linux for perl tool support308static void setPerfFile(TR::FILE *f) { _perfFile = f; }309310#if defined(J9VM_OPT_JITSERVER)311void setClientData(ClientSessionData *data) { _cachedClientDataPtr = data; }312ClientSessionData *getClientData() const { return _cachedClientDataPtr; }313314void setClientStream(JITServer::ClientStream *stream) { _clientStream = stream; }315JITServer::ClientStream *getClientStream() const { return _clientStream; }316317/**318@brief After this method runs, all subsequent persistent allocations319on the current thread for a given client will use a per-client allocator,320instead of the global one.321*/322void enterPerClientAllocationRegion();323324/**325@brief Ends per-client allocation on this thread. After this method returns,326all allocations will use the global persistent allocator.327*/328void exitPerClientAllocationRegion();329TR_PersistentMemory *getPerClientPersistentMemory() { return _perClientPersistentMemory; }330331/**332@brief Heuristic that returns true if compiling a method of given size333and at given optimization level less is likely to consume little334memory relative to what the JVM has at its disposal335*/336bool isMemoryCheapCompilation(uint32_t bcsz, TR_Hotness optLevel);337/**338@brief Heuristic that returns true if compiling a method of given size339and at given optimization level less is likely to consume little340CPU relative to what the JVM has at its disposal341*/342bool isCPUCheapCompilation(uint32_t bcsz, TR_Hotness optLevel);343/**344@brief Returns true if we truly cannot perform a remote compilation345maybe because the server is not compatible, is not available, etc.346347Note, that if this query returns false, it is not guaranteed that we348can do a remote compilation, because the server could have died since349we last checked.350*/351bool cannotPerformRemoteComp();352/**353@brief Returns true if heuristics determine that we have the resources to perform354this compilation locally, rather than offloading it to the remote server.355*/356bool preferLocalComp(const TR_MethodToBeCompiled *entry);357358359bool compilationCanBeInterrupted() const { return _compilationCanBeInterrupted; }360361void downgradeLocalCompilationIfLowPhysicalMemory(TR_MethodToBeCompiled *entry);362363#endif /* defined(J9VM_OPT_JITSERVER) */364365protected:366367TR::CompilationInfo & _compInfo;368J9JITConfig * const _jitConfig;369TR_SharedCacheRelocationRuntime _sharedCacheReloRuntime;370#if defined(J9VM_OPT_JITSERVER)371TR_JITServerRelocationRuntime _remoteCompileReloRuntime;372#endif /* defined(J9VM_OPT_JITSERVER) */373int32_t const _compThreadId; // unique number starting from 0; Only used for compilation on separate thread374bool const _onSeparateThread;375376TR_J9VMBase * _vm;377TR_MethodToBeCompiled * _methodBeingCompiled;378TR::Compilation * _compiler;379TR_MethodMetaData * _metadata;380TR_DataCache * _reservedDataCache;381uintptr_t _timeWhenCompStarted;382int32_t _numJITCompilations; // num JIT compilations this thread has performed; AOT loads not counted383int32_t _qszWhenCompStarted; // size of compilation queue and compilation starts384385/// Determines whether this compilation thread can be interrupted the compile at the next yield point. A different386/// thread may still request that the compilation _should_ be interrupted, however we may not be in a state at387/// which we _can_ interrupt.388bool _compilationCanBeInterrupted;389390/// Counts the number of nested \see UninterruptibleOperation in the stack. An \see InterruptibleOperation can only391/// be issued if the depth of uninterruptable operations is 0.392int32_t _uninterruptableOperationDepth;393394bool _addToJProfilingQueue;395396volatile CompilationThreadState _compilationThreadState;397volatile CompilationThreadState _previousCompilationThreadState;398volatile uint8_t _compilationShouldBeInterrupted;399400static TR::FILE *_perfFile; // used on Linux for perl tool support401402#if defined(J9VM_OPT_JITSERVER)403ClientSessionData * _cachedClientDataPtr;404JITServer::ClientStream * _clientStream;405TR_PersistentMemory * _perClientPersistentMemory;406#endif /* defined(J9VM_OPT_JITSERVER) */407408private:409void logCompilationSuccess(410J9VMThread *vmThread,411TR_J9VMBase & vm,412J9Method * method,413const TR::SegmentAllocator &scratchSegmentProvider,414TR_ResolvedMethod * compilee,415TR::Compilation *compiler,416TR_MethodMetaData *metadata,417TR_OptimizationPlan * optimizationPlan);418419void processException(420J9VMThread *vmThread,421const TR::SegmentAllocator &scratchSegmentProvider,422TR::Compilation * compiler,423volatile bool & haveLockedClassUnloadMonitor,424const char *exceptionName425) throw();426427void processExceptionCommonTasks(428J9VMThread *vmThread,429TR::SegmentAllocator const &scratchSegmentProvider,430TR::Compilation * compiler,431const char *exceptionName);432433#if defined(TR_HOST_S390)434void outputVerboseMMapEntry(435TR_ResolvedMethod *compilee,436const struct ::tm &date,437const struct timeval &time,438void *startPC,439void *endPC,440const char *fmt,441const char *profiledString,442const char *compileString443);444void outputVerboseMMapEntries(445TR_ResolvedMethod *compilee,446TR_MethodMetaData *metaData,447const char *profiledString,448const char *compileString449);450#endif451452}; // CompilationInfoPerThreadBase453}454455//--------------------------------------------------------------------456// The following class will be use by the separate compilation threads457// TR::CompilationInfoPerThreadBase will be used by compilation on application thread458459namespace TR460{461462class CompilationInfoPerThread : public TR::CompilationInfoPerThreadBase463{464friend class TR::CompilationInfo;465public:466CompilationInfoPerThread(TR::CompilationInfo &compInfo, J9JITConfig *jitConfig, int32_t id, bool isDiagnosticThread);467bool initializationSucceeded() { return _initializationSucceeded; }468j9thread_t getOsThread() { return _osThread; }469void setOsThread(j9thread_t t) { _osThread = t; }470J9VMThread *getCompilationThread() {return _compilationThread;}471void setCompilationThread(J9VMThread *t) { _compilationThread = t; }472int32_t getCompThreadPriority() const { return _compThreadPriority; }473void setCompThreadPriority(int32_t priority) { _compThreadPriority = priority; }474int32_t changeCompThreadPriority(int32_t priority, int32_t locationCode);475TR::Monitor *getCompThreadMonitor() { return _compThreadMonitor; }476void run();477void processEntries();478virtual void processEntry(TR_MethodToBeCompiled &entry, J9::J9SegmentProvider &scratchSegmentProvider);479bool shouldPerformCompilation(TR_MethodToBeCompiled &entry);480void waitForWork();481void doSuspend();482void suspendCompilationThread();483void resumeCompilationThread();484void requeue(); // requeue only works for compilation on separate thread485virtual void setCompilationThreadState(CompilationThreadState v);486void waitForGCCycleMonitor(bool threadHasVMAccess);487char *getActiveThreadName() const { return _activeThreadName; }488char *getSuspendedThreadName() const { return _suspendedThreadName; }489int64_t getLastTimeThreadWasSuspended() const { return _lastTimeThreadWasSuspended; }490void setLastTimeThreadWasSuspended(int64_t t) { _lastTimeThreadWasSuspended = t; }491int64_t getLastTimeThreadWentToSleep() const { return _lastTimeThreadWentToSleep; }492void setLastTimeThreadWentToSleep(int64_t t) { _lastTimeThreadWentToSleep = t; }493int32_t getLastCompilationDuration() const { return _lastCompilationDuration; }494void setLastCompilationDuration(int32_t t) { _lastCompilationDuration = t; }495bool isDiagnosticThread() const { return _isDiagnosticThread; }496CpuSelfThreadUtilization& getCompThreadCPU() { return _compThreadCPU; }497TR::FILE *getRTLogFile() { return _rtLogFile; }498virtual void freeAllResources();499500#if defined(J9VM_OPT_JITSERVER)501TR_J9ServerVM *getServerVM() const { return _serverVM; }502void setServerVM(TR_J9ServerVM *vm) { _serverVM = vm; }503TR_J9SharedCacheServerVM *getSharedCacheServerVM() const { return _sharedCacheServerVM; }504void setSharedCacheServerVM(TR_J9SharedCacheServerVM *vm) { _sharedCacheServerVM = vm; }505JITServer::ServerStream *getStream();506J9ROMClass *getAndCacheRemoteROMClass(J9Class *clazz);507J9ROMClass *getRemoteROMClassIfCached(J9Class *clazz);508PersistentUnorderedSet<TR_OpaqueClassBlock*> *getClassesThatShouldNotBeNewlyExtended() const { return _classesThatShouldNotBeNewlyExtended; }509#endif /* defined(J9VM_OPT_JITSERVER) */510511protected:512J9::J9SegmentCache initializeSegmentCache(J9::J9SegmentProvider &segmentProvider);513514j9thread_t _osThread;515J9VMThread *_compilationThread;516int32_t _compThreadPriority; // to reduce number of checks517TR::Monitor *_compThreadMonitor;518char *_activeThreadName; // name of thread when active519char *_suspendedThreadName; // name of thread when suspended520uint64_t _lastTimeThreadWasSuspended; // RAS; only accessed by the thread itself521uint64_t _lastTimeThreadWentToSleep; // RAS; only accessed by the thread itself522int32_t _lastCompilationDuration; // wall clock, ms523bool _initializationSucceeded;524bool _isDiagnosticThread;525CpuSelfThreadUtilization _compThreadCPU;526TR::FILE *_rtLogFile;527#if defined(J9VM_OPT_JITSERVER)528TR_J9ServerVM *_serverVM;529TR_J9SharedCacheServerVM *_sharedCacheServerVM;530// The following hastable caches <classLoader,classname> --> <J9Class> mappings531// The cache only lives during a compilation due to class unloading concerns532PersistentUnorderedSet<TR_OpaqueClassBlock*> *_classesThatShouldNotBeNewlyExtended;533#endif /* defined(J9VM_OPT_JITSERVER) */534535}; // CompilationInfoPerThread536537#if defined(J9VM_OPT_JITSERVER)538extern thread_local TR::CompilationInfoPerThread * compInfoPT;539#endif /* defined(J9VM_OPT_JITSERVER) */540541} // namespace TR542543#endif // COMPILATIONTHREAD_INCL544545546