引出问题
以Net为节点,Gate为边构建超图。超图格式:
355 396
25 145 29
32 27
32 267
32 266
32 269
101 302 36 316
265 178 316 260 43
44 43
32 257
网表文件格式:
INV_X1B_A12PP140ZTR_C30 U441 (.A(n442),
.Y(n240));
AOI22_X1M_A12PP140ZTR_C30 U442 (.A0(n486),
.A1(n374),
.B0(n373),
.B1(n478),
.Y(n384));
连接关系:Gate有若干pin,pin上连接net。
解决问题
1、转换:需要将字符串name转换为序号,并有map数据结构存储。【name, 序号】、【序号、name】。
2、输出超图文件:遍历每个gate,将其关联的net输出,注意:有些pin上可能没有线网、有些pin上可能是port。
3、对超图文件进行切割:利用hmetis对生成的超图文件进行切割。
4、读取划分结果:划分成功后,可以将net cluster ID 注入net。
统一将net是reset的去掉
转换
数据结构
std::unordered_map<std::string, int> _net_name_indexs; //net:(name,index)
std::unordered_map<int, std::string> _net_index_names; //net:(index,name)
在得到线网的编号之前,为了让每个线网有固定的一个编号。
先按照绝对顺序输出线网 dump_net_sort
void Timer::_dump_net_sort(std::ostream &os) const
{
for (const auto &[net_name, net] : _nets)
{
//去除包含ports以及Q、reset的线网
if (net_name != "reset")
os << net_name << "\n";
}
}
得到的结果如下:
读入绝对排序文件后,之后进行编号。存放在_net_name_indexs、_net_index_names中。可以通过name查到index,也可以通过index查到name。
index 从1开始编号, 同样对于切割的结果也是按照1开始编号。
void Timer::read_net_sort(std::filesystem::path path)
{
std::shared_lock lock(_mutex);
std::ifstream ifs(path);
assert(ifs.good());
std::string netname;
int index = 1; //start from 1 net index
while (getline(ifs, netname))
{
//std::cout << gatename << endl;
_net_name_indexs[netname] = index;
_net_index_names[index] = netname;
index++;
}
ifs.close();
}
输出超图文件
//输出超图 以net作为节点
void Timer::_dump_hypergraph_net(std::ostream &os)
{
std::string net_name; //存放net_name
std::string buffer; //输出点s的buffer,之后文件一块输出
int edge_size = 0; //超边数量(符号要求的gates数量)
std::unordered_set<std::string> uset; // set,记录所有筛掉后(>=2)超边(gate)所连的net(node)
//遍历gate(超边),将gate所连的net(节点)输出
for (const auto &[gate_name, gate] : _gates)
{
int tmp_nodes = 0; //临时存放节点(net)数
std::string tmp_str; //临时存放输出内容:点s(index)
std::vector<std::string> tmp_vec; //临时存放点信息(net name)
//遍历所有的pin,以及pin所关联的net
for (const auto &pin : gate._pins)
{
auto net = pin->_net; // pin所连的net
// assert(net != nullptr);
// net is normal
if (net != nullptr && net->_name!="reset")
{
net_name = net->_name;
int index = _net_name_indexs[net_name];
tmp_str += to_string(index) + " ";
tmp_vec.push_back(net_name);
tmp_nodes++;
}
}
// gate(超边)所连接的net(节点)必须大于等于两个,此超边才有效
if (tmp_nodes >= 2)
{
buffer += tmp_str + "\n";
edge_size++;
for (auto node : tmp_vec)
{
//将点(net)加入set中
uset.emplace(node);
}
}
}
//遍历gates所得到的点(net)总数量 <= net 总数量
assert(uset.size() <= _net_name_indexs.size());
//输出超边数量 ,节点数量
os << edge_size << " " << _net_name_indexs.size() << "\n";
//输出超边所连接的所有net(点)信息(index start from 0)
os << buffer;
}
切割
使用Hmetis提供的各种可执行包。
下一节将如何切割。
读取划分结果
使用_net_index_parts存放netindex 和 Cluster ID.这种可以index找到name。
//读取net的划分结果
void Timer::read_net_part(std::filesystem::path path)
{
std::shared_lock lock(_mutex);
std::cout << path.c_str() << std::endl;
std::string path_res = ot::getPartFileName(path.c_str());
std::cout << path_res << std::endl;
std::ifstream ifs(path_res);
assert(ifs.good());
std::string partid;
int index = 1; //start from 1 net index
while (getline(ifs, partid))
{
//std::cout << _net_index_names[index] << "---------" << partid << endl;
_net_index_parts[index++] = atoi(partid.c_str());
}
ifs.close();
}
其中,文件处理函数如下:
#include <ot/utility/files.hpp>
namespace ot
{
void getFiles(std::string path, std::vector<std::string> &files)
{
DIR *dir;
struct dirent *ptr;
if ((dir = opendir(path.c_str())) == NULL)
{
perror("Open dir error...");
return;
}
while ((ptr = readdir(dir)) != NULL)
{
if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) ///current dir OR parrent dir
continue;
else if (ptr->d_type == 8) ///file
{
std::string strFile;
strFile = path;
strFile += "/";
strFile += ptr->d_name;
files.push_back(strFile);
}
else
{
continue;
}
}
closedir(dir);
}
/*
输入: path: ./partition/hypergraph_gate_100/
part_file: b14_0_mode_0.part
输出: partition/hypergraph_gate_100/b14_0_mode_0.part.30
*/
std::string getPartFileName(std::string path, std::string part_file)
{
std::vector<std::string> files;
std::cout << "path: " << path << std::endl;
getFiles(path, files);
std::string out_file = path;
for (auto file : files)
{
//std::cout << "file: " << file << "part_file: " << part_file << std::endl;
if (file.find(part_file) != std::string::npos)
{
out_file = file;
}
}
assert(out_file != path);
std::cout << "out_file" << out_file << std::endl;
return out_file;
}
//字符串分割函数
std::vector<std::string> split(std::string str, std::string pattern)
{
std::string::size_type pos;
std::vector<std::string> result;
str += pattern; //扩展字符串以方便操作
int size = str.size();
for (int i = 0; i < size; i++)
{
pos = str.find(pattern, i);
if (pos < size)
{
std::string s = str.substr(i, pos - i);
result.push_back(s);
i = pos + pattern.size() - 1;
}
}
return result;
}
/*
输入: ./partition/hypergraph_gate_100/b14_0_mode_0.part
输出:./partition/hypergraph_gate_100/b14_0_mode_0.part.30
*/
std::string getPartFileName(std::string path_origin)
{
std::vector<std::string> res = split(path_origin, "/");
//. partition hypergraph_gate_100 b14_0_mode_0.part
std::string path_res;
for (int i = 0; i < res.size() - 2; i++)
{
path_res += res[i] + "/";
//输出: ./partition/hypergraph_gate_100
}
path_res += res[res.size() - 2];
//输出: b14_0_mode_0.part
std::string part_file = res[res.size() - 1];
//输出: ./partition/hypergraph_gate_100/b14_0_mode_0.part.30
return getPartFileName(path_res, part_file);
}
}
批量处理
1、绝对排序
bin文件生成cpp源文件
/**
* @file debug_dump_net_sort.cpp
* @author your name (you@domain.com)
* @brief dump absolutly sorted net for hypergraph cutting.
* @version 0.1
* @date 2022-05-16
*
* @copyright Copyright (c) 2022
*
*/
#include <ot/timer/timer.hpp>
int main(int argc, char *argv[])
{
ot::Timer timer;
if (argc == 2)
{
std::string filename = argv[1];
std::string netlist = "data/netlist/" + filename;
std::string sdc = "data/sdc/" + filename.substr(0, 3) + "/" + filename.substr(0, 3) + "_0_pr.sdc";
std::string placename = filename.substr(0, 6) + filename.substr(9, 6);
std::string spef = "data/generator_spef/" + filename.substr(0, filename.size() - 2) + ".spef";
timer.read_celllib("data/celllib", ot::MIN)
.read_celllib("data/celllib", ot::MAX)
.read_verilog(netlist)
.read_place(placename)
.read_sdc(sdc)
.read_spef(spef);
timer.update_timing();
std::string debug = "result/net_sort/" + placename;
if (std::ofstream ofs(debug); ofs)
{
timer.dump_net_sort(ofs);
ofs.close();
}
}
return 0;
}
对线网进行批量绝对排序,shell脚本执行bin,遍历文件。
#!/bin/bash
echo "data/netlist2"
if [ -r data/netlist2 ]
then
for file in `ls data/netlist2`
do
if [ `expr index "$file" S` == 0 ]
then
echo ${file}
bin/debug_dump_net_sort ${file}
fi
done fi
输出批量 result/net_sort如下:
2、输出超图文件
bin文件生成cpp源文件,读入绝对排序文件。
/**
* @file debug_dump_net_hypergraph.cpp
* @author zhengtao,jiang (2876253980@qq.com)
* @brief generate hypergraph based on net.
* @version 0.1
* @date 2022-05-16
*
* @copyright Copyright (c) 2022
*
*/
#include <ot/timer/timer.hpp>
int main(int argc, char *argv[])
{
// create a timer object
ot::Timer timer;
if (argc == 2)
{
std::string filename = argv[1];
std::string netlist = "data/netlist/" + filename;
std::string sdc = "data/sdc/" + filename.substr(0, 3) + "/" + filename.substr(0, 3) + "_0_pr.sdc";
std::string placename = filename.substr(0, 6) + filename.substr(9, 6);
std::string spef = "data/generator_spef/" + filename.substr(0, filename.size() - 2) + ".spef";
// std::cout << netlist << " " << sdc << std::endl;
// Read design
timer.read_celllib("data/celllib", ot::MIN)
.read_celllib("data/celllib", ot::MAX)
.read_verilog(netlist)
.read_place(placename)
.read_sdc(sdc)
.read_spef(spef);
timer.update_timing();
timer.read_net_sort("result/net_sort/" + placename);//读入绝对排序文件,生成map:name和index的映射文件
// dump the timing graph to dot format for debugging
// timer.dump_graph(std::cout);
std::string debug = "result/net_hypergraph/" + placename;
if (std::ofstream ofs(debug); ofs)
{
timer.dump_hypergraph_net(ofs);
ofs.close();
}
}
return 0;
}
shell脚本执行bin,遍历文件。
#!/bin/bash
echo "data/netlist2"
if [ -r data/netlist2 ]
then
for file in `ls data/netlist2`
do
if [ `expr index "$file" S` == 0 ]
then
echo ${file}
bin/debug_dump_net_hypergraph ${file}
fi
done fi