Hmetis图分割处理网表-数据预处理

引出问题

以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

遗留问题

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涛歌依旧fly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值