Skip to content

Commit

Permalink
Add classes for building and handling the IDT and InliningMethodSumma…
Browse files Browse the repository at this point in the history
…ry for the BenefitInliner.

IDT.cpp, IDTNode.cpp, InliningMethodSummary.cpp

This is the phase 2/3 of the BenefitInliner contribution.

Co-authored-by: Cijie Xia <[email protected]>
Co-authored-by: dino li <[email protected]>
Co-authored-by: Qasim Khawaja <[email protected]>
Co-authored-by: Siva C. Nandipati <[email protected]>
Signed-off-by: Mingwei Li <[email protected]>
  • Loading branch information
5 people committed Jun 5, 2023
1 parent c766c41 commit 13a02cd
Show file tree
Hide file tree
Showing 10 changed files with 947 additions and 1 deletion.
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;

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!");
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

0 comments on commit 13a02cd

Please sign in to comment.