Skip to content

Commit

Permalink
Merge pull request #24 from yyan7223/master
Browse files Browse the repository at this point in the history
Add the incremental mapping function, which re-utilizes the previous mapping results to acceleterate ccurrent mapping.
  • Loading branch information
tancheng authored Sep 16, 2024
2 parents 80ce2d7 + c9cc6d3 commit e76bf4e
Show file tree
Hide file tree
Showing 7 changed files with 283 additions and 15 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Execution
- [optLatency](https://github.com/tancheng/CGRA-Mapper/blob/589fd61434966e4d4a44220b59854b1795bc7cde/test/param.json#L19): used to support multi-cycle execution. If this field is not specified, every operation is done in one single-cycle. Note that there is currently no hardware support for this feature, which is supposed to be used for performance exploration only.
- [optPipelined](https://github.com/tancheng/CGRA-Mapper/blob/589fd61434966e4d4a44220b59854b1795bc7cde/test/param.json#L23): used to enable pipelined execution of the multi-cycle operation (i.e., indicated in [optLatency](https://github.com/tancheng/CGRA-Mapper/blob/589fd61434966e4d4a44220b59854b1795bc7cde/test/param.json#L19)).
- [additionalFunc](https://github.com/tancheng/CGRA-Mapper/blob/589fd61434966e4d4a44220b59854b1795bc7cde/test/param.json#L24): used to enable specific functionalities on target tiles. Normally, we don't need to set this field as all the tiles already include most functionalities. By default, the `ld`/`st` is only enabled on the left most tiles. So if you wanna enable the memory access on the other tiles, this field needs to be provided.
- [incrementalMapping](https://github.com/yyan7223/CGRA-Mapper/blob/10aa217e9e995b6dfa4242e0ce121b79668e9995/test/param.json#L28C1-L28C33) `true` indicates incremental mapping while `false` indicates heuristic/exhaustive mapping. Incremental mapping re-utilizes the previous mapping results of current kernel (e.g., on 4x4 CGRA) to accelerate its mapping on the new resource allocation decisions (e.g., on 5x5 CGRA). To simply check the acceleration effect of incremental mapping, calls heuristic mapping first to generate `increMapInput.json` for current kernel on 4x4 CGRA, then sets incrementalMapping to `true` and performs mapping on 5x5 CGRA again, finally checks the elapsed time differences.

- Run:
```
Expand Down
4 changes: 4 additions & 0 deletions src/CGRANode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,3 +579,7 @@ void CGRANode::disableAllFUs() {
m_supportComplex = false;
m_supportVectorization = false;
}

bool CGRANode::isDisabled() {
return m_disabled;
}
1 change: 1 addition & 0 deletions src/CGRANode.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class CGRANode {
void allocateReg(int, int, int, int);
int* getRegsAllocation(int);
void disable();
bool isDisabled();
void disableAllFUs();
};

Expand Down
247 changes: 237 additions & 10 deletions src/Mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ void Mapper::showSchedule(CGRA* t_cgra, DFG* t_dfg, int t_II,

if (cycle < t_II and t_parameterizableCGRA) {
for (int i=0; i<t_cgra->getLinkCount(); ++i) {
CGRALink* link = t_cgra->links[i];
CGRALink* link = t_cgra->links[i];
if (link->isOccupied(cycle, t_II, t_isStaticElasticCGRA)) {
string strSrcNodeID = to_string(link->getSrc()->getID());
string strDstNodeID = to_string(link->getDst()->getID());
Expand All @@ -528,7 +528,7 @@ void Mapper::showSchedule(CGRA* t_cgra, DFG* t_dfg, int t_II,
jsonLinks[strSrcNodeID][strDstNodeID] = jsonLinkDstCycles;
}
jsonLinks[strSrcNodeID][strDstNodeID].push_back(cycle);
}
}
}
}

Expand Down Expand Up @@ -563,15 +563,15 @@ void Mapper::showSchedule(CGRA* t_cgra, DFG* t_dfg, int t_II,
str_fu = "[ " + to_string(dfgNode->getID()) + " ]";
else
str_fu = "[ " + to_string(dfgNode->getID()) + " ]";
string strNodeID = to_string(t_cgra->nodes[i][j]->getID());
if (t_parameterizableCGRA) {
if (jsonTiles.find(strNodeID) == jsonTiles.end()) {
string strNodeID = to_string(t_cgra->nodes[i][j]->getID());
if (t_parameterizableCGRA) {
if (jsonTiles.find(strNodeID) == jsonTiles.end()) {
map<string, vector<int>> jsonTileCycleOps;
jsonTiles[strNodeID] = jsonTileCycleOps;
}
vector<int> jsonCycleOp { dfgNode->getID() };
jsonTiles[strNodeID][to_string(cycle % t_II)] = jsonCycleOp;
}
jsonTiles[strNodeID] = jsonTileCycleOps;
}
vector<int> jsonCycleOp { dfgNode->getID() };
jsonTiles[strNodeID][to_string(cycle % t_II)] = jsonCycleOp;
}
} else {
str_fu = "[ ]";
}
Expand Down Expand Up @@ -1346,3 +1346,230 @@ map<int, CGRANode*>* Mapper::getReorderPath(map<CGRANode*, int>* t_path) {
return reorderPath;
}

// Saves the mapping results to json file for subsequent incremental mapping.
void Mapper::generateJSON4IncrementalMap(CGRA* t_cgra, DFG* t_dfg){
ofstream jsonFile("increMapInput.json", ios::out);
jsonFile<<"{"<<endl;
jsonFile<<" \"Opt2TileXY\":{"<<endl;
int idx = 0;
for (DFGNode* dfgNode: t_dfg->nodes) {
// Writes dfgnodeID, mapped CGRANode X and Y coordinates.i
// opt id.
jsonFile<<" \""<<dfgNode->getID()<<"\": {"<<endl;
// opt mapped tile x coordinate.
jsonFile<<" \"x\":"<<m_mapping[dfgNode]->getX()<<","<<endl;
// opt mapped tile y coordinate.
jsonFile<<" \"y\":"<<m_mapping[dfgNode]->getY()<<endl;
idx += 1;
if (idx < t_dfg->nodes.size()) jsonFile<<" },"<<endl;
else jsonFile<<" }"<<endl;
}
jsonFile<<" },"<<endl;

jsonFile<<" \"Tile2Level\":{"<<endl;
// Generates level informations of current mapping results.
// FanIO is the number of links of current CGRANode connected to other CGRANode,
// and FanIO_CGRANodes can help with querying the list of CGRANodes with the given FanIO.
vector<int> FanIOs;
map<int, vector<CGRANode*>> FanIO_CGRANodes;
int numTiles = 0;
for (int i=0; i<t_cgra->getRows(); ++i) {
for (int j=0; j<t_cgra->getColumns(); ++j) {

// Records the number of FanIO for each tile.
CGRANode* currentCGRANode = t_cgra->nodes[i][j];
// Only records tiles that have DFGNodes mapped.
if (currentCGRANode->getInLinks() == 0) continue;
int FanIO = max(currentCGRANode->getInLinks()->size(), currentCGRANode->getOutLinks()->size());
FanIO_CGRANodes[FanIO].push_back(currentCGRANode);

// Records FanIO in the list if it appears for the first time.
if (find(FanIOs.begin(), FanIOs.end(), FanIO) == FanIOs.end()) {
FanIOs.push_back(FanIO);
}

numTiles++;
}
}

// Sorts FanIOs from big to small helps automatically form the level.
// Level indicates the ranking of CGRA according to the FanIOs that CGRANode has,
// high level means higher FanIOs, CGRANodes within the same level have same FanIOs.
std::sort(FanIOs.rbegin(), FanIOs.rend());
idx = 0;
for (int level = 0; level < FanIOs.size(); level++) {
int FanIO = FanIOs[level];
vector<CGRANode*> tiles = FanIO_CGRANodes[FanIO];
for (auto tile : tiles) {
idx += 1;
if (idx < numTiles) jsonFile<<" \""<<tile->getID()<<"\":"<<level<<","<<endl;
else jsonFile<<" \""<<tile->getID()<<"\":"<<level<<endl;
}
}
jsonFile<<" }"<<endl;

jsonFile<<"}"<<endl;
}

// Reads from the referenced mapping results json file and generates variables for incremental mapping.
int Mapper::readRefMapRes(CGRA* t_cgra, DFG* t_dfg){
ifstream refFile("./increMapInput.json");
if (!refFile.good()) {
cout<<"Incremental mapping requires increMapInput.json in current directory!"<<endl;
return -1;
}
json refs;
refFile >> refs;
CGRANodeID2Level.clear();
for (list<DFGNode*>::iterator dfgNode=t_dfg->nodes.begin(); dfgNode != t_dfg->nodes.end(); ++dfgNode) {
int dfgNodeID = (*dfgNode)->getID();
int x = refs["Opt2TileXY"][to_string(dfgNodeID)]["x"];
int y = refs["Opt2TileXY"][to_string(dfgNodeID)]["y"];
refMapRes[*dfgNode] = t_cgra->nodes[y][x];
int cgraNodeID = t_cgra->nodes[y][x]->getID();
CGRANodeID2Level[cgraNodeID] = refs["Tile2Level"][to_string(cgraNodeID)];
}

return 0;
}

// Generates variables for incremental mapping.
void Mapper::sortAllocTilesByLevel(CGRA* t_cgra){
map<int, vector<CGRANode*>> FanIO_CGRANodes;
vector<int> FanIOs;
int numTiles = 0;
for (int i=0; i<t_cgra->getRows(); ++i) {
for (int j=0; j<t_cgra->getColumns(); ++j) {

// Records the number of FanIO for each tile.
CGRANode* currentCGRANode = t_cgra->nodes[i][j];
// only record tiles that have DFGNodes mapped.
if (currentCGRANode->isDisabled()) continue;
int FanIO = max(currentCGRANode->getInLinks()->size(), currentCGRANode->getOutLinks()->size());
FanIO_CGRANodes[FanIO].push_back(currentCGRANode);

// Records FanIO in the list if it appears for the first time.
if (find(FanIOs.begin(), FanIOs.end(), FanIO) == FanIOs.end()) {
FanIOs.push_back(FanIO);
}

numTiles++;
}
}
// Sorts FanIOs from big to small to automatically form the level.
std::sort(FanIOs.rbegin(), FanIOs.rend());

CGRANodes_sortedByLevel.clear();
for (int level = 0; level < FanIOs.size(); level++) {
int FanIO = FanIOs[level];
vector<CGRANode*> tiles = FanIO_CGRANodes[FanIO];
CGRANodes_sortedByLevel.push_back(tiles);
}
}

// Generates the placement recommendation list for current DFGNode
// by referencing its placement in the former mapping results.
// Two principles: Reference Placement Tendency (RPT) & Minimize Bypass Operations (MBO).
list<CGRANode*> Mapper::placementGen(CGRA* t_cgra, DFGNode* t_dfgNode){
list<CGRANode*> placementRecommList;
CGRANode* refCGRANode = refMapRes[t_dfgNode];
list<DFGNode*>* predNodes = t_dfgNode->getPredNodes();
// The level is used to ordering the CGRANodes based on the FanIO.
// Though FanIO of each CGRANode would change for different CGRA architectures,
// the DFGNode prefers to being mapped onto the CGRANode with same level.
int refLevel = CGRANodeID2Level[refCGRANode->getID()];
int level = refLevel;
int maxLevel = CGRANodes_sortedByLevel.size() - 1;
cout<<t_dfgNode->getOpcodeName()<<t_dfgNode->getID()<<" is mapped to Tile "<<refCGRANode->getID()<<" in the referenced mapping results, refLevel="<<refLevel<<endl;

int initLevel = level;
while (true) {
// Sorts the CGRANodes with the number of bypass operations
// required to communicate with its predecessors.
map<int, vector<CGRANode*>> bypassNums_CGRANode;
int curX, curY, preX, preY;
int xdiff, ydiff;
for (auto curCGRANode : CGRANodes_sortedByLevel[level]) {
int numBypass = 0;
for (DFGNode* pre: *predNodes) {
if (m_mapping.find(pre) != m_mapping.end()) {
CGRANode* preCGRANode = m_mapping[pre];
xdiff = abs(curCGRANode->getX() - preCGRANode->getX());
ydiff = abs(curCGRANode->getY() - preCGRANode->getY());
numBypass += (xdiff + ydiff);
}
else continue;
}
bypassNums_CGRANode[numBypass].push_back(curCGRANode);
}

// bypassNums_CGRANode is sorted by key from smallest to largest by default,
// and tile with fewer bypass nodes has higher priority.
for (auto iter : bypassNums_CGRANode) {
for (auto tile : iter.second) {
placementRecommList.push_back(tile);
}
}

level += 1;
if (level > maxLevel) {
// Goes back to the highest level.
level = 0;
}
if (level == initLevel) break;
}

return placementRecommList;
}

// Incremental mapping function.
int Mapper::incrementalMap(CGRA* t_cgra, DFG* t_dfg, int t_II){
if (readRefMapRes(t_cgra, t_dfg) == -1) return -1;
sortAllocTilesByLevel(t_cgra);

bool dfgNodeMapFailed;
while (1) {
cout<<"----------------------------------------\n";
cout<<"[DEBUG] start incremental mapping with II="<<t_II<<"\n";
int cycle = 0;
constructMRRG(t_dfg, t_cgra, t_II);
for (list<DFGNode*>::iterator dfgNode=t_dfg->nodes.begin(); dfgNode!=t_dfg->nodes.end(); dfgNode++) {
list<CGRANode*> placementRecommList = placementGen(t_cgra, *dfgNode);
dfgNodeMapFailed = true;
for (auto fu : placementRecommList) {
map<CGRANode*, int>* path = calculateCost(t_cgra, t_dfg, t_II, *dfgNode, fu);
if (path == NULL) {
// Switches to the next tile.
cout<<"[DEBUG] no available path for DFG node "<<(*dfgNode)->getID()<<" on CGRA node "<<fu->getID()<<" within II "<<t_II<<endl;
continue;
}
else {
if (schedule(t_cgra, t_dfg, t_II, *dfgNode, path, false)) {
// Current DFGNode is scheduled successfully, moves to the next DFGNode.
dfgNodeMapFailed = false;
break;
}
else {
// Switches to the next tile.
cout<<"[DEBUG] no available path to schedule DFG node "<<(*dfgNode)->getID()<<" on CGRA node "<<fu->getID()<<" within II "<<t_II<<endl;
continue;
}
}
}
// Increases II and restart if current DFGNode fails the mapping.
if (dfgNodeMapFailed) break;
}

if (dfgNodeMapFailed) {
cout<<"[DEBUG] fail in schedule() under II: "<<t_II<<"\n";
t_II++;
}
else {
cout<<"[DEBUG] success in schedule() under II: "<<t_II<<"\n";
return t_II;
}
}

return -1;
}

11 changes: 11 additions & 0 deletions src/Mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ class Mapper {
bool DFSMap(CGRA*, DFG*, int, list<DFGNode*>*, list<map<CGRANode*, int>*>*, bool);
list<map<CGRANode*, int>*>* getOrderedPotentialPaths(CGRA*, DFG*, int,
DFGNode*, list<map<CGRANode*, int>*>*);
// The mapping relationship referenced by incrementalMap, read from increMapInput.json file
map<DFGNode*, CGRANode*> refMapRes;
// One to one relationship between CGRANode and its level
map<int, int> CGRANodeID2Level;
// The list of CGRANodes sorted by levels
vector<vector<CGRANode*>> CGRANodes_sortedByLevel;

public:
Mapper(){}
Expand All @@ -40,4 +46,9 @@ class Mapper {
bool schedule(CGRA*, DFG*, int, DFGNode*, map<CGRANode*, int>*, bool);
void showSchedule(CGRA*, DFG*, int, bool, bool);
void generateJSON(CGRA*, DFG*, int, bool);
void generateJSON4IncrementalMap(CGRA*, DFG*);
int readRefMapRes(CGRA*, DFG*);
void sortAllocTilesByLevel(CGRA*);
list<CGRANode*> placementGen(CGRA*, DFGNode*);
int incrementalMap(CGRA*, DFG*, int);
};
31 changes: 27 additions & 4 deletions src/mapperPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using namespace llvm;
using namespace std;
using json = nlohmann::json;
using namespace chrono;

void addDefaultKernels(map<string, list<int>*>*);

Expand Down Expand Up @@ -57,7 +58,8 @@ namespace {
bool diagonalVectorization = false;
bool heterogeneity = false;
bool heuristicMapping = true;
bool parameterizableCGRA = false;
bool parameterizableCGRA = false;
bool incrementalMapping = false;
map<string, int>* execLatency = new map<string, int>();
list<string>* pipelinedOpt = new list<string>();
map<string, list<int>*>* additionalFunc = new map<string, list<int>*>();
Expand Down Expand Up @@ -97,6 +99,7 @@ namespace {
paramKeys.insert("heterogeneity");
paramKeys.insert("heuristicMapping");
paramKeys.insert("parameterizableCGRA");
paramKeys.insert("incrementalMapping");

try
{
Expand Down Expand Up @@ -135,6 +138,7 @@ namespace {
heterogeneity = param["heterogeneity"];
heuristicMapping = param["heuristicMapping"];
parameterizableCGRA = param["parameterizableCGRA"];
incrementalMapping = param["incrementalMapping"];
cout<<"Initialize opt latency for DFG nodes: "<<endl;
for (auto& opt : param["optLatency"].items()) {
cout<<opt.key()<<" : "<<opt.value()<<endl;
Expand Down Expand Up @@ -211,13 +215,26 @@ namespace {
bool success = false;
if (!isStaticElasticCGRA) {
cout << "==================================\n";
typedef std::chrono::high_resolution_clock Clock;
auto t1 = Clock::now();

if (heuristicMapping) {
cout << "[heuristic]\n";
II = mapper->heuristicMap(cgra, dfg, II, isStaticElasticCGRA);
if(incrementalMapping){
II = mapper->incrementalMap(cgra, dfg, II);
cout << "[Incremental]\n";
}
else{
cout << "[heuristic]\n";
II = mapper->heuristicMap(cgra, dfg, II, isStaticElasticCGRA);
}
} else {
cout << "[exhaustive]\n";
II = mapper->exhaustiveMap(cgra, dfg, II, isStaticElasticCGRA);
}

auto t2 = Clock::now();
int elapsedTime = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count() / 1000000;
std::cout <<"Mapping algorithm elapsed time="<<elapsedTime <<"ms"<< '\n';
}

// Partially exhaustive search to try to map the DFG onto
Expand All @@ -238,7 +255,13 @@ namespace {
cout << "[Mapping Success]\n";
cout << "==================================\n";
mapper->generateJSON(cgra, dfg, II, isStaticElasticCGRA);
cout << "[Output Json]\n";
cout << "[Output Json]\n";

// save mapping results json file for possible incremental mapping
if(!incrementalMapping) {
mapper->generateJSON4IncrementalMap(cgra, dfg);
cout << "[Output Json for Incremental Mapping]\n";
}
}
cout << "=================================="<<endl;

Expand Down
Loading

0 comments on commit e76bf4e

Please sign in to comment.