Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BenefitInliner phase 2/3 Classes for building the IDT. #5508

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/control/OMROptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,7 @@ TR::OptionTable OMR::Options::_jitOptions[] = {
{"traceBasicBlockPeepHole", "L\ttrace basic blocks peepHole", TR::Options::traceOptimization, basicBlockPeepHole, 0, "P"},
{"traceBBVA", "L\ttrace backward bit vector analysis", SET_OPTION_BIT(TR_TraceBBVA), "P" },
{"traceBC", "L\tdump bytecodes", SET_OPTION_BIT(TR_TraceBC), "P" },
{"traceBenefitInlinerIDTGen", "L\ttrace benefit inliner IDT generation", SET_OPTION_BIT(TR_TraceBIIDTGen), "P" },
{"traceBlockFrequencyGeneration", "L\ttrace block frequency generation", SET_OPTION_BIT(TR_TraceBFGeneration), "P"},
{"traceBlockShuffling", "L\ttrace random rearrangement of blocks", TR::Options::traceOptimization, blockShuffling, 0, "P"},
{"traceBlockSplitter", "L\ttrace block splitter", TR::Options::traceOptimization, blockSplitter, 0, "P"},
Expand Down
2 changes: 1 addition & 1 deletion compiler/control/OMROptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ enum TR_CompilationOptions
TR_MimicInterpreterFrameShape = 0x00008000,

TR_TraceBC = 0x00010000,
// Available = 0x00020000,
TR_TraceBIIDTGen = 0x00020000,
TR_TraceTrees = 0x00040000,
TR_TraceCG = 0x00080000,
TR_TraceAliases = 0x00100000,
Expand Down
1 change: 1 addition & 0 deletions compiler/env/VerboseLog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ enum TR_VlogTag
TR_Vlog_PROFILING,
TR_Vlog_JITServer,
TR_Vlog_AOTCOMPRESSION,
TR_Vlog_BI, //(benefit inliner)
TR_Vlog_FSD,
TR_Vlog_VECTOR_API,
TR_Vlog_CHECKPOINT_RESTORE,
Expand Down
3 changes: 3 additions & 0 deletions compiler/optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,7 @@ compiler_library(optimizer
${CMAKE_CURRENT_LIST_DIR}/abstractinterpreter/AbsValue.cpp
${CMAKE_CURRENT_LIST_DIR}/abstractinterpreter/AbsOpStack.cpp
${CMAKE_CURRENT_LIST_DIR}/abstractinterpreter/AbsOpArray.cpp
${CMAKE_CURRENT_LIST_DIR}/abstractinterpreter/InliningMethodSummary.cpp
${CMAKE_CURRENT_LIST_DIR}/abstractinterpreter/IDTNode.cpp
${CMAKE_CURRENT_LIST_DIR}/abstractinterpreter/IDT.cpp
)
174 changes: 174 additions & 0 deletions compiler/optimizer/abstractinterpreter/IDT.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*******************************************************************************
* Copyright IBM Corp. and others 2020
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at http://eclipse.org/legal/epl-2.0
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/

#include "optimizer/abstractinterpreter/IDT.hpp"
#include "infra/String.hpp"

TR::IDT::IDT(TR::Region& region, TR_CallTarget* callTarget, TR::ResolvedMethodSymbol* symbol, uint32_t budget, TR::Compilation* comp):
_region(region),
_nextIdx(-1),
_comp(comp),
_root(new (_region) IDTNode(getNextGlobalIDTNodeIndex(), callTarget, symbol, -1, 1, NULL, budget)),
_indices(NULL),
_totalCost(0)
{
increaseGlobalIDTNodeIndex();
}

void TR::IDT::print()
{
bool verboseInlining = comp()->getOptions()->getVerboseOption(TR_VerboseInlining);
bool traceBIIDTGen = comp()->getOption(TR_TraceBIIDTGen);

if (!verboseInlining && !traceBIIDTGen)
return;
const uint32_t candidates = getNumNodes() - 1;
// print header line
TR::StringBuf line(comp()->trMemory()->currentStackRegion());
line.appendf("#IDT: %d candidate methods inlinable into %s with a budget %d",
candidates,
getRoot()->getName(comp()->trMemory()),
getRoot()->getBudget());

TR_VerboseLog::CriticalSection vlogLock(verboseInlining);
if (verboseInlining)
{
TR_VerboseLog::writeLine(TR_Vlog_BI, "%s", line.text());
}
if (traceBIIDTGen)
traceMsg(comp(), "%s\n", line.text());

if (candidates <= 0)
return;

// print the IDT nodes in BFS
TR::deque<TR::IDTNode*, TR::Region&> idtNodeQueue(comp()->trMemory()->currentStackRegion());

idtNodeQueue.push_back(getRoot());
while (!idtNodeQueue.empty())
{
TR::IDTNode* currentNode = idtNodeQueue.front();
idtNodeQueue.pop_front();

int32_t index = currentNode->getGlobalIndex();

// skip root node
if (index != -1)
{
line.clear();
line.appendf("#IDT: #%d: #%d inlinable @%d -> bcsz=%d %s target %s, static benefit = %d, benefit = %f, cost = %d, budget = %d, callratio = %f, rootcallratio = %f",
index,
currentNode->getParentGlobalIndex(),
currentNode->getByteCodeIndex(),
currentNode->getByteCodeSize(),
currentNode->getResolvedMethodSymbol()->signature(comp()->trMemory()),
currentNode->getName(comp()->trMemory()),
currentNode->getStaticBenefit(),
currentNode->getBenefit(),
currentNode->getCost(),
currentNode->getBudget(),
currentNode->getCallRatio(),
currentNode->getRootCallRatio()
);
if (verboseInlining)
TR_VerboseLog::writeLine(TR_Vlog_BI, "%s", line.text());

if (traceBIIDTGen)
traceMsg(comp(), "%s\n", line.text());
}

// process children
for (uint32_t i = 0; i < currentNode->getNumChildren(); i ++)
idtNodeQueue.push_back(currentNode->getChild(i));
}
}

void TR::IDT::flattenIDT()
{
if (_indices != NULL)
return;

// initialize nodes index array
uint32_t numNodes = getNumNodes();
_indices = new (_region) TR::IDTNode *[numNodes]();

// add all the descendents of the root node to the indices array
TR::deque<TR::IDTNode*, TR::Region&> idtNodeQueue(comp()->trMemory()->currentStackRegion());
idtNodeQueue.push_back(getRoot());

while (!idtNodeQueue.empty())
{
TR::IDTNode* currentNode = idtNodeQueue.front();
idtNodeQueue.pop_front();

const int32_t index = currentNode->getGlobalIndex();
TR_ASSERT_FATAL(_indices[index + 1] == 0, "Callee index not unique!\n");

_indices[index + 1] = currentNode;
jdmpapin marked this conversation as resolved.
Show resolved Hide resolved

for (uint32_t i = 0; i < currentNode->getNumChildren(); i ++)
{
idtNodeQueue.push_back(currentNode->getChild(i));
}
}
}

TR::IDTNode *TR::IDT::getNodeByGlobalIndex(int32_t index)
{
TR_ASSERT_FATAL(_indices, "Call flattenIDT() first");
TR_ASSERT_FATAL(index < getNextGlobalIDTNodeIndex(), "Index out of range!");
jdmpapin marked this conversation as resolved.
Show resolved Hide resolved
TR_ASSERT_FATAL(index >= -1, "Index too low!");
return _indices[index + 1];
}

TR::IDTPriorityQueue::IDTPriorityQueue(TR::IDT* idt, TR::Region& region) :
_entries(region),
_idt(idt),
_pQueue(IDTNodeCompare(), IDTNodeVector(region))
{
_pQueue.push(idt->getRoot());
}

TR::IDTNode* TR::IDTPriorityQueue::get(uint32_t index)
{
const size_t entriesSize = _entries.size();

const uint32_t idtSize = size();
TR_ASSERT_FATAL(index < idtSize, "IDTPriorityQueue::get index out of bound!");
// already in entries
if (entriesSize > index)
return _entries.at(index);

// not in entries yet. Update entries.
while (_entries.size() <= index)
{
TR::IDTNode *newEntry = _pQueue.top();
_pQueue.pop();

_entries.push_back(newEntry);
for (uint32_t j = 0; j < newEntry->getNumChildren(); j++)
{
_pQueue.push(newEntry->getChild(j));
}
}

return _entries.at(index);
}
142 changes: 142 additions & 0 deletions compiler/optimizer/abstractinterpreter/IDT.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*******************************************************************************
* Copyright IBM Corp. and others 2020
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at http://eclipse.org/legal/epl-2.0
* or the Apache License, Version 2.0 which accompanies this distribution
* and is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception [1] and GNU General Public
* License, version 2 with the OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/

#ifndef IDT_INCL
#define IDT_INCL

#include "compile/Compilation.hpp"
#include "optimizer/CallInfo.hpp"
#include "optimizer/abstractinterpreter/IDTNode.hpp"
#include "env/Region.hpp"
#include "env/VerboseLog.hpp"
#include "il/ResolvedMethodSymbol.hpp"
#include <queue>

namespace TR {

/**
* IDT stands for Inlining Dependency Tree
* It is a structure that holds all candidate methods to be inlined.
*
* The parent-child relationship in the IDT corresponds to the caller-callee relationship.
*/
class IDT
{
public:
IDT(TR::Region& region, TR_CallTarget*, TR::ResolvedMethodSymbol* symbol, uint32_t budget, TR::Compilation* comp);

TR::IDTNode* getRoot() { return _root; }

TR::Region& getRegion() { return _region; }

void addCost(uint32_t cost) { _totalCost += cost; }
uint32_t getTotalCost() { return _totalCost; }

/**
* @brief Get the total number of nodes in this IDT.
*
* @return the total number of node
*/
uint32_t getNumNodes() { return _nextIdx + 1; }

/**
* @brief Get the next avaible IDTNode index.
*
* @return the next index
*/
int32_t getNextGlobalIDTNodeIndex() { return _nextIdx; }

/**
* @brief Increase the next available IDTNode index by 1.
* This should only be called when successfully adding an IDTNode to the IDT
*/
void increaseGlobalIDTNodeIndex() { _nextIdx ++; }

/**
* @brief Get the IDTNode using index.
* Before using this method for accessing IDTNode, flattenIDT() must be called.
*
* @return the IDT node
*/
TR::IDTNode *getNodeByGlobalIndex(int32_t index);

/**
* @brief Flatten all the IDTNodes into a list.
*/
void flattenIDT();

void print();

private:
TR::Compilation* comp() { return _comp; }

TR::Compilation *_comp;
TR::Region& _region;
int32_t _nextIdx;
uint32_t _totalCost;
TR::IDTNode* _root;
TR::IDTNode** _indices;
};

/**
* A topological sort of the IDT in which the lowest-benefit node is listed first and lowest cost used to
* break the tie whenever there is a choice.
*
* This topological sort is to prepare an ordered list of inlining options for the algorithm described
* in following patent:
* https://patents.google.com/patent/US10055210B2/en
*
* This patent describes the topological sort as the following quote:
* "constraints on the order of node consideration, where the constraints serve to ensure every node is
* considered only after all of the node's ancestors are considered, and nodes are included in order of
* increasing cumulative benefit with lowest cumulative cost used to break ties to allow the generation
* of all intermediate solutions at a given cost budget to simplify backtracking in subsequent iterations
* of the algorithm".
*/
class IDTPriorityQueue
{
public:
IDTPriorityQueue(TR::IDT* idt, TR::Region& region);
uint32_t size() { return _idt->getNumNodes(); }

TR::IDTNode* get(uint32_t index);

private:
struct IDTNodeCompare
{
bool operator()(TR::IDTNode *left, TR::IDTNode *right)
{
TR_ASSERT_FATAL(left && right, "Comparing against null");
if (left->getBenefit() == right->getBenefit()) return left->getCost() > right->getCost();
else return left->getBenefit() > right->getBenefit();
}
};

typedef TR::vector<IDTNode*, TR::Region&> IDTNodeVector;
typedef std::priority_queue<IDTNode*, IDTNodeVector, IDTNodeCompare> IDTNodePriorityQueue;

TR::IDT* _idt;
IDTNodePriorityQueue _pQueue;
IDTNodeVector _entries;
};
}

#endif
Loading