-
Notifications
You must be signed in to change notification settings - Fork 10
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
Add the incremental mapping function, which re-utilizes the previous mapping results to acceleterate ccurrent mapping. #24
Changes from 9 commits
640ed34
10aa217
b9b4a10
f9b5c84
328427a
00d2658
c3c284c
8365910
8ec0b09
ea76c04
d00acdd
d9d99b1
c9cc6d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -579,3 +579,7 @@ void CGRANode::disableAllFUs() { | |
m_supportComplex = false; | ||
m_supportVectorization = false; | ||
} | ||
|
||
bool CGRANode::isDisabled() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So now,
Correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the confirmation, plz summarize above two cases and put the summary as comment above the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think about it again, if CGRANode5 is allocated to |
||
return m_disabled; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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()); | ||
|
@@ -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); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -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 = "[ ]"; | ||
} | ||
|
@@ -1346,3 +1346,206 @@ map<int, CGRANode*>* Mapper::getReorderPath(map<CGRANode*, int>* t_path) { | |
return reorderPath; | ||
} | ||
|
||
// Saves the mapping results to json file for subsequent incremental mapping | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Period at the end, thanks! Same to the others. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry what do you mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Has fixed all similar issues |
||
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 | ||
jsonFile<<" \""<<dfgNode->getID()<<"\": {"<<endl; // opt id | ||
jsonFile<<" \"x\":"<<m_mapping[dfgNode]->getX()<<","<<endl; // opt mapped tile x coordinate | ||
jsonFile<<" \"y\":"<<m_mapping[dfgNode]->getY()<<endl; // opt mapped tile y coordinate | ||
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 | ||
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]; | ||
if (currentCGRANode->getInLinks() == 0) continue; // Only records tiles that have DFGNodes mapped | ||
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++; | ||
} | ||
} | ||
std::sort(FanIOs.rbegin(), FanIOs.rend()); // Sorts FanIOs from big to small | ||
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]; | ||
if (currentCGRANode->isDisabled()) continue; // only record tiles that have DFGNodes mapped | ||
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++; | ||
} | ||
} | ||
std::sort(FanIOs.rbegin(), FanIOs.rend()); // Sorts FanIOs from big to small to automatically form the level | ||
|
||
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: RPT & MBO | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate on these two principles? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reference Placement Tendency (RPT): if DFGNode0 is mapped on CGRANode5 in the referenced mapping results, we believe it should have the tendency to be mapped on the CGRANode that has the same or the closest FanIO with CGRANode5, so that we don't need to iteratively call calcaulateCost() like in heuristicMapper(), which saves lots of time and therefore accelerating the mapping. Minimize Bypass Operations (MBO): Bypass operations occupy the CGRALink resources and may lead to the decrease of mapping quality. Therefore, on the basis of RPT, we further calculate the number of bypass operations for each CGRANode candidate required to communicate with its predecessors, and the CGRANode with fewer bypass operations has the higher priority to be mapped. An example There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, super clear! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plz just provide the full name for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Has been corrected |
||
list<CGRANode*> Mapper::placementGen(CGRA* t_cgra, DFGNode* t_dfgNode){ | ||
list<CGRANode*> placementRecommList; | ||
CGRANode* refCGRANode = refMapRes[t_dfgNode]; | ||
list<DFGNode*>* predNodes = t_dfgNode->getPredNodes(); | ||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If BTW, can we replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah these two variables are easily confused, I use the following examples to explain the difference: map<int, vector<CGRANode*>> FanIO_CGRANodes = { For an athelete in a championship, I thought There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good, i am okay with FanIO. Can you rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Larger FanIO not always has higher priority, for example in the referenced mapping results, So when incrementalMap() choose which CGRANodes within the new resource allocation decision have highest priority for So sorry I still think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How could there exist There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plz add comment "The |
||
while (true) { | ||
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) { | ||
level = 0; // Goes back to the highest level | ||
} | ||
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) { | ||
cout<<"[DEBUG] no available path for DFG node "<<(*dfgNode)->getID()<<" on CGRA node "<<fu->getID()<<" within II "<<t_II<<endl; | ||
continue; // Switches to next tile in placementRecommList | ||
} | ||
else { | ||
if (schedule(t_cgra, t_dfg, t_II, *dfgNode, path, false)) { | ||
dfgNodeMapFailed = false; | ||
break; // Current DFGNode finishes mapping, move to next DFGNode | ||
} | ||
else { | ||
cout<<"[DEBUG] no available path to schedule DFG node "<<(*dfgNode)->getID()<<" on CGRA node "<<fu->getID()<<" within II "<<t_II<<endl; | ||
continue; // Switches to next tile in placementRecommList | ||
} | ||
} | ||
} | ||
if (dfgNodeMapFailed) break; // Current DFGNode fails mapping, increase II and restart | ||
} | ||
|
||
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; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,9 @@ 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>*>*); | ||
map<DFGNode*, CGRANode*> refMapRes; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Plz comment on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When I say There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then plz add the comments above it. |
||
map<int, int> CGRANodeID2Level; | ||
vector<vector<CGRANode*>> CGRANodes_sortedByLevel; | ||
|
||
public: | ||
Mapper(){} | ||
|
@@ -40,4 +43,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); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
"additionalFunc" : { | ||
"load" : [4], | ||
"store": [4] | ||
} | ||
}, | ||
"incrementalMapping" : false | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering why we need to let the user perform the two-step experiment. Why cannot just set this to true, and it will automatically perform heuristic/exhaustive first, then, based on the generated .json and perform the incremental mapping?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imagine a situation that we firstly map the KERNEL1 with 200 DFGNodes on 400 CGRANodes, and the heuristic mapper takes 1 hour to finish this.
Then let's say KERNEL2 takes 10 of 400 CGRANodes from KERNEL1, normally we need to re-map KERNEL1 on the rest of 390 CGRANodes from the scratch, which will cost us 1 hour again. This is the time when we need the incremental mapping, we can simply set the incrementalMapping to true, then the mapping can finish within several minutes.
But for small DFG mapping on small CGRAs, the heuristic mapper has already been fast enough and we seem do not need incremental mapping to further accelerate the mapping, so that's why I set incrementalMapping default to false.
(I have not really tested the incremental mapping on large DFG and large CGRA, It will definitely bring significant mapping acceleration, but may require additional tricks to ensure mapping quality. Anyway, I think incremental mapping might be an interesting idea in CGRA just like it in FPGA)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation. Does it mean:
KERNEL1
) as those nodes are occupied byKERNEL2
?KERNEL1
's mapping? So we have tore-map
? How is this case handled?IncrementalMapping
needs to check whether theincreMapInput.json
exists in the folder?KERNEL1
, instead of some random kernels?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
param.json
forKernel1
adnKernel2
, just like the DRIPS controller.re-map
, just like in Vivado.IncrementalMapping
should check whetherincreMapInput.json
is corresponding toKernel1
, which can be achieved by comparing some fields in.json
likeKernelID
. Or if developers use CGRA-Flow, we can simply add a message box and let them choose the correct.json
.Current merge request is just a initial version of incremental mapping, and I know there are lots of functions are incomplete, but I’m happy to complement all the related functions in the future and hope they actually contributes to the CGRA development rather than just some academic ideas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But for now, if I want to use this feature, I need manually disable some tiles (before invoking the incremental mapping) to see its effect, right?
Can you please provide the description about the constraint (users need to guarantee that
increMapInput.json
exists and theincrementalMapping
can only work on the same kernel (and users need to manually disable some tiles?).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the updated README.md