Path: blob/master/runtime/compiler/control/CompilationController.cpp
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#include "control/CompilationController.hpp"2324#include "codegen/PrivateLinkage.hpp"25#include "compile/Compilation.hpp"26#include "compile/CompilationTypes.hpp"27#include "control/MethodToBeCompiled.hpp"28#include "control/OptimizationPlan.hpp"29#include "control/Recompilation.hpp"30#include "control/RecompilationInfo.hpp"31#include "env/IO.hpp"32#include "env/TRMemory.hpp"33#include "env/VerboseLog.hpp"34#include "ilgen/IlGeneratorMethodDetails_inlines.hpp"35#include "infra/Monitor.hpp"36#include "runtime/CodeCacheManager.hpp"37#include "control/CompilationRuntime.hpp"38#include "env/ut_j9jit.h"39#include "env/CompilerEnv.hpp"4041// NOTE: TR::CompilationController is actually defined in control/OptimizationPlan.hpp4243TR::CompilationStrategy *TR::CompilationController::_compilationStrategy = NULL;44TR::CompilationInfo * TR::CompilationController::_compInfo = 0;45int32_t TR::CompilationController::_verbose = 0;46bool TR::CompilationController::_useController = false;47bool TR::CompilationController::_tlsCompObjCreated = false;484950//------------------------------------ init -----------------------------------51// Initializes the compilationController.52// Return false if it fails53//-----------------------------------------------------------------------------54bool TR::CompilationController::init(TR::CompilationInfo *compInfo)55{56_useController = false; // Default to failure57_compilationStrategy = 0; // Default to failure58TR::Options *options = TR::Options::getCmdLineOptions();59char *strategyName = options->getCompilationStrategyName();6061if (strategyName && strcmp(strategyName, "none"))62{63_compInfo = compInfo;64if (strcmp(strategyName, "default") == 0)65_compilationStrategy = new (PERSISTENT_NEW) TR::DefaultCompilationStrategy();66else if (strcmp(strategyName, "threshold") == 0)67_compilationStrategy = new (PERSISTENT_NEW) TR::ThresholdCompilationStrategy();68else // if no match, use default69{70_compilationStrategy = new (PERSISTENT_NEW) TR::DefaultCompilationStrategy();71}7273if (_compilationStrategy)74{75TR_OptimizationPlan::_optimizationPlanMonitor = TR::Monitor::create("OptimizationPlanMonitor");76_useController = (TR_OptimizationPlan::_optimizationPlanMonitor != 0);77if (_useController)78{79static char *verboseController = feGetEnv("TR_VerboseController");80if (verboseController)81setVerbose(atoi(verboseController));82if (verbose() >= LEVEL1)83fprintf(stderr, "Using %s comp strategy\n", strategyName);84}85}86}87//TR_ASSERT(_useController, "Must use compilation controller");88//#ifdef COMP_YIELD_ANALYSIS89if (options->getOption(TR_EnableCompYieldStats))90TR::Compilation::allocateCompYieldStatsMatrix();91tlsAlloc(OMR::compilation);92_tlsCompObjCreated = true;93return _useController;94}959697//-------------------------------- shutdown ---------------------------------98// Called at shutdown time after compilation thread has been stopped99// --------------------------------------------------------------------------100void TR::CompilationController::shutdown()101{102if (_tlsCompObjCreated)103tlsFree(OMR::compilation);104if (!_useController)105return;106// would like to free all entries in the pool of compilation plans107int32_t remainingPlans = TR_OptimizationPlan::freeEntirePool();108// print some stats109if (verbose() >= LEVEL1)110{111fprintf(stderr, "Remaining optimizations plans in the system: %d\n", remainingPlans);112}113_compilationStrategy->shutdown();114}115116117//======================== DefaultCompilationStrategy ==========================118119120121TR::DefaultCompilationStrategy::DefaultCompilationStrategy()122{123// initialize the statistics124for (int32_t i=0; i < TR_MethodEvent::NumEvents; i++)125_statEventType[i] = 0;126}127128129void TR::DefaultCompilationStrategy::shutdown()130{131// printing stats132if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL1)133{134fprintf(stderr, "Stats for type of events:\n");135for (int32_t i=0; i < TR_MethodEvent::NumEvents; i++)136fprintf(stderr, "EventType:%d cases:%u\n", i, _statEventType[i]);137}138}139140141TR_Hotness TR::DefaultCompilationStrategy::getInitialOptLevel(J9Method *j9method)142{143J9ROMMethod *romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(j9method);144return TR::Options::getInitialHotnessLevel(J9ROMMETHOD_HAS_BACKWARDS_BRANCHES(romMethod) ? true : false);145}146147148//------------------------------- processEvent ------------------------149// If the function returns NULL, then the value of *newPlanCreated is150// undefined and should not be tested151//---------------------------------------------------------------------152TR_OptimizationPlan *TR::DefaultCompilationStrategy::processEvent(TR_MethodEvent *event, bool *newPlanCreated)153{154TR_OptimizationPlan *plan = NULL, *attachedPlan = NULL;155TR_Hotness hotnessLevel;156TR_PersistentJittedBodyInfo *bodyInfo;157TR_PersistentMethodInfo *methodInfo;158TR::CompilationInfo *compInfo = TR::CompilationController::getCompilationInfo();159160if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL3)161fprintf(stderr, "Event %d\n", event->_eventType);162163// first decode the event type164switch (event->_eventType)165{166case TR_MethodEvent::JittedMethodSample:167compInfo->_stats._sampleMessagesReceived++;168plan = processJittedSample(event);169*newPlanCreated = true;170break;171case TR_MethodEvent::InterpretedMethodSample:172compInfo->_stats._sampleMessagesReceived++;173plan = processInterpreterSample(event);174*newPlanCreated = true;175break;176case TR_MethodEvent::InterpreterCounterTripped:177TR_ASSERT(event->_oldStartPC == 0, "oldStartPC should be 0 for an interpreted method");178compInfo->_stats._methodsCompiledOnCount++;179// most likely we need to compile the method, unless it's already being compiled180// even if the method is already queued for compilation we must still invoke181// compilemethod because we may need to do a async compilation and the thread182// needs to block183184// use the counts to determine the first level of compilation185// the level of compilation can be changed later on if option subsets are present186hotnessLevel = TR::DefaultCompilationStrategy::getInitialOptLevel(event->_j9method);187if (hotnessLevel == veryHot && // we probably want to profile188!TR::Options::getCmdLineOptions()->getOption(TR_DisableProfiling) &&189TR::Recompilation::countingSupported() &&190!TR::CodeCacheManager::instance()->almostOutOfCodeCache())191plan = TR_OptimizationPlan::alloc(hotnessLevel, true, false);192else193plan = TR_OptimizationPlan::alloc(hotnessLevel);194*newPlanCreated = true;195// the optimization plan needs to include opt level and if we do profiling196// these may change197break;198case TR_MethodEvent::JitCompilationInducedByDLT:199hotnessLevel = TR::DefaultCompilationStrategy::getInitialOptLevel(event->_j9method);200plan = TR_OptimizationPlan::alloc(hotnessLevel);201if (plan)202plan->setInducedByDLT(true);203*newPlanCreated = true;204break;205case TR_MethodEvent::OtherRecompilationTrigger: // sync recompilation through fixMethodCode or recomp triggered from jitted code (like counting recompilation)206// For sync re-compilation we have attached a plan to the persistentBodyInfo207bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);208methodInfo = bodyInfo->getMethodInfo();209210if (methodInfo->getReasonForRecompilation() == TR_PersistentMethodInfo::RecompDueToInlinedMethodRedefinition ||211(methodInfo->getReasonForRecompilation() == TR_PersistentMethodInfo::RecompDueToJProfiling && !bodyInfo->getIsProfilingBody())) // if the recompilation is triggered from a JProfiling block but not in a profiled compilation keep the current compilation level unchanged212{213hotnessLevel = bodyInfo->getHotness();214plan = TR_OptimizationPlan::alloc(hotnessLevel);215*newPlanCreated = true;216}217else218{219hotnessLevel = TR::Recompilation::getNextCompileLevel(event->_oldStartPC);220plan = TR_OptimizationPlan::alloc(hotnessLevel);221*newPlanCreated = true;222}223224TR_OptimizationPlan::_optimizationPlanMonitor->enter();225attachedPlan = methodInfo->_optimizationPlan;226if (attachedPlan)227{228TR_ASSERT(!TR::CompilationController::getCompilationInfo()->asynchronousCompilation(),229"This case should happen only for sync recompilation");230plan->clone(attachedPlan); // override231}232TR_OptimizationPlan::_optimizationPlanMonitor->exit();233break;234case TR_MethodEvent::NewInstanceImpl:235// use the counts to determine the first level of compilation236// the level of compilation can be changed later on if option subsets are present237hotnessLevel = TR::Options::getInitialHotnessLevel(false);238plan = TR_OptimizationPlan::alloc(hotnessLevel);239*newPlanCreated = true;240break;241case TR_MethodEvent::ShareableMethodHandleThunk:242case TR_MethodEvent::CustomMethodHandleThunk:243// TODO: methodInfo->setWasNeverInterpreted()244hotnessLevel = TR::DefaultCompilationStrategy::getInitialOptLevel(event->_j9method);245if (hotnessLevel < warm && event->_eventType == TR_MethodEvent::CustomMethodHandleThunk)246hotnessLevel = warm; // Custom thunks benefit a LOT from warm opts like preexistence and repeated inlining passes247plan = TR_OptimizationPlan::alloc(hotnessLevel);248// plan->setIsForcedCompilation(); // TODO:JSR292: Seems reasonable, but somehow it crashes249plan->setUseSampling(false); // We don't yet support sampling-based recompilation of MH thunks250*newPlanCreated = true;251break;252case TR_MethodEvent::MethodBodyInvalidated:253// keep the same optimization level254bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);255TR_ASSERT(bodyInfo, "A recompilable method should have jittedBodyInfo");256hotnessLevel = bodyInfo->getHotness();257plan = TR_OptimizationPlan::alloc(hotnessLevel);258*newPlanCreated = true;259bodyInfo->getMethodInfo()->incrementNumberOfInvalidations();260261// the following is just for compatibility with older implementation262//bodyInfo->getMethodInfo()->setNextCompileLevel(hotnessLevel, false); // no profiling263break;264case TR_MethodEvent::HWPRecompilationTrigger:265{266plan = processHWPSample(event);267}268break;269default:270TR_ASSERT(0, "Bad event type %d", event->_eventType);271}272273_statEventType[event->_eventType]++; // statistics274275if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL2)276fprintf(stderr, "Event %d created plan %p\n", event->_eventType, plan);277278return plan;279}280281282283//--------------------- processInterpreterSample ----------------------284TR_OptimizationPlan *285TR::DefaultCompilationStrategy::processInterpreterSample(TR_MethodEvent *event)286{287// Sampling an interpreted method. The method could have been already288// compiled (but we got a sample in the old interpreted body).289//290TR_OptimizationPlan *plan = 0;291TR::Options * cmdLineOptions = TR::Options::getCmdLineOptions();292J9Method *j9method = event->_j9method;293J9JITConfig *jitConfig = event->_vmThread->javaVM->jitConfig;294TR::CompilationInfo *compInfo = 0;295if (jitConfig)296compInfo = TR::CompilationInfo::get(jitConfig);297TR_J9VMBase *fe = TR_J9VMBase::get(jitConfig, event->_vmThread);298299int32_t totalSampleCount = TR::Recompilation::globalSampleCount;300char msg[350]; // size should be big enough to hold the whole one-line msg301msg[0] = 0;302char *curMsg = msg;303bool logSampling = fe->isLogSamplingSet() || TrcEnabled_Trc_JIT_Sampling_Detail;304#define SIG_SZ 150305char sig[SIG_SZ]; // hopefully the size is good for most cases306307J9ROMMethod * romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(j9method);308bool loopy = J9ROMMETHOD_HAS_BACKWARDS_BRANCHES(romMethod) ? true : false;309310if (logSampling || TrcEnabled_Trc_JIT_Sampling)311{312fe->printTruncatedSignature(sig, SIG_SZ, (TR_OpaqueMethodBlock*)j9method);313314if (logSampling)315curMsg += sprintf(curMsg, "(%d)\tInterpreted %s\t", totalSampleCount, sig);316if (TrcEnabled_Trc_JIT_Sampling && ((totalSampleCount % 4) == 0))317Trc_JIT_Sampling(getJ9VMThreadFromTR_VM(fe), "Interpreted", sig, 0);318}319320compInfo->_stats._interpretedMethodSamples++;321322if (!TR::CompilationInfo::isCompiled(j9method))323{324int32_t count = TR::CompilationInfo::getInvocationCount(j9method);325// the count will be -1 for JNI or if extra is negative326if (!cmdLineOptions->getOption(TR_DisableInterpreterSampling))327{328// If the method is an interpreted non-JNI method, the last slot in329// the RAM method is an invocation count. See if it is reasonable330// to reduce the invocation count since this method has been sampled.331//332if (count > 0)333{334int32_t threshold, divisor;335/* Modify thresholds for JSR292 methods */336bool isJSR292Method = _J9ROMMETHOD_J9MODIFIER_IS_SET((J9_ROM_METHOD_FROM_RAM_METHOD(j9method)), J9AccMethodHasMethodHandleInvokes );337if (jitConfig->javaVM->phase != J9VM_PHASE_NOT_STARTUP)338{339threshold = isJSR292Method ? TR::Options::_interpreterSamplingThresholdInJSR292 : TR::Options::_interpreterSamplingThresholdInStartupMode;340divisor = TR::Options::_interpreterSamplingDivisorInStartupMode;341}342else343{344threshold = isJSR292Method ? TR::Options::_interpreterSamplingThresholdInJSR292 : TR::Options::_interpreterSamplingThreshold;345divisor = TR::Options::_interpreterSamplingDivisor;346}347int32_t activeThreadsThreshold = TR::Options::_activeThreadsThreshold;348if (activeThreadsThreshold == -1) // -1 means we want to determine this dynamically349activeThreadsThreshold = compInfo->getNumAppThreadsActive();350351if (count <= threshold && count > activeThreadsThreshold)352{353// This is an interpreted method that can be compiled.354// Reduce the invocation count.355//356int32_t newCount = count / divisor;357// Don't decrement more than the number of active threads358if (newCount < activeThreadsThreshold)359newCount = activeThreadsThreshold;360if (TR::CompilationInfo::setInvocationCount(j9method, count, newCount))361{362if (logSampling)363curMsg += sprintf(curMsg, " reducing count %d --> %d", count, newCount);364if (cmdLineOptions->getOption(TR_UseSamplingJProfilingForInterpSampledMethods))365compInfo->getInterpSamplTrackingInfo()->addOrUpdate(j9method, count - newCount);366}367else368{369if (logSampling)370curMsg += sprintf(curMsg, " count = %d, already changed", count);371}372373// If the method is ready to be compiled and we are using a separate374// compilation thread, get a head start by scheduling the compilation375// now376//377if (newCount == 0 && fe->isAsyncCompilation())378{379if (TR::Options::_compilationDelayTime <= 0 ||380compInfo->getPersistentInfo()->getElapsedTime() >= 1000 * TR::Options::_compilationDelayTime)381plan = TR_OptimizationPlan::alloc(getInitialOptLevel(j9method));382}383}384else if (returnIprofilerState() == IPROFILING_STATE_OFF)385{386int32_t newCount = 0;387if (cmdLineOptions->getOption(TR_SubtractMethodCountsWhenIprofilerIsOff))388newCount = count - TR::Options::_IprofilerOffSubtractionFactor;389else390newCount = count / TR::Options::_IprofilerOffDivisionFactor;391392if (newCount < 0)393newCount = 0;394395if (TR::CompilationInfo::setInvocationCount(j9method, count, newCount))396{397if (logSampling)398curMsg += sprintf(curMsg, " reducing count %d --> %d", count, newCount);399if (cmdLineOptions->getOption(TR_UseSamplingJProfilingForInterpSampledMethods))400compInfo->getInterpSamplTrackingInfo()->addOrUpdate(j9method, count - newCount);401}402else403{404if (logSampling)405curMsg += sprintf(curMsg, " count = %d, already changed", count);406}407}408else if (loopy && count > activeThreadsThreshold)409{410int32_t newCount = 0;411if (cmdLineOptions->getOption(TR_SubtractLoopyMethodCounts))412newCount = count - TR::Options::_LoopyMethodSubtractionFactor;413else414newCount = count / TR::Options::_LoopyMethodDivisionFactor;415416if (newCount < 0)417newCount = 0;418if (newCount < activeThreadsThreshold)419newCount = activeThreadsThreshold;420if (TR::CompilationInfo::setInvocationCount(j9method, count, newCount))421{422if (logSampling)423curMsg += sprintf(curMsg, " reducing count %d --> %d", count, newCount);424if (cmdLineOptions->getOption(TR_UseSamplingJProfilingForInterpSampledMethods))425compInfo->getInterpSamplTrackingInfo()->addOrUpdate(j9method, count - newCount);426}427else428{429if (logSampling)430curMsg += sprintf(curMsg, " count = %d, already changed", count);431}432}433else434{435if (logSampling)436curMsg += sprintf(curMsg, " count = %d / %d", count, threshold);437}438}439else if (count == 0)440{441// Possible scenario: a long activation method receives a MIL count of 1.442// The method gets invoked and the count becomes 0 (but the compilation is not443// triggered now, only when the counter would become negative).444// The method receives a sample while still being interpreted. We should probably445// schedule a compilation446if (logSampling)447curMsg += sprintf(curMsg, " count = 0 (long running?)");448if (fe->isAsyncCompilation())449{450if (TR::Options::_compilationDelayTime <= 0 ||451compInfo->getPersistentInfo()->getElapsedTime() >= 1000 * TR::Options::_compilationDelayTime)452plan = TR_OptimizationPlan::alloc(getInitialOptLevel(j9method));453}454}455else // count==-1456{457if (TR::CompilationInfo::getJ9MethodVMExtra(j9method) == J9_JIT_QUEUED_FOR_COMPILATION)458{459if (logSampling)460curMsg += sprintf(curMsg, " already queued");461if (compInfo &&462(compInfo->compBudgetSupport() || compInfo->dynamicThreadPriority()))463{464fe->acquireCompilationLock();465int32_t n = compInfo->promoteMethodInAsyncQueue(j9method, 0);466fe->releaseCompilationLock();467if (logSampling)468{469if (n > 0)470curMsg += sprintf(curMsg, " promoted from %d", n);471else if (n == 0)472curMsg += sprintf(curMsg, " comp in progress");473else474curMsg += sprintf(curMsg, " already in the right place %d", n);475}476}477}478else479{480if (logSampling)481curMsg += sprintf(curMsg, " cannot be compiled, extra field is %" OMR_PRIdPTR, TR::CompilationInfo::getJ9MethodExtra(j9method));482}483}484TR::Recompilation::globalSampleCount++;485}486else if (logSampling)487{488if (count >= 0)489curMsg += sprintf(curMsg, " %d invocations before compiling", count);490else491curMsg += sprintf(curMsg, " cannot be compiled");492}493}494else // sampling interpreted body, but method was compiled495{496// Unlikely scenario, unless the method has long running activations.497// Create an activation length record for this method498//499//if(TR::Options::getCmdLineOptions()->getFixedOptLevel() == -1)500// compInfo->getPersistentInfo()->getActivationTable()->insert(j9method, totalSampleCount, fe);501502TR_PersistentJittedBodyInfo *bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(j9method->extra);503if (bodyInfo)504bodyInfo->_longRunningInterpreted = true;505506if (logSampling)507curMsg += sprintf(curMsg, " counter = XX (long running?)");508// Note that we do not increment globalSampleCount here509}510if (fe->isLogSamplingSet())511{512TR_VerboseLog::writeLineLocked(TR_Vlog_SAMPLING,"%s", msg);513}514Trc_JIT_Sampling_Detail(getJ9VMThreadFromTR_VM(fe), msg);515return plan;516}517518519TR_OptimizationPlan *520TR::DefaultCompilationStrategy::processJittedSample(TR_MethodEvent *event)521{522TR_OptimizationPlan *plan = 0;523TR::Options * cmdLineOptions = TR::Options::getCmdLineOptions();524J9Method *j9method = event->_j9method;525J9JITConfig *jitConfig = event->_vmThread->javaVM->jitConfig;526TR::CompilationInfo *compInfo = 0;527if (jitConfig)528compInfo = TR::CompilationInfo::get(jitConfig);529530TR_J9VMBase * fe = TR_J9VMBase::get(jitConfig, event->_vmThread);531int32_t totalSampleCount = ++ TR::Recompilation::globalSampleCount;532uint64_t crtTime = compInfo->getPersistentInfo()->getElapsedTime();533534#define MSG_SZ 450535char msg[MSG_SZ]; // size should be big enough to hold the whole one-line msg536msg[0] = 0;537char *curMsg = msg;538void *startPC = event->_oldStartPC;539bool logSampling = fe->isLogSamplingSet() || TrcEnabled_Trc_JIT_Sampling_Detail;540if (logSampling || TrcEnabled_Trc_JIT_Sampling)541{542#define SIG_SZ 150543char sig[SIG_SZ]; // hopefully the size is good for most cases544fe->printTruncatedSignature(sig, SIG_SZ, (TR_OpaqueMethodBlock*)j9method);545int32_t pcOffset = (uint8_t *)(event->_samplePC) - (uint8_t *)startPC;546if (logSampling)547curMsg += sprintf(curMsg, "(%d)\tCompiled %s\tPC=" POINTER_PRINTF_FORMAT "\t%+d\t", totalSampleCount, sig, startPC, pcOffset);548if (TrcEnabled_Trc_JIT_Sampling && ((totalSampleCount % 4) == 0))549Trc_JIT_Sampling(getJ9VMThreadFromTR_VM(fe), "Compiled", sig, 0); // TODO put good pcOffset550}551552TR::Recompilation::jitGlobalSampleCount++;553554// Insert an yield point if compilation queue size is too big and CPU utilization is close to 100%555// QueueSize changes all the time, so threads may experience cache misses556// trying to access it. It's better to have a variable defined in compInfo557// which says by how much we need to delay application threads. This variable558// will be changed by the sampling thread, every 0.5 seconds559if (TR::Options::getCmdLineOptions()->getOption(TR_EnableAppThreadYield))560{561int32_t sleepNano = compInfo->getAppSleepNano(); // determine how much I need to sleep562if (sleepNano != 0) // If I need to sleep at all563{564if (sleepNano == 1000000)565{566j9thread_sleep(1); // param in ms567}568else569{570if (fe->shouldSleep()) // sleep every other sample point571j9thread_sleep(1); // param in ms572}573}574}575J9::PrivateLinkage::LinkageInfo *linkageInfo = J9::PrivateLinkage::LinkageInfo::get(startPC);576TR_PersistentJittedBodyInfo *bodyInfo = NULL;577578compInfo->_stats._compiledMethodSamples++;579580if (linkageInfo->hasFailedRecompilation())581{582compInfo->_stats._compiledMethodSamplesIgnored++;583if (logSampling)584curMsg += sprintf(curMsg, " has already failed a recompilation attempt");585}586else if (!linkageInfo->isSamplingMethodBody())587{588compInfo->_stats._compiledMethodSamplesIgnored++;589if (logSampling)590curMsg += sprintf(curMsg, " does not use sampling");591}592else if (debug("disableSamplingRecompilation"))593{594compInfo->_stats._compiledMethodSamplesIgnored++;595if (logSampling)596curMsg += sprintf(curMsg, " sampling disabled");597}598else599bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(startPC);600601if (bodyInfo && bodyInfo->getDisableSampling())602{603compInfo->_stats._compiledMethodSamplesIgnored++;604if (logSampling)605curMsg += sprintf(curMsg, " uses sampling but sampling disabled (last comp. with prex)");606bodyInfo = NULL;607}608609if (bodyInfo)610{611bool getOut = false;612TR_PersistentMethodInfo *methodInfo = bodyInfo->getMethodInfo();613fe->acquireCompilationLock();614bool isAlreadyBeingCompiled;615TR_OpaqueMethodBlock *j9m = methodInfo->getMethodInfo();616void *currentStartPC = TR::CompilationInfo::getPCIfCompiled((J9Method*)j9m);617618// See if the method has already been compiled but we get a sample in the old body619if (currentStartPC != startPC) // rare case620getOut = true;621else if (TR::Options::getCmdLineOptions()->getFixedOptLevel() != -1622|| TR::Options::getAOTCmdLineOptions()->getFixedOptLevel() != -1) // prevent recompilation when opt level is specified623{624getOut = true;625}626else627{628isAlreadyBeingCompiled = TR::Recompilation::isAlreadyBeingCompiled(methodInfo->getMethodInfo(), startPC, fe);629// If we already decided to recompile this body, and we haven't yet630// queued the method don't bother continuing. Very small window of time.631//632if (bodyInfo->getSamplingRecomp() && // flag needs to be tested after getting compilationMonitor633!isAlreadyBeingCompiled)634{635if (logSampling)636curMsg += sprintf(curMsg, " uses sampling but a recomp decision has already been taken");637getOut = true;638}639}640if (getOut)641{642fe->releaseCompilationLock();643// and do nothing644}645else646{647bool recompile = false;648TR_Hotness nextOptLevel;649bool useProfiling = false;650651// Profiling compilations that precede scorching ones are quite taxing652// on large multicore machines. Thus, we want to observe the hotness of a653// method for longer, rather than rushing into a profiling very-hot compilation.654// We can afford to do so because scorching methods accumulate samples at a655// higher rate than hot ones.656// The goal here is to implement a rather short decision window (sampling interval)657// for decisions to upgrade to hot, but a larger decision window for decisions658// to go to scorching. This is based on density of samples observed in the JVM:659// the larger the density of samples, the larger the scorching decision window.660// scorchingSampleInterval will be a multiple of hotSampleInterval661// When a hotSampleInterval ends, if the method looks scorching we postpone any662// recompilation decision until a scorchingSampleInterval finishes. If the method663// only looks hot, then we decide to recompile at hot at the end of the hotSampleInterval664665uint32_t intervalIncreaseFactor = compInfo->getJitSampleInfoRef().getIncreaseFactor();666// possibly larger sample interval for scorching compilations667int32_t scorchingSampleInterval = TR::Options::_sampleInterval * intervalIncreaseFactor;668669// Hot recompilation decisions use the regular sized sampling interval670uint8_t hotSampleInterval = TR::Options::_sampleInterval;671int32_t hotSampleThreshold = TR::Options::_sampleThreshold;672673int32_t count = bodyInfo->decCounter();674uint8_t crtSampleIntervalCount = bodyInfo->incSampleIntervalCount(scorchingSampleInterval);675bool hotSamplingWindowComplete = (crtSampleIntervalCount % hotSampleInterval) == 0;676bool scorchingSamplingWindowComplete = (crtSampleIntervalCount == 0);677678int32_t startSampleCount = bodyInfo->getStartCount();679int32_t globalSamples = totalSampleCount - startSampleCount;680int32_t globalSamplesInHotWindow = globalSamples - bodyInfo->getHotStartCountDelta();681682int32_t scaledScorchingThreshold = 0, scaledHotThreshold = 0;683684if (logSampling)685curMsg += sprintf(curMsg, " cnt=%d ncl=%d glblSmplCnt=%d startCnt=%d[-%u,+%u] samples=[%d %d] windows=[%d %u] crtSmplIntrvlCnt=%u",686count, methodInfo->getNextCompileLevel(), totalSampleCount, startSampleCount,687bodyInfo->getOldStartCountDelta(), bodyInfo->getHotStartCountDelta(),688globalSamples, globalSamplesInHotWindow,689scorchingSampleInterval, hotSampleInterval, crtSampleIntervalCount);690691bool dontSwitchToProfiling = false;692if (count <= 0)693{694if (!isAlreadyBeingCompiled)695{696// do not allow scorching compiles based on count reaching 0697if (methodInfo->getNextCompileLevel() > hot)698{699// replenish the counter with a multiple of sampleInterval700bodyInfo->setCounter(hotSampleInterval);701// even if the count reached 0, we still need to check if we can702// promote this method through sample thresholds703}704else // allow transition to HOT through exhaustion of count705{706recompile = true;707TR::Recompilation::limitMethodsCompiled++;708// Currently the counter can be decremented because (1) the method was709// sampled; (2) EDO; (3) PIC miss; (4) megamorphic interface call profile.710// EDO will have its own recompilation snippet, but in cases (3) and (4)711// the counter just reaches 0, and only the next sample will trigger712// recompilation. These cases can be identified by the negative counter713// (we decrement the counter above in sampleMethod()). In contrast, if the714// counter is decremented through sampling, only the first thread that sees715// the counter 0 will recompile the method, and all the others will be716// prevented from reaching this point due to isAlreadyBeingCompiled717718if (count < 0 && !methodInfo->disableMiscSamplingCounterDecrementation())719{720// recompile at same level721nextOptLevel = bodyInfo->getHotness();722723// mark this special situation724methodInfo->setDisableMiscSamplingCounterDecrementation();725// write a message in the vlog to know the reason of recompilation726if (logSampling)727curMsg += sprintf(curMsg, " PICrecomp");728methodInfo->setReasonForRecompilation(TR_PersistentMethodInfo::RecompDueToMegamorphicCallProfile);729}730else731{732nextOptLevel = methodInfo->getNextCompileLevel();733methodInfo->setReasonForRecompilation(bodyInfo->getIsPushedForRecompilation() ?734TR_PersistentMethodInfo::RecompDueToRecompilationPushing : TR_PersistentMethodInfo::RecompDueToCounterZero);735// It's possible that a thread decrements the counter to 0 and another736// thread decrements it further to -1 which will trigger a compilation737// at same level. The following line will prevent that.738methodInfo->setDisableMiscSamplingCounterDecrementation();739}740}741}742743if (recompile) // recompilation due to count reaching 0744{745bodyInfo->setOldStartCountDelta(totalSampleCount - startSampleCount);// Should we handle overflow?746bodyInfo->setHotStartCountDelta(0);747bodyInfo->setStartCount(totalSampleCount);748}749}750751bool postponeDecision = false;752if (!recompile && hotSamplingWindowComplete && totalSampleCount > startSampleCount)753{754compInfo->_stats._methodsReachingSampleInterval++;755756// Goal: based on codeSize, scale the original Threshold by no more than +/-x%757// 'x' will be called sampleThresholdVariationAllowance758// When codeSize==avgCodeSize, we want the scaling factor to be 1.0759// The scaling of the threshold can be turned off by having760// the sampleThresholdVariationAllowance equal to 0761J9JITExceptionTable *metaData = jitConfig->jitGetExceptionTableFromPC(event->_vmThread, (UDATA)startPC);762int32_t codeSize = 0; // TODO eliminate the overhead; we already have metadata763if (metaData)764codeSize = compInfo->calculateCodeSize(metaData);765766// Scale the recompilation thresholds based on method size767int32_t avgCodeSize = (TR::Compiler->target.cpu.isI386() || TR::Compiler->target.cpu.isPower()) ? 1500 : 3000; // experimentally determined768769TR_ASSERT(codeSize != 0, "startPC!=0 ==> codeSize!=0");770771float scalingFactor = 0.01*((100 - TR::Options::_sampleThresholdVariationAllowance) +772(avgCodeSize << 1)*TR::Options::_sampleThresholdVariationAllowance /773(float)(avgCodeSize + codeSize));774curMsg += sprintf(curMsg, " SizeScaling=%.1f", scalingFactor);775scaledHotThreshold = (int32_t)(hotSampleThreshold*scalingFactor);776777// Do not use aggressive recompilations for big applications like websphere.778// WebSphere loads more than 14000 classes, typical small apps more like 1000-2000 classes.779// ==> use a reasonable value like 5000 to determine if the application is big780bool useAggressiveRecompilations = !cmdLineOptions->getOption(TR_DisableAggressiveRecompilations) &&781(bodyInfo->decAggressiveRecompilationChances() > 0 ||782compInfo->getPersistentInfo()->getNumLoadedClasses() < TR::Options::_bigAppThreshold);783784bool conservativeCase = TR::Options::getCmdLineOptions()->getOption(TR_ConservativeCompilation) &&785compInfo->getPersistentInfo()->getNumLoadedClasses() >= TR::Options::_bigAppThreshold;786787if (conservativeCase)788{789scaledHotThreshold >>= 1; // halve the threshold for a more conservative comp decision790useAggressiveRecompilations = true; // force it, to allow recomp at original threshold,791// but double the sample interval (60 samples)792}793// For low number of processors become more conservative during startup794if (jitConfig->javaVM->phase != J9VM_PHASE_NOT_STARTUP &&795TR::Compiler->target.numberOfProcessors() <= 2)796scaledHotThreshold >>= 2;797798// Used to make recompilations less aggressive during WebSphere startup,799// avoiding costly hot, and very hot compilation800bool isBigAppStartup = (jitConfig->javaVM->phase != J9VM_PHASE_NOT_STARTUP801&& TR::Options::sharedClassCache()802&& compInfo->getPersistentInfo()->getNumLoadedClasses() >= TR::Options::_bigAppThreshold803&& TR::Options::_bigAppSampleThresholdAdjust > 0);804if (isBigAppStartup)805{806scaledHotThreshold >>= TR::Options::_bigAppSampleThresholdAdjust; //adjust to avoid hot recomps807useAggressiveRecompilations = false; //also to avoid potential hot recomps, this could have been set808}809810// We allow hot compilations at a lower CPU, but for a longer period of time (scorching window)811bool secondCriteriaHot = false;812// Check for non first hot interval813if (useAggressiveRecompilations)814{815int32_t samplesInSelf = scorchingSamplingWindowComplete ? scorchingSampleInterval : crtSampleIntervalCount;816// Alternative: Here we may want to do something only if a scorchingSampleWindow is complete817if (samplesInSelf > hotSampleInterval)818{819// 0.5*targetCPU < crtCPU820if (((globalSamples*hotSampleInterval) >> 1) < (scaledHotThreshold * samplesInSelf))821secondCriteriaHot = true;822}823}824825// TODO: if the scorching window is complete, should we look at CPU over the larger window?826if (globalSamplesInHotWindow <= scaledHotThreshold || secondCriteriaHot)827{828// The method is hot, but is it actually scorching?829//830// If the scorching interval is done, perform normal scorching test831// If the scorching interval is not done, performs a sniff test for a shorter interval832// 1. If the method looks scorching during this small interval, do not833// do anything; just wait for the scorching interval to finish834// 2. If the method does not look scorching, perform a hot compilation835//836// First let's do some scaling based on size, startup, bigApp, numProc, etc837scaledScorchingThreshold = (int32_t)(TR::Options::_scorchingSampleThreshold * scalingFactor);838if (conservativeCase)839{840scaledScorchingThreshold >>= 1; // halve the threshold for a more conservative comp decision841if (TR::Compiler->target.numberOfProcessors() != 1)842useAggressiveRecompilations = true; // to allow recomp at original threshold,843else // but double the sample interval (60 samples)844useAggressiveRecompilations = false;845}846847if (isBigAppStartup)848{849scaledScorchingThreshold >>= TR::Options::_bigAppSampleThresholdAdjust; //adjust to avoid scorching recomps850useAggressiveRecompilations = false; //this could have been set, so disable to avoid851}852853if (!scorchingSamplingWindowComplete)854{855// Perform scorching recompilation sniff test using a shorter sample interval856// TODO: relax the thresholds a bit, maybe we can go directly to scorching next time857if (globalSamplesInHotWindow <= scaledScorchingThreshold)858postponeDecision = true;859}860else // scorching sample interval is done861{862// Adjust the scorchingSampleThreshold because the sample window is larger863scaledScorchingThreshold = scaledScorchingThreshold * intervalIncreaseFactor;864865// Make the scorching compilation less likely as time goes by866// The bigger the number of scorching intervals, the smaller scaledScorchingThreshold867if (bodyInfo->getNumScorchingIntervals() > 3)868scaledScorchingThreshold >>= 1;869870// secondCriteria looks at hotness over a period of time that is double871// than normal (60 samples). This is why we have to increase scaledScorchingThreshold872// by a factor of 2. If we want to become twice as aggressive we need to double873// scaledScorchingThreshold yet again874//875bool secondCriteriaScorching = useAggressiveRecompilations &&876(totalSampleCount - bodyInfo->getOldStartCount() <= (scaledScorchingThreshold << 2));877// Scorching test878if ((globalSamples <= scaledScorchingThreshold) || secondCriteriaScorching)879{880// Determine whether or not the method is to be profiled before881// being compiled as scorching hot.882// For profiling the platform must support counting recompilation.883//884if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableProfiling) &&885TR::Recompilation::countingSupported() && !TR::CodeCacheManager::instance()->almostOutOfCodeCache() &&886!(methodInfo->profilingDisabled()))887{888nextOptLevel = veryHot;889useProfiling = true;890}891else892{893nextOptLevel = scorching;894}895recompile = true;896compInfo->_stats._methodsSelectedToRecompile++;897TR::Recompilation::scorchingThresholdMethodsCompiled++;898}899}900// Should we proceed with the hot compilation?901if (!recompile && !postponeDecision && bodyInfo->getHotness() <= warm)902{903nextOptLevel = hot;904// Decide whether to deny optimizer to switch to profiling on the fly905if (globalSamplesInHotWindow > TR::Options::_sampleDontSwitchToProfilingThreshold &&906!TR::Options::getCmdLineOptions()->getOption(TR_AggressiveSwitchingToProfiling))907dontSwitchToProfiling = true;908recompile = true;909compInfo->_stats._methodsSelectedToRecompile++;910TR::Recompilation::hotThresholdMethodsCompiled++;911}912}913// If the method is truly cold, replenish the counter to avoid914// recompilation through counter decrementation915else if (globalSamplesInHotWindow >= TR::Options::_resetCountThreshold)916{917compInfo->_stats._methodsSampleWindowReset++;918bodyInfo->setCounter(count + hotSampleInterval);919if (logSampling)920curMsg += sprintf(curMsg, " is cold, reset cnt to %d", bodyInfo->getCounter());921}922// The hot sample interval is done. Prepare for next interval.923if (scorchingSamplingWindowComplete)924{925// scorching sample interval is done926bodyInfo->setStartCount(totalSampleCount);927bodyInfo->setOldStartCountDelta(totalSampleCount - startSampleCount);928bodyInfo->setHotStartCountDelta(0);929}930else931{932int32_t hotStartCountDelta = totalSampleCount - startSampleCount;933TR_ASSERT(hotStartCountDelta >= 0, "hotStartCountDelta should not be negative\n");934if (hotStartCountDelta > 0xffff)935hotStartCountDelta = 0xffff;936bodyInfo->setHotStartCountDelta(hotStartCountDelta);937}938939if (recompile)940{941// One more test942if (!isAlreadyBeingCompiled)943{944methodInfo->setReasonForRecompilation(TR_PersistentMethodInfo::RecompDueToThreshold);945}946else // the method is already being compiled; maybe we need to update the opt level947{948recompile = false; // do not need to recompile the method949if ((int32_t)nextOptLevel > (int32_t)methodInfo->getNextCompileLevel())950{951// search the queue to update the optimization plan.952//953TR::IlGeneratorMethodDetails details(j9method);954TR_MethodToBeCompiled *entry =955compInfo->adjustCompilationEntryAndRequeue(details, methodInfo, nextOptLevel,956useProfiling,957CP_ASYNC_NORMAL, fe);958if (entry)959{960if (logSampling)961curMsg += sprintf(curMsg, " adj opt lvl to %d", (int32_t)(entry->_optimizationPlan->getOptLevel()));962int32_t measuredCpuUtil = crtSampleIntervalCount == 0 ? // scorching interval done?963scorchingSampleInterval * 1000 / globalSamples :964hotSampleInterval * 1000 / globalSamplesInHotWindow;965entry->_optimizationPlan->setPerceivedCPUUtil(measuredCpuUtil);966}967}968}969}970}971972// try to upgrade some of the less optimized compilations973bool willUpgrade = false;974if (!recompile)975{976if (bodyInfo->getFastRecompilation() && !isAlreadyBeingCompiled)977{978// Allow profiling even if we are about to exhaust the code cache979// because this case is used for diagnostic only980if (bodyInfo->getFastScorchingRecompilation())981{982if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableProfiling) &&983TR::Recompilation::countingSupported() &&984!(methodInfo->profilingDisabled()))985{986nextOptLevel = veryHot;987useProfiling = true;988}989else990{991nextOptLevel = scorching;992}993}994else995{996nextOptLevel = hot;997}998recompile = true;999methodInfo->setReasonForRecompilation(TR_PersistentMethodInfo::RecompDueToThreshold);//lie1000}1001else if (!postponeDecision &&1002!TR::Options::getCmdLineOptions()->getOption(TR_DisableUpgrades) &&1003// case (1) methods downgraded to cold1004((bodyInfo->getHotness() < warm &&1005(methodInfo->isOptLevelDowngraded() || cmdLineOptions->getOption(TR_EnableUpgradingAllColdCompilations))) ||1006// case (2) methods taken from shared cache1007bodyInfo->getIsAotedBody()))1008// case (3) cold compilations for bootstrap methods, even if not downgraded1009{1010// test other conditions for upgrading10111012uint32_t threshold = TR::Options::_coldUpgradeSampleThreshold;1013// Pick a threshold based on method size (higher thresholds for bigger methods)1014if (jitConfig->javaVM->phase != J9VM_PHASE_NOT_STARTUP &&1015compInfo->getPersistentInfo()->getNumLoadedClasses() >= TR::Options::_bigAppThreshold)1016{1017threshold += (uint32_t)(TR::CompilationInfo::getMethodBytecodeSize(j9method) >> 8);1018// sampleIntervalCount goes from 0 to _sampleInterval-11019// Very big methods (bigger than 6K bytecodes) will have a threshold bigger than this1020// and never be upgraded, which is what we want1021}1022if ((uint32_t)crtSampleIntervalCount >= threshold &&1023compInfo->getMethodQueueSize() <= TR::CompilationInfo::SMALL_QUEUE &&1024!compInfo->getPersistentInfo()->isClassLoadingPhase() &&1025!isAlreadyBeingCompiled &&1026!cmdLineOptions->getOption(TR_DisableUpgradingColdCompilations))1027{1028recompile = true;1029if (!bodyInfo->getIsAotedBody())1030{1031// cold-nonaot compilations can only be upgraded to warm1032nextOptLevel = warm;1033}1034else // AOT bodies1035{1036if (!TR::Options::isQuickstartDetected())1037{1038// AOT upgrades are performed at warm1039// We may want to look at how expensive the method is though1040nextOptLevel = warm;1041}1042else // -Xquickstart (and AOT)1043{1044nextOptLevel = cold;1045// Exception: bootstrap class methods that are cheap should be upgraded directly at warm1046if (cmdLineOptions->getOption(TR_UpgradeBootstrapAtWarm) && fe->isClassLibraryMethod((TR_OpaqueMethodBlock *)j9method))1047{1048TR_J9SharedCache *sc = TR_J9VMBase::get(jitConfig, event->_vmThread, TR_J9VMBase::AOT_VM)->sharedCache();1049bool expensiveComp = sc->isHint(j9method, TR_HintLargeMemoryMethodW);1050if (!expensiveComp)1051nextOptLevel = warm;1052}1053}1054}1055methodInfo->setReasonForRecompilation(TR_PersistentMethodInfo::RecompDueToOptLevelUpgrade);1056// reset the flag to avoid upgrading repeatedly1057methodInfo->setOptLevelDowngraded(false);1058willUpgrade = true;1059}1060}1061}10621063// if we don't take any recompilation decision, let's see if we can1064// schedule a compilation from the low priority queue1065if (!recompile && compInfo && compInfo->getLowPriorityCompQueue().hasLowPriorityRequest() &&1066compInfo->canProcessLowPriorityRequest())1067{1068// wake up the compilation thread1069compInfo->getCompilationMonitor()->notifyAll();1070}1071if (recompile)1072{1073// Method is being recompiled because it is truly hot;1074bodyInfo->setSamplingRecomp();1075}1076fe->releaseCompilationLock();1077if (recompile)1078{1079//induceRecompilation(fe, startPC);1080bool useSampling = (nextOptLevel != scorching && !useProfiling);1081plan = TR_OptimizationPlan::alloc(nextOptLevel, useProfiling, useSampling);1082if (plan)1083{1084int32_t measuredCpuUtil = crtSampleIntervalCount == 0 ? // scorching interval done?1085(globalSamples != 0 ? scorchingSampleInterval * 1000 / globalSamples : 0) :1086(globalSamplesInHotWindow != 0 ? hotSampleInterval * 1000 / globalSamplesInHotWindow : 0);1087plan->setPerceivedCPUUtil(measuredCpuUtil);1088plan->setIsUpgradeRecompilation(willUpgrade);1089plan->setDoNotSwitchToProfiling(dontSwitchToProfiling);1090if (crtSampleIntervalCount == 0 && // scorching compilation decision can be taken1091globalSamples <= TR::Options::_relaxedCompilationLimitsSampleThreshold) // FIXME: needs scaling1092plan->setRelaxedCompilationLimits(true);1093if (logSampling)1094{1095float cpu = measuredCpuUtil / 10.0;1096if (useProfiling)1097curMsg += sprintf(curMsg, " --> recompile at level %d, profiled CPU=%.1f%%", nextOptLevel, cpu);1098else1099curMsg += sprintf(curMsg, " --> recompile at level %d CPU=%.1f%%", nextOptLevel, cpu);11001101if (methodInfo->getReasonForRecompilation() == TR_PersistentMethodInfo::RecompDueToThreshold)1102{1103curMsg += sprintf(curMsg, " scaledThresholds=[%d %d]", scaledScorchingThreshold, scaledHotThreshold);1104}1105}1106}1107else // OOM1108{1109if (logSampling)1110curMsg += sprintf(curMsg, " --> not recompiled: OOM");1111}1112}1113else if (logSampling)1114{1115if (isAlreadyBeingCompiled)1116curMsg += sprintf(curMsg, " - is already being recompiled");1117else if (!hotSamplingWindowComplete)1118curMsg += sprintf(curMsg, " not recompiled, smpl interval not done");1119else1120{1121float measuredCpuUtil = 0.0;1122if (crtSampleIntervalCount == 0) // scorching interval done1123{1124if (globalSamples)1125measuredCpuUtil = scorchingSampleInterval * 100.0 / globalSamples;1126}1127else1128{1129if (globalSamplesInHotWindow)1130measuredCpuUtil = hotSampleInterval * 100.0 / globalSamplesInHotWindow;1131}1132curMsg += sprintf(curMsg, " not recompiled, CPU=%.1f%% %s scaledThresholds=[%d %d]",1133measuredCpuUtil, postponeDecision ? " postpone decision" : "",1134scaledScorchingThreshold, scaledHotThreshold);1135}1136}1137}1138} // endif (bodyInfo)11391140if (logSampling)1141{1142bool bufferOverflow = ((curMsg - msg) >= MSG_SZ); // check for overflow at runtime1143if (fe->isLogSamplingSet())1144{1145TR_VerboseLog::CriticalSection vlogLock;1146TR_VerboseLog::writeLine(TR_Vlog_SAMPLING,"%s", msg);1147if (bufferOverflow)1148TR_VerboseLog::writeLine(TR_Vlog_SAMPLING,"Sampling line is too big: %d characters", curMsg-msg);1149}1150Trc_JIT_Sampling_Detail(getJ9VMThreadFromTR_VM(fe), msg);1151if (bufferOverflow)1152Trc_JIT_Sampling_Detail(getJ9VMThreadFromTR_VM(fe), "Sampling line will cause buffer overflow");1153// check for buffer overflow and write a message1154}1155return plan;1156}11571158TR_OptimizationPlan *1159TR::DefaultCompilationStrategy::processHWPSample(TR_MethodEvent *event)1160{1161TR_OptimizationPlan *plan = NULL;1162TR_Hotness hotnessLevel;1163TR_PersistentJittedBodyInfo *bodyInfo;1164TR_PersistentMethodInfo *methodInfo;11651166bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);11671168TR_ASSERT(bodyInfo, "bodyInfo should not be NULL!\n");1169if (!bodyInfo)1170return NULL;11711172methodInfo = bodyInfo->getMethodInfo();1173hotnessLevel = bodyInfo->getHotness();1174if (bodyInfo->getIsProfilingBody() && !bodyInfo->getUsesJProfiling())1175{1176// We rely on a count-based recompilation for profiled methods.1177return NULL;1178}11791180TR_Hotness nextOptLevel = event->_nextOptLevel;1181if (nextOptLevel > hotnessLevel ||1182(bodyInfo->getIsAotedBody() && !TR::Options::getCmdLineOptions()->getOption(TR_DontRIUpgradeAOTWarmMethods)))1183{1184J9JITConfig *jitConfig = event->_vmThread->javaVM->jitConfig;1185TR_J9VMBase * fe = TR_J9VMBase::get(jitConfig, event->_vmThread);1186fe->acquireCompilationLock();1187bool isAlreadyBeingCompiled = TR::Recompilation::isAlreadyBeingCompiled((TR_OpaqueMethodBlock *) event->_j9method, event->_oldStartPC, fe);1188fe->releaseCompilationLock();1189if (!isAlreadyBeingCompiled)1190{1191if (nextOptLevel == scorching &&1192!TR::Options::getCmdLineOptions()->getOption(TR_DisableProfiling) &&1193TR::Recompilation::countingSupported() &&1194!bodyInfo->_methodInfo->profilingDisabled())1195{1196plan = TR_OptimizationPlan::alloc(veryHot, true, false);1197}1198else1199{1200plan = TR_OptimizationPlan::alloc(nextOptLevel, false, true);1201}12021203if (plan)1204methodInfo->setReasonForRecompilation(TR_PersistentMethodInfo::RecompDueToRI);1205}1206}1207return plan;1208}12091210//-------------------------- adjustOptimizationPlan ---------------------------1211// Input: structure with information about the method to be compiled1212// Output: returns true if the optimization plan has been changed. In that case1213// the optimization level will be changed and also 2 flags in the1214// optimization plan may be changed (OptLevelDowngraded, AddToUpgradeQueue)1215//----------------------------------------------------------------------------1216bool TR::DefaultCompilationStrategy::adjustOptimizationPlan(TR_MethodToBeCompiled *entry, int32_t optLevelAdjustment)1217{1218// Run SmoothCompilation to see if we need to change the opt level and/or priority1219bool shouldAddToUpgradeQueue = false;1220TR::CompilationInfo *compInfo = TR::CompilationController::getCompilationInfo();1221if (optLevelAdjustment == 0) // unchanged opt level (default)1222{1223shouldAddToUpgradeQueue = compInfo->SmoothCompilation(entry, &optLevelAdjustment);1224}12251226// Recompilations are treated differently1227if (entry->_oldStartPC != 0)1228{1229// Downgrade the optimization level of invalidation requests1230// if too many invalidations are present into the compilation queue1231// Here we access _numInvRequestsInCompQueue outside the protection of compilation queue monitor1232// This is fine because it's just a heuristic1233if (entry->_entryIsCountedAsInvRequest &&1234compInfo->getNumInvRequestsInCompQueue() >= TR::Options::_numQueuedInvReqToDowngradeOptLevel &&1235entry->_optimizationPlan->getOptLevel() > cold &&1236!TR::Options::getCmdLineOptions()->getOption(TR_DontDowngradeToCold))1237{1238entry->_optimizationPlan->setOptLevel(cold);1239// Keep the optLevel in sync between the optPlan and methodInfo1240TR_PersistentMethodInfo* methodInfo = TR::Recompilation::getMethodInfoFromPC(entry->_oldStartPC);1241TR_ASSERT(methodInfo, "methodInfo must exist because we recompile");1242methodInfo->setNextCompileLevel(entry->_optimizationPlan->getOptLevel(), entry->_optimizationPlan->insertInstrumentation());1243// DO NOT mark this as optLevelDowngraded1244// entry->_optimizationPlan->setOptLevelDowngraded(true);1245return true;1246}1247return false;1248}12491250if (optLevelAdjustment == 0)1251return false;12521253// Must check if we really downgrade this method (for fixed opt level we do not do it)1254TR_Hotness hotnessLevel = entry->_optimizationPlan->getOptLevel();1255bool optLevelDowngraded = false;12561257if (true)1258{1259if (TR::Options::getCmdLineOptions()->allowRecompilation()) // don't do it for fixed level1260{1261if (optLevelAdjustment > 0) // would like to increase the opt level1262{1263if (hotnessLevel == warm || hotnessLevel == cold || hotnessLevel == noOpt)1264hotnessLevel = (TR_Hotness)((int)hotnessLevel + 1);1265}1266else // would like to decrease the opt level1267{1268if (optLevelAdjustment < -1)1269{1270hotnessLevel = noOpt;1271optLevelDowngraded = true;1272}1273else if (hotnessLevel == warm || hotnessLevel == hot)1274{1275hotnessLevel = (TR_Hotness)((int)hotnessLevel - 1);1276optLevelDowngraded = true;1277}1278}1279}1280}12811282// If change in hotness level1283if (entry->_optimizationPlan->getOptLevel() != hotnessLevel)1284{1285entry->_optimizationPlan->setOptLevel(hotnessLevel);1286entry->_optimizationPlan->setOptLevelDowngraded(optLevelDowngraded);1287// Set the flag to add to the upgrade queue1288if (optLevelDowngraded && shouldAddToUpgradeQueue)1289entry->_optimizationPlan->setAddToUpgradeQueue();1290return true;1291}1292else1293{1294return false;1295}1296}129712981299void TR::DefaultCompilationStrategy::beforeCodeGen(TR_OptimizationPlan *plan, TR::Recompilation *recomp)1300{1301// Set up the opt level and counter for the next compilation. This will1302// also decide if there is going to be a next compilation. If there is no1303// next compilation, remove any counters that have been inserted into the code1304// Ideally, we should have a single step after the compilation1305if (! recomp->_doNotCompileAgain)1306{1307int32_t level;1308int32_t countValue;13091310// do not test plan->insertInstrumentation() because we might have switched to profiling1311TR_Hotness current = recomp->_compilation->getMethodHotness();1312if (recomp->isProfilingCompilation() && current < scorching)1313{1314// Set the level for the next compilation. This will be higher than1315// the level at which we are compiling the current method for profiling.1316//1317level = current+1;1318countValue = PROFILING_INVOCATION_COUNT - 1; // defined in Profiler.hpp1319}1320else1321{1322// figure out the next opt level and the next count1323TR::Compilation *comp = recomp->_compilation;1324bool mayHaveLoops = comp->mayHaveLoops();1325TR::Options *options = comp->getOptions();1326if (recomp->_bodyInfo->getUsesGCR())1327{1328level = warm; // GCR recompilations should be performed at warm1329// If a GCR count was specified, used that1330if (options->getGCRCount() > 0)1331{1332countValue = options->getGCRCount();1333}1334else // find the count corresponding to the warm level (or next available)1335{1336countValue = options->getCountValue(mayHaveLoops, (TR_Hotness) level);1337if (countValue < 0)1338{1339// Last resort: use some sensible values1340countValue = mayHaveLoops ? options->getInitialBCount() : options->getInitialCount();1341}1342}1343}1344else1345{1346level = options->getNextHotnessLevel(mayHaveLoops, plan->getOptLevel());1347countValue = options->getCountValue(mayHaveLoops, (TR_Hotness) level);1348}1349}13501351if ((countValue > 0) || (recomp->isProfilingCompilation() && current < scorching) || plan->isOptLevelDowngraded() || recomp->_bodyInfo->getUsesGCR())1352{1353recomp->_nextLevel = (TR_Hotness)level; // There may be another compilation1354}1355else1356{1357// There will not be another compilation - remove any counters that1358// have been inserted into the code.1359//1360recomp->preventRecompilation();1361//recomp->_useSampling = false; // wrong, because the codegen will generate a counting body1362recomp->_bodyInfo->setDisableSampling(true);1363// also turn off sampling for this body1364}1365recomp->_nextCounter = countValue;1366}1367}13681369void TR::DefaultCompilationStrategy::postCompilation(TR_OptimizationPlan *plan, TR::Recompilation *recomp)1370{1371if (!TR::CompilationController::getCompilationInfo()->asynchronousCompilation())1372{1373TR_OptimizationPlan::_optimizationPlanMonitor->enter();1374recomp->getMethodInfo()->_optimizationPlan = NULL;1375TR_OptimizationPlan::_optimizationPlanMonitor->exit();1376}1377}137813791380138113821383//============================= ThresholdCompilationStrategy ====================138413851386TR::ThresholdCompilationStrategy::ThresholdCompilationStrategy()1387{1388// To be safe, clear everything out before setting anything1389for (int32_t level=noOpt; level <= numHotnessLevels; level++)1390{1391_nextLevel[level] = unknownHotness;1392_samplesNeededToMoveTo[level] = -1;1393_performInstrumentation[level] = false;1394}13951396// Now, initialize our strategy threshold based strategy1397//1398// These could easily be set from command line options or any other1399// way (maybe from the existing options string?)1400//1401// The current strategy uses only noOpt -> warm -> scorching. (and veryHot if instrumentation-based profiling is used)1402_samplesNeededToMoveTo[noOpt] = 1;1403_samplesNeededToMoveTo[warm] = 6;1404int32_t SCORCHING_THRESH = 20;1405_samplesNeededToMoveTo[scorching] = SCORCHING_THRESH;14061407// If we are doing instrumentation-based profiling1408if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableProfiling))1409{1410// Insert instrumentation in VeryHot1411_samplesNeededToMoveTo[veryHot] = SCORCHING_THRESH;1412_performInstrumentation[veryHot] = 1; // Yes, perform profiling at this level14131414_samplesNeededToMoveTo[scorching] = SCORCHING_THRESH + 1; // Sampling is disable during instrumentation-based profiling,1415// so this is really just a place holder1416}14171418// Use the information above to setup the "next" pointers.1419// Go through list backwards, and for each "active" level, set where you'll jump to next.1420int32_t prevActiveLevel = unknownHotness;1421for (int32_t curLevel = numHotnessLevels;1422curLevel >= noOpt; // should be "> minHotness" if it existed1423curLevel--)1424{1425if (_samplesNeededToMoveTo[curLevel] > 0)1426{1427// curLevel is an active level1428_nextLevel[curLevel] = (TR_Hotness) prevActiveLevel;1429prevActiveLevel = curLevel;1430}1431}1432// Finally, check unknownHotness (which represents the method still being interpreted) last1433_nextLevel[unknownHotness] = (TR_Hotness) prevActiveLevel;14341435}1436143714381439TR_Hotness TR::ThresholdCompilationStrategy::getInitialOptLevel()1440{1441return noOpt;1442}144314441445TR_OptimizationPlan *TR::ThresholdCompilationStrategy::processEvent(TR_MethodEvent *event, bool *newPlanCreated)1446{1447TR_OptimizationPlan *plan = NULL;1448TR_Hotness hotnessLevel;1449TR_PersistentJittedBodyInfo *bodyInfo;1450TR_PersistentMethodInfo *methodInfo;1451*newPlanCreated = false;14521453if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL3)1454fprintf(stderr, "Received event %d\n", event->_eventType);14551456// first decode the event type1457switch (event->_eventType)1458{1459case TR_MethodEvent::InterpretedMethodSample:1460// do nothing1461break;1462case TR_MethodEvent::InterpreterCounterTripped:1463TR_ASSERT(event->_oldStartPC == 0, "oldStartPC should be 0 for an interpreted method");1464// use the counts to determine the first level of compilation1465// the level of compilation can be changed later on if option subsets are present1466hotnessLevel = TR::ThresholdCompilationStrategy::getInitialOptLevel();1467plan = TR_OptimizationPlan::alloc(hotnessLevel);1468*newPlanCreated = true;1469break;1470case TR_MethodEvent::OtherRecompilationTrigger: // sync recompilation through fixMethodCode1471// For sync re-compilation we attach the plan to the persistentBodyInfo1472bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);1473methodInfo = bodyInfo->getMethodInfo();14741475if (methodInfo->getReasonForRecompilation() == TR_PersistentMethodInfo::RecompDueToInlinedMethodRedefinition)1476{1477methodInfo->incrementNumberOfInlinedMethodRedefinition();1478hotnessLevel = bodyInfo->getHotness();1479plan = TR_OptimizationPlan::alloc(hotnessLevel);1480*newPlanCreated = true;1481}1482else if (methodInfo->getOptimizationPlan())1483{1484TR_ASSERT(!TR::CompilationController::getCompilationInfo()->asynchronousCompilation(), "This case should happen only for sync recompilation");1485plan = methodInfo->getOptimizationPlan();1486}1487else1488{1489//hotnessLevel = TR::Recompilation::getNextCompileLevel(event->_oldStartPC);1490hotnessLevel = getNextOptLevel(bodyInfo->getHotness());1491plan = TR_OptimizationPlan::alloc(hotnessLevel);1492*newPlanCreated = true;1493}1494break;1495case TR_MethodEvent::NewInstanceImpl:1496hotnessLevel = getInitialOptLevel();1497plan = TR_OptimizationPlan::alloc(hotnessLevel);1498*newPlanCreated = true;1499break;1500case TR_MethodEvent::MethodBodyInvalidated:1501// keep the same optimization level1502bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);1503TR_ASSERT(bodyInfo, "A recompilable method should have jittedBodyInfo");1504hotnessLevel = bodyInfo->getHotness();1505plan = TR_OptimizationPlan::alloc(hotnessLevel);1506*newPlanCreated = true;1507// the following is just for compatibility with older implementation1508bodyInfo->getMethodInfo()->setNextCompileLevel(hotnessLevel, false); // no profiling1509break;1510case TR_MethodEvent::JittedMethodSample:1511plan = processJittedSample(event);1512*newPlanCreated = true;1513break;15141515default:1516TR_ASSERT(0, "Bad event type %d", event->_eventType);1517}15181519if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL2)1520fprintf(stderr, "Event %d created plan %p\n", event->_eventType, plan);15211522return plan;1523}152415251526TR_OptimizationPlan *1527TR::ThresholdCompilationStrategy::processJittedSample(TR_MethodEvent *event)1528{1529TR_OptimizationPlan *plan = NULL;1530TR::Options * cmdLineOptions = TR::Options::getCmdLineOptions();1531J9Method *j9method = event->_j9method;1532J9JITConfig *jitConfig = event->_vmThread->javaVM->jitConfig;1533TR_J9VMBase * fe = TR_J9VMBase::get(jitConfig, event->_vmThread);1534void *startPC = event->_oldStartPC;1535// here we may need to write into the vlog153615371538J9::PrivateLinkage::LinkageInfo *linkageInfo = J9::PrivateLinkage::LinkageInfo::get(startPC);1539TR_PersistentJittedBodyInfo *bodyInfo = NULL;15401541if (linkageInfo->hasFailedRecompilation())1542{1543//if (logSampling)1544// msgLen += sprintf(msg + msgLen, " has already failed a recompilation attempt");1545}1546else if (!linkageInfo->isSamplingMethodBody())1547{1548//if (logSampling)1549// msgLen += sprintf(msg + msgLen, " does not use sampling");1550}1551else if (debug("disableSamplingRecompilation"))1552{1553//if (logSampling)1554//msgLen += sprintf(msg + msgLen, " sampling disabled");1555}1556else1557bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(startPC);15581559if (bodyInfo && bodyInfo->getDisableSampling())1560{1561//if (logSampling)1562//msgLen += sprintf(msg + msgLen, " uses sampling but sampling disabled (last comp. with prex)");1563bodyInfo = NULL;1564}15651566if (bodyInfo)1567{1568TR_PersistentMethodInfo *methodInfo = bodyInfo->getMethodInfo();1569fe->acquireCompilationLock();1570void *currentStartPC = (void *)TR::Compiler->mtd.startPC((TR_OpaqueMethodBlock *) methodInfo->getMethodInfo());1571if (currentStartPC != startPC) // rare case; sampling an old body1572{1573fe->releaseCompilationLock();1574// do nothing1575}1576else if (TR::Options::getCmdLineOptions()->getFixedOptLevel() != -11577|| TR::Options::getAOTCmdLineOptions()->getFixedOptLevel() != -1) // prevent recompilation when opt level is specified1578{1579fe->releaseCompilationLock();1580// do nothing1581}1582else1583{1584// increment the CPOcount and see if we need to recompile1585int32_t sampleCount = methodInfo->cpoIncCounter();1586fe->releaseCompilationLock();1587TR_Hotness curOptLevel = bodyInfo->getHotness();1588TR_Hotness nextOptLevel = getNextOptLevel(curOptLevel);15891590if ((nextOptLevel != unknownHotness) && (sampleCount == getSamplesNeeded(nextOptLevel)))1591{1592bool useSampling = (getNextOptLevel(nextOptLevel) != unknownHotness);1593plan = TR_OptimizationPlan::alloc(nextOptLevel,1594getPerformInstrumentation(nextOptLevel), useSampling);1595}1596}1597}1598return plan;1599}160016011602