Skip to content

Commit

Permalink
Merge pull request #16799 from mpirvu/edo-fix
Browse files Browse the repository at this point in the history
Infrastructure for EDO profiling optimization
  • Loading branch information
ymanton authored Mar 2, 2023
2 parents 6cddd76 + 99ce07c commit a8164fc
Show file tree
Hide file tree
Showing 9 changed files with 29 additions and 278 deletions.
227 changes: 2 additions & 225 deletions runtime/compiler/control/CompilationController.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2022 IBM Corp. and others
* Copyright (c) 2000, 2023 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -64,8 +64,7 @@ bool TR::CompilationController::init(TR::CompilationInfo *compInfo)
_compInfo = compInfo;
if (strcmp(strategyName, "default") == 0)
_compilationStrategy = new (PERSISTENT_NEW) TR::DefaultCompilationStrategy();
else if (strcmp(strategyName, "threshold") == 0)
_compilationStrategy = new (PERSISTENT_NEW) TR::ThresholdCompilationStrategy();
// checks for other strategies go here
else // if no match, use default
{
_compilationStrategy = new (PERSISTENT_NEW) TR::DefaultCompilationStrategy();
Expand Down Expand Up @@ -1497,225 +1496,3 @@ void TR::DefaultCompilationStrategy::postCompilation(TR_OptimizationPlan *plan,
TR_OptimizationPlan::_optimizationPlanMonitor->exit();
}
}





//============================= ThresholdCompilationStrategy ====================


TR::ThresholdCompilationStrategy::ThresholdCompilationStrategy()
{
// To be safe, clear everything out before setting anything
for (int32_t level=noOpt; level <= numHotnessLevels; level++)
{
_nextLevel[level] = unknownHotness;
_samplesNeededToMoveTo[level] = -1;
_performInstrumentation[level] = false;
}

// Now, initialize our strategy threshold based strategy
//
// These could easily be set from command line options or any other
// way (maybe from the existing options string?)
//
// The current strategy uses only noOpt -> warm -> scorching. (and veryHot if instrumentation-based profiling is used)
_samplesNeededToMoveTo[noOpt] = 1;
_samplesNeededToMoveTo[warm] = 6;
int32_t SCORCHING_THRESH = 20;
_samplesNeededToMoveTo[scorching] = SCORCHING_THRESH;

// If we are doing instrumentation-based profiling
if (!TR::Options::getCmdLineOptions()->getOption(TR_DisableProfiling))
{
// Insert instrumentation in VeryHot
_samplesNeededToMoveTo[veryHot] = SCORCHING_THRESH;
_performInstrumentation[veryHot] = 1; // Yes, perform profiling at this level

_samplesNeededToMoveTo[scorching] = SCORCHING_THRESH + 1; // Sampling is disable during instrumentation-based profiling,
// so this is really just a place holder
}

// Use the information above to setup the "next" pointers.
// Go through list backwards, and for each "active" level, set where you'll jump to next.
int32_t prevActiveLevel = unknownHotness;
for (int32_t curLevel = numHotnessLevels;
curLevel >= noOpt; // should be "> minHotness" if it existed
curLevel--)
{
if (_samplesNeededToMoveTo[curLevel] > 0)
{
// curLevel is an active level
_nextLevel[curLevel] = (TR_Hotness) prevActiveLevel;
prevActiveLevel = curLevel;
}
}
// Finally, check unknownHotness (which represents the method still being interpreted) last
_nextLevel[unknownHotness] = (TR_Hotness) prevActiveLevel;

}



TR_Hotness TR::ThresholdCompilationStrategy::getInitialOptLevel()
{
return noOpt;
}


TR_OptimizationPlan *TR::ThresholdCompilationStrategy::processEvent(TR_MethodEvent *event, bool *newPlanCreated)
{
TR_OptimizationPlan *plan = NULL;
TR_Hotness hotnessLevel;
TR_PersistentJittedBodyInfo *bodyInfo;
TR_PersistentMethodInfo *methodInfo;
*newPlanCreated = false;

if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL3)
fprintf(stderr, "Received event %d\n", event->_eventType);

// first decode the event type
switch (event->_eventType)
{
case TR_MethodEvent::InterpretedMethodSample:
// do nothing
break;
case TR_MethodEvent::InterpreterCounterTripped:
TR_ASSERT(event->_oldStartPC == 0, "oldStartPC should be 0 for an interpreted method");
// use the counts to determine the first level of compilation
// the level of compilation can be changed later on if option subsets are present
hotnessLevel = TR::ThresholdCompilationStrategy::getInitialOptLevel();
plan = TR_OptimizationPlan::alloc(hotnessLevel);
*newPlanCreated = true;
break;
case TR_MethodEvent::OtherRecompilationTrigger: // sync recompilation through fixMethodCode
// For sync re-compilation we attach the plan to the persistentBodyInfo
bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);
methodInfo = bodyInfo->getMethodInfo();

if (methodInfo->getReasonForRecompilation() == TR_PersistentMethodInfo::RecompDueToInlinedMethodRedefinition)
{
methodInfo->incrementNumberOfInlinedMethodRedefinition();
hotnessLevel = bodyInfo->getHotness();
plan = TR_OptimizationPlan::alloc(hotnessLevel);
*newPlanCreated = true;
}
else if (methodInfo->getOptimizationPlan())
{
TR_ASSERT(!TR::CompilationController::getCompilationInfo()->asynchronousCompilation(), "This case should happen only for sync recompilation");
plan = methodInfo->getOptimizationPlan();
}
else
{
//hotnessLevel = TR::Recompilation::getNextCompileLevel(event->_oldStartPC);
hotnessLevel = getNextOptLevel(bodyInfo->getHotness());
plan = TR_OptimizationPlan::alloc(hotnessLevel);
*newPlanCreated = true;
}
break;
case TR_MethodEvent::NewInstanceImpl:
hotnessLevel = getInitialOptLevel();
plan = TR_OptimizationPlan::alloc(hotnessLevel);
*newPlanCreated = true;
break;
case TR_MethodEvent::MethodBodyInvalidated:
// keep the same optimization level
bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(event->_oldStartPC);
TR_ASSERT(bodyInfo, "A recompilable method should have jittedBodyInfo");
hotnessLevel = bodyInfo->getHotness();
plan = TR_OptimizationPlan::alloc(hotnessLevel);
*newPlanCreated = true;
// the following is just for compatibility with older implementation
bodyInfo->getMethodInfo()->setNextCompileLevel(hotnessLevel, false); // no profiling
break;
case TR_MethodEvent::JittedMethodSample:
plan = processJittedSample(event);
*newPlanCreated = true;
break;

default:
TR_ASSERT(0, "Bad event type %d", event->_eventType);
}

if (TR::CompilationController::verbose() >= TR::CompilationController::LEVEL2)
fprintf(stderr, "Event %d created plan %p\n", event->_eventType, plan);

return plan;
}


TR_OptimizationPlan *
TR::ThresholdCompilationStrategy::processJittedSample(TR_MethodEvent *event)
{
TR_OptimizationPlan *plan = NULL;
TR::Options * cmdLineOptions = TR::Options::getCmdLineOptions();
J9Method *j9method = event->_j9method;
J9JITConfig *jitConfig = event->_vmThread->javaVM->jitConfig;
TR_J9VMBase * fe = TR_J9VMBase::get(jitConfig, event->_vmThread);
void *startPC = event->_oldStartPC;
// here we may need to write into the vlog


J9::PrivateLinkage::LinkageInfo *linkageInfo = J9::PrivateLinkage::LinkageInfo::get(startPC);
TR_PersistentJittedBodyInfo *bodyInfo = NULL;

if (linkageInfo->hasFailedRecompilation())
{
//if (logSampling)
// msgLen += sprintf(msg + msgLen, " has already failed a recompilation attempt");
}
else if (!linkageInfo->isSamplingMethodBody())
{
//if (logSampling)
// msgLen += sprintf(msg + msgLen, " does not use sampling");
}
else if (debug("disableSamplingRecompilation"))
{
//if (logSampling)
//msgLen += sprintf(msg + msgLen, " sampling disabled");
}
else
bodyInfo = TR::Recompilation::getJittedBodyInfoFromPC(startPC);

if (bodyInfo && bodyInfo->getDisableSampling())
{
//if (logSampling)
//msgLen += sprintf(msg + msgLen, " uses sampling but sampling disabled (last comp. with prex)");
bodyInfo = NULL;
}

if (bodyInfo)
{
TR_PersistentMethodInfo *methodInfo = bodyInfo->getMethodInfo();
fe->acquireCompilationLock();
void *currentStartPC = (void *)TR::Compiler->mtd.startPC((TR_OpaqueMethodBlock *) methodInfo->getMethodInfo());
if (currentStartPC != startPC) // rare case; sampling an old body
{
fe->releaseCompilationLock();
// do nothing
}
else if (TR::Options::getCmdLineOptions()->getFixedOptLevel() != -1
|| TR::Options::getAOTCmdLineOptions()->getFixedOptLevel() != -1) // prevent recompilation when opt level is specified
{
fe->releaseCompilationLock();
// do nothing
}
else
{
// increment the CPOcount and see if we need to recompile
int32_t sampleCount = methodInfo->cpoIncCounter();
fe->releaseCompilationLock();
TR_Hotness curOptLevel = bodyInfo->getHotness();
TR_Hotness nextOptLevel = getNextOptLevel(curOptLevel);

if ((nextOptLevel != unknownHotness) && (sampleCount == getSamplesNeeded(nextOptLevel)))
{
bool useSampling = (getNextOptLevel(nextOptLevel) != unknownHotness);
plan = TR_OptimizationPlan::alloc(nextOptLevel,
getPerformInstrumentation(nextOptLevel), useSampling);
}
}
}
return plan;
}
24 changes: 1 addition & 23 deletions runtime/compiler/control/CompilationController.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2022 IBM Corp. and others
* Copyright (c) 2000, 2023 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -235,26 +235,4 @@ class DefaultCompilationStrategy : public TR::CompilationStrategy
};
} // namespace TR

//----------------------- TR::ThresholdCompilationStrategy ---------------------
namespace TR
{

class ThresholdCompilationStrategy : public TR::CompilationStrategy
{
public:
TR_PERSISTENT_ALLOC(TR_Memory::PersistentInfo); // Do I need this ?
ThresholdCompilationStrategy();
TR_OptimizationPlan *processEvent(TR_MethodEvent *event, bool *newPlanCreated);
TR_OptimizationPlan *processJittedSample(TR_MethodEvent *event);
TR_Hotness getInitialOptLevel();
int32_t getSamplesNeeded(TR_Hotness optLevel) { TR_ASSERT(_samplesNeededToMoveTo[optLevel] >= 0, "must be valid entry"); return _samplesNeededToMoveTo[optLevel]; }
bool getPerformInstrumentation(TR_Hotness optLevel) { return _performInstrumentation[optLevel]; }
TR_Hotness getNextOptLevel(TR_Hotness curOptLevel) { TR_ASSERT(_nextLevel[curOptLevel] != unknownHotness, "must be valid opt level"); return _nextLevel[curOptLevel]; }

private:
TR_Hotness _nextLevel[numHotnessLevels+1];
int32_t _samplesNeededToMoveTo[numHotnessLevels+1];
bool _performInstrumentation[numHotnessLevels+1];
};
} // namespace TR
#endif // ifndef COMPILATIONCONTROLLER_INCL
3 changes: 2 additions & 1 deletion runtime/compiler/control/CompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10921,7 +10921,8 @@ void TR::CompilationInfoPerThreadBase::logCompilationSuccess(
recompReason = 'G';// Guarded counting recompilation
_compInfo._statNumGCRInducedCompilations++;
break;
// TODO: add here the EDO case if we ever modify the codegen to track that
case TR_PersistentMethodInfo::RecompDueToEdo:
recompReason = 'E'; break;
} // end switch
bodyInfo->getMethodInfo()->setReasonForRecompilation(0); // reset the flags
}
Expand Down
16 changes: 5 additions & 11 deletions runtime/compiler/control/J9Recompilation.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2022 IBM Corp. and others
* Copyright (c) 2000, 2023 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -497,7 +497,7 @@ J9::Recompilation::getExistingMethodInfo(TR_ResolvedMethod *method)
/**
* This method can extract a value profiler from the current list of
* recompilation profilers.
*
*
* \return The first TR_ValueProfiler in the current list of profilers, NULL if there are none.
*/
TR_ValueProfiler *
Expand Down Expand Up @@ -585,6 +585,7 @@ TR_PersistentMethodInfo::TR_PersistentMethodInfo(TR::Compilation *comp) :
_recentProfileInfo(0),
_bestProfileInfo(0),
_optimizationPlan(0),
_catchBlockCounter(0),
_numberOfInvalidations(0),
_numberOfInlinedMethodRedefinition(0),
_numPrexAssumptions(0)
Expand All @@ -601,14 +602,6 @@ TR_PersistentMethodInfo::TR_PersistentMethodInfo(TR::Compilation *comp) :
setDisableProfiling();
}

// Start cpoSampleCounter at 1. Because the method sample count
// is stored in the compiled method info, we can't start counting
// until already compiled once, thus we missed the first sample.
// (not particularly clean solution. Should really attach the
// counter to the method, not the compiled-method)
//
_cpoSampleCounter = 1;

uint64_t tempTimeStamp = comp->getPersistentInfo()->getElapsedTime();
if (tempTimeStamp < (uint64_t)0x0FFFF)
_timeStamp = (uint16_t)tempTimeStamp;
Expand All @@ -623,6 +616,7 @@ TR_PersistentMethodInfo::TR_PersistentMethodInfo(TR_OpaqueMethodBlock *methodInf
_recentProfileInfo(0),
_bestProfileInfo(0),
_optimizationPlan(0),
_catchBlockCounter(0),
_numberOfInvalidations(0),
_numberOfInlinedMethodRedefinition(0),
_numPrexAssumptions(0)
Expand Down Expand Up @@ -739,7 +733,7 @@ TR_PersistentMethodInfo::setForSharedInfo(TR_PersistentProfileInfo** ptr, TR_Per
// Before it can be accessed, inc ref count on new info
if (newInfo)
TR_PersistentProfileInfo::incRefCount(newInfo);

// Update ptr as if it was unlocked
// Doesn't matter what the old info was, as long as it was unlocked
do {
Expand Down
Loading

0 comments on commit a8164fc

Please sign in to comment.