fix libtorch/python floating-point arith difference

This commit is contained in:
liulixinkerry 2024-04-29 11:20:08 +08:00
parent 50897f14dc
commit 46ab26791a
8 changed files with 196 additions and 101 deletions

View File

@ -226,24 +226,19 @@ bool overlapCheck(const float* x,
// This will cause failure to detect some overlaps.
// We need to remove the "small" fixed cell that is inside another.
if (!nodes_in_row.empty()) {
std::vector<int> tmp_nodes;
tmp_nodes.reserve(nodes_in_row.size());
tmp_nodes.push_back(nodes_in_row.front());
for (int j = 1, je = nodes_in_row.size(); j < je; ++j) {
for (int j = 1; j < nodes_in_row.size(); ++j) {
int node_id1 = nodes_in_row.at(j - 1);
int node_id2 = nodes_in_row.at(j);
// two fixed cells
if (node_id1 >= num_movable_nodes && node_id2 >= num_movable_nodes) {
float xh1 = getXH(node_id1);
float xh2 = getXH(node_id2);
if (xh1 < xh2) {
tmp_nodes.push_back(node_id2);
}
} else {
tmp_nodes.push_back(node_id2);
if (xh1 >= xh2 && !nodes_in_row.empty()) {
nodes_in_row.erase(nodes_in_row.begin() + j);
--j;
}
}
}
nodes_in_row.swap(tmp_nodes);
}
}

View File

@ -94,21 +94,22 @@ bool DPTorchRawDB::check(float scale_factor) {
}
void DPTorchRawDB::scale(float scale_factor, bool use_round) {
torch::Tensor scalar_at = torch::tensor({scale_factor}, torch::dtype(torch::kFloat32).device(node_size.device()));
if (use_round) {
pin_rel_lpos.mul_(scale_factor);
node_size.mul_(scale_factor).round_();
node_lpos_init.mul_(scale_factor).round_();
pin_rel_lpos.mul_(scalar_at);
node_size.mul_(scalar_at).round_();
node_lpos_init.mul_(scalar_at).round_();
node_size_x.mul_(scale_factor).round_();
node_size_y.mul_(scale_factor).round_();
init_x.mul_(scale_factor).round_();
init_y.mul_(scale_factor).round_();
pin_offset_x.mul_(scale_factor).round_();
pin_offset_y.mul_(scale_factor).round_();
x.mul_(scale_factor).round_();
y.mul_(scale_factor).round_();
node_size_x.mul_(scalar_at).round_();
node_size_y.mul_(scalar_at).round_();
init_x.mul_(scalar_at).round_();
init_y.mul_(scalar_at).round_();
pin_offset_x.mul_(scalar_at).round_();
pin_offset_y.mul_(scalar_at).round_();
x.mul_(scalar_at).round_();
y.mul_(scalar_at).round_();
flat_region_boxes.mul_(scale_factor).round_();
flat_region_boxes.mul_(scalar_at).round_();
site_width = round(site_width * scale_factor);
row_height = round(row_height * scale_factor);
xl = round(xl * scale_factor);
@ -117,20 +118,23 @@ void DPTorchRawDB::scale(float scale_factor, bool use_round) {
yh = round(yh * scale_factor);
} else {
float inv_scale_factor = std::round(1.0 / scale_factor);
pin_rel_lpos.div_(inv_scale_factor);
node_size.div_(inv_scale_factor);
node_lpos_init.div_(inv_scale_factor);
torch::Tensor inv_scalar_at =
torch::tensor({inv_scale_factor}, torch::dtype(torch::kFloat32).device(node_size.device()));
node_size_x.div_(inv_scale_factor);
node_size_y.div_(inv_scale_factor);
init_x.div_(inv_scale_factor);
init_y.div_(inv_scale_factor);
pin_offset_x.div_(inv_scale_factor);
pin_offset_y.div_(inv_scale_factor);
x.div_(inv_scale_factor);
y.div_(inv_scale_factor);
pin_rel_lpos.div_(inv_scalar_at);
node_size.div_(inv_scalar_at);
node_lpos_init.div_(inv_scalar_at);
flat_region_boxes.div_(inv_scale_factor);
node_size_x.div_(inv_scalar_at);
node_size_y.div_(inv_scalar_at);
init_x.div_(inv_scalar_at);
init_y.div_(inv_scalar_at);
pin_offset_x.div_(inv_scalar_at);
pin_offset_y.div_(inv_scalar_at);
x.div_(inv_scalar_at);
y.div_(inv_scalar_at);
flat_region_boxes.div_(inv_scalar_at);
site_width = site_width / inv_scale_factor;
row_height = row_height / inv_scale_factor;
xl = xl / inv_scale_factor;

View File

@ -274,12 +274,60 @@ public:
return legal_flag;
}
std::vector<std::vector<int>> reorder_row_map(
const float* host_x, const float* host_y, const float* host_node_size_x, const float* host_node_size_y, std::vector<std::vector<int>>& row2node_map, int sort_coord) {
if (sort_coord < 0 || sort_coord > 2) sort_coord = 0;
std::vector<std::vector<int>> row2node_map_helper;
// copy row2node_map to row2node_map_helper
row2node_map_helper.resize(row2node_map.size());
for (int i = 0; i < row2node_map.size(); ++i) {
row2node_map_helper[i] = row2node_map[i];
}
// sort according to right
for (int i = 0; i < row2node_map.size(); ++i) {
auto& row2nodes = row2node_map_helper[i];
if (!row2nodes.empty()) {
switch (sort_coord) {
case 0: // center
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
float x1 = host_x[node_id1] + host_node_size_x[node_id1] / 2;
float x2 = host_x[node_id2] + host_node_size_x[node_id2] / 2;
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
break;
case 1: // left
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
float x1 = host_x[node_id1];
float x2 = host_x[node_id2];
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
break;
case 2: // right
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
float x1 = host_x[node_id1] + host_node_size_x[node_id1];
float x2 = host_x[node_id2] + host_node_size_x[node_id2];
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
break;
default:
break;
}
}
}
return row2node_map_helper;
}
void make_row2node_map(const float* host_x,
const float* host_y,
const float* host_node_size_x,
const float* host_node_size_y,
int host_num_nodes,
std::vector<std::vector<int>>& row2node_map) {
std::vector<std::vector<int>>& row2node_map,
int sort_coord = 0) {
if (sort_coord < 0 || sort_coord > 2) sort_coord = 0;
// distribute cells to rows
for (int i = 0; i < host_num_nodes; ++i) {
float node_yl = host_y[i];
@ -312,10 +360,7 @@ public:
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
if (!row2nodes.empty()) {
std::vector<int> tmp_nodes;
tmp_nodes.reserve(row2nodes.size());
tmp_nodes.push_back(row2nodes.front());
for (int j = 1, je = row2nodes.size(); j < je; ++j) {
for (int j = 1; j < row2nodes.size(); ++j) {
int node_id1 = row2nodes.at(j - 1);
int node_id2 = row2nodes.at(j);
// two fixed cells
@ -327,21 +372,39 @@ public:
float xh1 = xl1 + width1;
float xh2 = xl2 + width2;
// only collect node_id2 if its right edge is righter than node_id1
if (xh1 < xh2) {
tmp_nodes.push_back(node_id2);
}
} else {
tmp_nodes.push_back(node_id2);
if (xh1 >= xh2 && !row2nodes.empty()) {
row2nodes.erase(row2nodes.begin() + j);
--j;
}
}
}
row2nodes.swap(tmp_nodes);
// sort according to center
switch (sort_coord) {
case 0: // center
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
float x1 = host_x[node_id1] + host_node_size_x[node_id1] / 2;
float x2 = host_x[node_id2] + host_node_size_x[node_id2] / 2;
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
break;
case 1: // left
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
float x1 = host_x[node_id1];
float x2 = host_x[node_id2];
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
break;
case 2: // right
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
float x1 = host_x[node_id1] + host_node_size_x[node_id1];
float x2 = host_x[node_id2] + host_node_size_x[node_id2];
return x1 < x2 || (x1 == x2 && node_id1 < node_id2);
});
break;
default:
break;
}
}
}
}
@ -352,8 +415,12 @@ public:
const float* host_node_size_y,
std::vector<std::vector<int>>& row2node_map,
std::vector<RowMapIndex>& node2row_map,
std::vector<Space<float>>& spaces) {
make_row2node_map(host_x, host_y, host_node_size_x, host_node_size_y, num_nodes + 2, row2node_map);
std::vector<Space<float>>& spaces,
int sort_coord = 0) {
make_row2node_map(host_x, host_y, host_node_size_x, host_node_size_y, num_nodes + 2, row2node_map, sort_coord);
// copy row2node_map to row2node_map_helper
std::vector<std::vector<int>> row2node_map_helper = reorder_row_map(host_x, host_y, host_node_size_x, host_node_size_y, row2node_map, sort_coord);
// construct node2row_map
for (int i = 0; i < num_sites_y; ++i) {
@ -373,7 +440,10 @@ public:
int node_id = row2node_map[i][j];
if (node_id < num_movable_nodes) {
assert(j);
int left_node_id = row2node_map[i][j - 1];
// int left_node_id = row2node_map[i][j - 1];
int j_helper = std::find(row2node_map_helper[i].begin(), row2node_map_helper[i].end(), node_id) - row2node_map_helper[i].begin();
int left_node_id = row2node_map[i][j_helper - 1];
spaces[node_id].xl = host_x[left_node_id] + host_node_size_x[left_node_id];
assert(j + 1 < row2node_map[i].size());
int right_node_id = row2node_map[i][j + 1];

View File

@ -911,7 +911,8 @@ void globalSwapCUDA(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y, int bat
host_node_size_y.data(),
host_row2node_map,
host_node2row_map,
host_spaces);
host_spaces,
1);
// distribute movable cells to bins on host, bin map is column-major
std::vector<std::vector<int>> host_bin2node_map(db.num_bins_x * db.num_bins_y);
std::vector<BinMapIndex> host_node2bin_map(db.num_movable_nodes);

View File

@ -244,10 +244,7 @@ void make_row2node_map(const DetailedPlaceDBType& db,
// This will cause failure to detect some overlaps.
// We need to remove the "small" fixed cell that is inside another.
if (!row2nodes.empty()) {
std::vector<int> tmp_nodes;
tmp_nodes.reserve(row2nodes.size());
tmp_nodes.push_back(row2nodes.front());
for (int j = 1, je = row2nodes.size(); j < je; ++j) {
for (int j = 1; j < row2nodes.size(); ++j) {
int node_id1 = row2nodes.at(j - 1);
int node_id2 = row2nodes.at(j);
// two fixed cells
@ -259,14 +256,12 @@ void make_row2node_map(const DetailedPlaceDBType& db,
typename DetailedPlaceDBType::type xh1 = xl1 + width1;
typename DetailedPlaceDBType::type xh2 = xl2 + width2;
// only collect node_id2 if its right edge is righter than node_id1
if (xh1 < xh2) {
tmp_nodes.push_back(node_id2);
}
} else {
tmp_nodes.push_back(node_id2);
if (xh1 >= xh2 && !row2nodes.empty()) {
row2nodes.erase(row2nodes.begin() + j);
--j;
}
}
}
row2nodes.swap(tmp_nodes);
// sort according to center
std::sort(row2nodes.begin(), row2nodes.end(), [&](int node_id1, int node_id2) {
@ -982,16 +977,17 @@ void kReorderCUDA(DPTorchRawDB& at_db, int num_bins_x, int num_bins_y, int K, in
allocateCopyCpu(cpu_db.node_size_y, db.node_size_y, db.num_nodes, T);
make_row2node_map(cpu_db, cpu_db.x, cpu_db.y, host_row2node_map, db.num_threads);
std::vector<std::vector<int>> host_row2node_map_left = db.reorder_row_map(cpu_db.x, cpu_db.y, cpu_db.node_size_x, cpu_db.node_size_y, host_row2node_map, 1);
host_node_space_x.resize(cpu_db.num_movable_nodes);
for (int i = 0; i < cpu_db.num_sites_y; ++i) {
for (unsigned int j = 0; j < host_row2node_map.at(i).size(); ++j) {
int node_id = host_row2node_map[i][j];
for (unsigned int j = 0; j < host_row2node_map_left.at(i).size(); ++j) {
int node_id = host_row2node_map_left[i][j];
if (node_id < db.num_movable_nodes) {
auto& space = host_node_space_x[node_id];
T space_xl = cpu_db.x[node_id];
T space_xh = cpu_db.xh;
if (j + 1 < host_row2node_map[i].size()) {
int right_node_id = host_row2node_map[i][j + 1];
if (j + 1 < host_row2node_map_left[i].size()) {
int right_node_id = host_row2node_map_left[i][j + 1];
space_xh = min(space_xh, cpu_db.x[right_node_id]);
}
space = space_xh - space_xl;

View File

@ -145,12 +145,18 @@ void distributeBlanks2Bins(const float* x,
bin_blanks.at(blank_bin_id).push_back(blank);
}
}
}
for (int i = 0; i < num_bins_x * num_bins_y; i += 1) {
int bin_id_x = i / num_bins_y;
int bin_id_y = i - bin_id_x * num_bins_y;
int blank_num_bins_per_bin = roundDiv(bin_size_y, blank_bin_size_y);
int blank_bin_id_yl = bin_id_y * blank_num_bins_per_bin;
int blank_bin_id_yh = std::min(blank_bin_id_yl + blank_num_bins_per_bin, blank_num_bins_y);
const std::vector<int>& cells = bin_fixed_cells.at(i);
std::vector<Blank<float>>& blanks = bin_blanks.at(blank_bin_id);
for (unsigned int bi = 0; bi < blanks.size(); ++bi) {
Blank<float>& blank = blanks.at(bi);
for (unsigned int ci = 0; ci < cells.size(); ++ci) {
int node_id = cells.at(ci);
float node_xl = x[node_id];
@ -158,14 +164,26 @@ void distributeBlanks2Bins(const float* x,
float node_xh = node_xl + node_size_x[node_id];
float node_yh = node_yl + node_size_y[node_id];
if (node_yh > blank.yl && node_yl < blank.yh && node_xh > blank.xl &&
node_xl < blank.xh) // overlap
{
// int node_2_blank_bin_id_yl = std::max(floorDiv((node_yl - yl), blank_bin_size_y), blank_bin_id_yl);
// int node_2_blank_bin_id_yh = std::min(ceilDiv((node_yh - yl), blank_bin_size_y), blank_bin_id_yh);
int node_2_blank_bin_id_yl = std::max((node_yl - yl) / blank_bin_size_y, (float)blank_bin_id_yl);
int node_2_blank_bin_id_yh = std::min((int)ceil((node_yh - yl) / blank_bin_size_y), blank_bin_id_yh);
for (int blank_bin_id_y = node_2_blank_bin_id_yl; blank_bin_id_y < node_2_blank_bin_id_yh; ++blank_bin_id_y) {
int blank_bin_id = bin_id_x * blank_num_bins_y + blank_bin_id_y;
std::vector<Blank<float>>& blanks = bin_blanks.at(blank_bin_id);
for (unsigned int bi = 0; bi < blanks.size(); ++bi) {
Blank<float>& blank = blanks.at(bi);
if (blank.xh <= node_xl) continue;
if (blank.xl >= node_xh) break;
if (node_xl <= blank.xl && node_xh >= blank.xh) // erase
{
bin_blanks.at(blank_bin_id).erase(bin_blanks.at(blank_bin_id).begin() + bi);
--bi;
break;
} else if (node_xl <= blank.xl) { // one blank
blank.xl = ceilDiv((node_xh - xl), site_width) * site_width + xl; // align blanks to sites
} else if (node_xh >= blank.xh) { // one blank
@ -177,8 +195,6 @@ void distributeBlanks2Bins(const float* x,
floorDiv((node_xh - xl), site_width) * site_width + xl; // align blanks to sites
bin_blanks.at(blank_bin_id).insert(bin_blanks.at(blank_bin_id).begin() + bi + 1, new_blank);
--bi;
break;
}
}
}
}

View File

@ -50,6 +50,7 @@ def get_option():
parser.add_argument('--visualize_cgmap', type=str2bool, default=False, help='visualize congestion map')
# detailed placement and evaluation
parser.add_argument('--legalization', type=str2bool, default=True, help='perform lg')
parser.add_argument('--detail_placement', type=str2bool, default=True, help='perform dp')
parser.add_argument('--dp_engine', type=str, default="default", help='choose dp engine')
parser.add_argument('--eval_by_external', type=str2bool, default=False, help='eval dp sol by external binary')

View File

@ -155,7 +155,11 @@ def setup_detailed_rawdb(
# NOTE: we assume all legalized cells are on integer system
# this step can avoid some potential floating-point precision errors
_, floatmov_rhs, _ = data.node_type_indices[1]
inv_scalar = round(1.0 / get_ori_scale_factor(data))
inv_scalar = torch.tensor(
[round(1.0 / get_ori_scale_factor(data))],
dtype=torch.float32,
device=node_lpos.device
)
node_lpos[:floatmov_rhs].mul_(inv_scalar).round_().div_(inv_scalar)
mov_lhs, mov_rhs = data.movable_index
@ -466,7 +470,11 @@ def run_dp_route_opt(node_pos: torch.Tensor, gpdb, rawdb, ps, data: PlaceData, a
), dim=0).cpu()
# this step can avoid some potential floating-point precision errors
_, floatmov_rhs, _ = data.node_type_indices[1]
inv_scalar = round(1.0 / get_ori_scale_factor(data))
inv_scalar = torch.tensor(
[round(1.0 / get_ori_scale_factor(data))],
dtype=torch.float32,
device=node_lpos.device
)
node_lpos[:floatmov_rhs].mul_(inv_scalar).round_().div_(inv_scalar)
node_size = data.node_size.cpu()
@ -626,7 +634,8 @@ def external_detail_placement(input_file, data: PlaceData, args, logger, eval_mo
logger.info("Write detail placement in %s" % dp_out_file)
# del gpdb, rawdb
# logger.info("Evaluating detail placement result...")
# data, rawdb, gpdb = load_dataset(args, logger, dp_out_file)
# params = find_design_params(args, logger, dp_out_file)
# data, rawdb, gpdb = load_dataset(args, logger, params)
# data = data.to(device).preprocess()
# hpwl = get_obj_hpwl(data.node_pos, data, args).item()
# info = (iteration + 1, hpwl, data.design_name)
@ -645,9 +654,11 @@ def default_detail_placement(node_pos, gpdb, rawdb, ps, data: PlaceData, args, l
torch.cuda.synchronize(node_pos.device)
dp_start_time = time.time()
if args.legalization:
node_pos = run_lg(node_pos, data, args, logger)
torch.cuda.synchronize(node_pos.device)
lg_end_time = time.time()
if args.detail_placement:
node_pos = run_dp(node_pos, data, args, logger)
torch.cuda.synchronize(node_pos.device)
node_pos = run_dp_route_opt(node_pos, gpdb, rawdb, ps, data, args, logger)
@ -687,8 +698,9 @@ def detail_placement_main(node_pos, gpdb, rawdb, ps, data: PlaceData, args, logg
gp_out_file = gp_prefix + post_fix
args.write_global_placement = False # we won't write GP solution anymore
args.detail_placement = False if args.legalization is False else args.detail_placement
if args.detail_placement:
if args.detail_placement or args.legalization:
logger.info("------- Start DP -------")
if args.dp_engine in ["ntuplace3", "ntuplace4dr", "rippledp"]:
# use external engine to perform lg/dp and write solution