Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/gpl/include/gpl/Replace.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct PlaceOptions
bool uniformTargetDensityMode = false;
std::vector<int> timingNetWeightOverflows{64, 20};
float timingNetWeightMax = 5;
bool timingNetWeightMaxUserSet = false;
float overflow = 0.1;
int nesterovPlaceMaxIter = 5000;
// timing driven check overflow to keep resizer changes (non-virtual resizer)
Expand Down
19 changes: 17 additions & 2 deletions src/gpl/src/replace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
#include "gpl/Replace.h"

#include <algorithm>
#include <cctype>
#include <chrono>
#include <cstdlib>
#include <memory>
#include <optional>
#include <string>
#include <utility>

Expand All @@ -22,8 +25,8 @@
#include "placerBase.h"
#include "routeBase.h"
#include "rsz/Resizer.hh"
#include "sta/StaMain.hh"
#include "timingBase.h"
#include "utl/Environment.h"
#include "utl/Logger.h"
#include "utl/validation.h"

Expand Down Expand Up @@ -258,7 +261,19 @@ bool Replace::initNesterovPlace(const PlaceOptions& options, const int threads)
if (!tb_) {
tb_ = std::make_shared<TimingBase>(nbc_, rs_, log_);
tb_->setTimingNetWeightOverflows(options.timingNetWeightOverflows);
tb_->setTimingNetWeightMax(options.timingNetWeightMax);
float timing_net_weight_max = options.timingNetWeightMax;
if (utl::envVarTruthy("ORFS_ENABLE_NEW_OPENROAD")
&& !options.timingNetWeightMaxUserSet) {
if (auto env_max = utl::getEnvFloat("GPL_WEIGHT_MAX")) {
if (*env_max > 0.0f) {
timing_net_weight_max = *env_max;
} else {
log_->warn(
GPL, 160, "Ignoring GPL_WEIGHT_MAX={} (must be > 0).", *env_max);
}
}
}
tb_->setTimingNetWeightMax(timing_net_weight_max);
}

if (!np_) {
Expand Down
3 changes: 3 additions & 0 deletions src/gpl/src/replace.i
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ static gpl::PlaceOptions getOptions(
"-timing_driven_net_reweight_overflow",
options.timingNetWeightOverflows);
checkKey(keys, "-overflow", options.overflow);
if (keys.find("-timing_driven_net_weight_max") != keys.end()) {
options.timingNetWeightMaxUserSet = true;
}
checkKey(keys, "-timing_driven_net_weight_max", options.timingNetWeightMax);
checkKey(
keys, "-keep_resize_below_overflow", options.keepResizeBelowOverflow);
Expand Down
265 changes: 224 additions & 41 deletions src/gpl/src/timingBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,36 @@
#include "timingBase.h"

#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "nesterovBase.h"
#include "placerBase.h"
#include "rsz/Resizer.hh"
#include "sta/Fuzzy.hh"
#include "sta/NetworkClass.hh"
#include "utl/Environment.h"
#include "utl/Logger.h"

namespace gpl {

using utl::GPL;

// TimingBase
TimingBase::TimingBase() = default;
TimingBase::TimingBase()
{
if (utl::envVarTruthy("ORFS_ENABLE_NEW_OPENROAD")) {
loadEnvOverrides();
}
}

TimingBase::TimingBase(std::shared_ptr<NesterovBaseCommon> nbc,
rsz::Resizer* rs,
Expand All @@ -32,6 +43,9 @@ TimingBase::TimingBase(std::shared_ptr<NesterovBaseCommon> nbc,
rs_ = rs;
nbc_ = std::move(nbc);
log_ = log;
if (utl::envVarTruthy("ORFS_ENABLE_NEW_OPENROAD")) {
loadEnvOverrides();
}
}

void TimingBase::initTimingOverflowChk()
Expand All @@ -40,6 +54,57 @@ void TimingBase::initTimingOverflowChk()
timingOverflowChk_.resize(timingNetWeightOverflow_.size(), false);
}

void TimingBase::loadEnvOverrides()
{
if (!utl::envVarTruthy("ORFS_ENABLE_NEW_OPENROAD")) {
return;
}

if (auto env_max = utl::getEnvFloat("GPL_WEIGHT_MAX", log_, GPL, 124)) {
if (*env_max > 0.0F) {
net_weight_max_ = *env_max;
} else if (log_ != nullptr) {
log_->warn(
GPL, 125, "Ignoring GPL_WEIGHT_MAX={} (must be > 0).", *env_max);
}
}

if (auto env_exp = utl::getEnvFloat("GPL_WEIGHT_EXP", log_, GPL, 124)) {
if (*env_exp > 0.0F) {
net_weight_exponent_ = *env_exp;
} else if (log_ != nullptr) {
log_->warn(
GPL, 126, "Ignoring GPL_WEIGHT_EXP={} (must be > 0).", *env_exp);
}
}

const char* raw_use_zero_ref = std::getenv("GPL_WEIGHT_USE_ZERO_REF");
if (raw_use_zero_ref != nullptr && *raw_use_zero_ref != '\0') {
// Treat any non-zero value as enabled. Keep silent on parse issues to avoid
// plumbing yet another message id just for an experimental knob.
use_zero_slack_ref_ = (std::atoi(raw_use_zero_ref) != 0);
}

if (auto env_cov = utl::getEnvFloat("GPL_WEIGHT_COVERAGE", log_, GPL, 124)) {
// Interpret as percent of the "worst nets" set to use as the cutoff.
// Zero disables; values outside (0,100] are ignored.
if (*env_cov > 0.0F && *env_cov <= 100.0F) {
net_weight_coverage_percent_ = *env_cov;
}
}

const char* raw_len_factor = std::getenv("GPL_WEIGHT_USE_LENGTH_FACTOR");
if (raw_len_factor != nullptr && *raw_len_factor != '\0') {
use_length_factor_ = (std::atoi(raw_len_factor) != 0);
}

if (auto env_len_alpha
= utl::getEnvFloat("GPL_WEIGHT_LENGTH_ALPHA", log_, GPL, 124)) {
// Clamp to [0,1] and stay silent on range violations (experimental knob).
length_alpha_ = std::clamp(*env_len_alpha, 0.0F, 1.0F);
}
}

bool TimingBase::isTimingNetWeightOverflow(float overflow)
{
int intOverflow = std::round(overflow * 100);
Expand Down Expand Up @@ -137,10 +202,18 @@ bool TimingBase::executeTimingDriven(bool run_journal_restore)
}

// min/max slack for worst nets
auto slack_min = rs_->resizeNetSlack(worst_slack_nets[0]).value();
auto slack_max
= rs_->resizeNetSlack(worst_slack_nets[worst_slack_nets.size() - 1])
.value();
const auto slack_min_opt = rs_->resizeNetSlack(worst_slack_nets[0]);
const auto slack_max_opt
= rs_->resizeNetSlack(worst_slack_nets[worst_slack_nets.size() - 1]);
if (!slack_min_opt || !slack_max_opt) {
log_->warn(
GPL,
111,
"Timing-driven: missing net slack. Timing-driven mode disabled.");
return false;
}
auto slack_min = *slack_min_opt;
auto slack_max = *slack_max_opt;

log_->info(GPL, 106, "Timing-driven: worst slack {:.3g}", slack_min);

Expand All @@ -151,47 +224,157 @@ bool TimingBase::executeTimingDriven(bool run_journal_restore)
return false;
}

int weighted_net_count = 0;
for (auto& gNet : nbc_->getGNets()) {
// default weight
gNet->setTimingWeight(1.0);
if (gNet->getGPins().size() > 1) {
auto net_slack_opt = rs_->resizeNetSlack(gNet->getPbNet()->getDbNet());
if (!net_slack_opt) {
continue;
const bool use_orfs_new_openroad
= utl::envVarTruthy("ORFS_ENABLE_NEW_OPENROAD");
if (!use_orfs_new_openroad) {
int weighted_net_count = 0;
for (auto& gNet : nbc_->getGNets()) {
// default weight
gNet->setTimingWeight(1.0);
if (gNet->getGPins().size() > 1) {
auto net_slack_opt = rs_->resizeNetSlack(gNet->getPbNet()->getDbNet());
if (!net_slack_opt) {
continue;
}
auto net_slack = net_slack_opt.value();
if (net_slack < slack_max) {
if (slack_max == slack_min) {
gNet->setTimingWeight(1.0);
} else {
// weight(min_slack) = net_weight_max_
// weight(max_slack) = 1
const float weight = 1
+ (net_weight_max_ - 1)
* (slack_max - net_slack)
/ (slack_max - slack_min);
gNet->setTimingWeight(weight);
}
weighted_net_count++;
}
debugPrint(log_,
GPL,
"timing",
1,
"net:{} slack:{} weight:{}",
gNet->getPbNet()->getDbNet()->getConstName(),
net_slack,
gNet->getTotalWeight());
}
auto net_slack = net_slack_opt.value();
if (net_slack < slack_max) {
if (slack_max == slack_min) {
gNet->setTimingWeight(1.0);
} else {
// weight(min_slack) = net_weight_max_
// weight(max_slack) = 1
const float weight = 1
+ (net_weight_max_ - 1) * (slack_max - net_slack)
/ (slack_max - slack_min);
gNet->setTimingWeight(weight);
}

debugPrint(log_,
GPL,
"timing",
1,
"Timing-driven: weighted {} nets.",
weighted_net_count);
return true;
} else {
int weighted_net_count = 0;
using SlackT = decltype(slack_max);
const SlackT slack_zero = 0.0;
SlackT slack_ref = slack_max;
if (use_zero_slack_ref_) {
slack_ref = slack_zero;
if (net_weight_coverage_percent_ > 0.0F && !worst_slack_nets.empty()) {
const size_t worst_count = worst_slack_nets.size();
size_t coverage_count = static_cast<size_t>(
std::ceil(worst_count * net_weight_coverage_percent_ / 100.0F));
coverage_count = std::clamp<size_t>(coverage_count, 1, worst_count);
if (worst_count >= 2) {
coverage_count = std::max<size_t>(coverage_count, 2);
}
auto cutoff_opt
= rs_->resizeNetSlack(worst_slack_nets[coverage_count - 1]);
if (cutoff_opt) {
slack_ref = std::min(cutoff_opt.value(), slack_zero);
}
weighted_net_count++;
}
debugPrint(log_,
GPL,
"timing",
1,
"net:{} slack:{} weight:{}",
gNet->getPbNet()->getDbNet()->getConstName(),
net_slack,
gNet->getTotalWeight());
}
}

debugPrint(log_,
GPL,
"timing",
1,
"Timing-driven: weighted {} nets.",
weighted_net_count);
return true;
double length_norm = 0.0;
size_t length_norm_count = 0;
const float length_alpha = std::clamp(length_alpha_, 0.0F, 1.0F);
if (use_length_factor_) {
for (auto& gNet : nbc_->getGNets()) {
if (gNet->getGPins().size() <= 1) {
continue;
}
auto net_slack_opt = rs_->resizeNetSlack(gNet->getPbNet()->getDbNet());
if (!net_slack_opt) {
continue;
}
const SlackT net_slack = net_slack_opt.value();
if (!(net_slack < slack_ref)) {
continue;
}
const double dx = static_cast<double>(gNet->ux() - gNet->lx());
const double dy = static_cast<double>(gNet->uy() - gNet->ly());
length_norm += std::hypot(dx, dy);
length_norm_count++;
}
if (length_norm_count > 0) {
length_norm /= static_cast<double>(length_norm_count);
} else {
length_norm = 0.0;
}
}
for (auto& gNet : nbc_->getGNets()) {
// default weight
gNet->setTimingWeight(1.0);
if (gNet->getGPins().size() > 1) {
auto net_slack_opt = rs_->resizeNetSlack(gNet->getPbNet()->getDbNet());
if (!net_slack_opt) {
continue;
}
auto net_slack = net_slack_opt.value();
if (net_slack < slack_ref) {
if (slack_ref == slack_min) {
gNet->setTimingWeight(1.0);
} else {
// weight(min_slack) = net_weight_max_
// weight(max_slack) = 1
const float normalized_slack
= std::clamp(static_cast<float>((slack_ref - net_slack)
/ (slack_ref - slack_min)),
0.0F,
1.0F);
float scaled_slack
= std::pow(normalized_slack, net_weight_exponent_);
if (use_length_factor_ && length_norm > 0.0) {
const double dx = static_cast<double>(gNet->ux() - gNet->lx());
const double dy = static_cast<double>(gNet->uy() - gNet->ly());
const double len_metric = std::hypot(dx, dy);
const float len_ratio = std::clamp(
static_cast<float>(len_metric / length_norm), 0.0F, 1.0F);
const float length_factor
= (1.0F - length_alpha) + length_alpha * len_ratio;
scaled_slack *= length_factor;
}
const float weight = 1 + (net_weight_max_ - 1) * scaled_slack;
gNet->setTimingWeight(weight);
}
weighted_net_count++;
}
debugPrint(log_,
GPL,
"timing",
1,
"net:{} slack:{} weight:{}",
gNet->getPbNet()->getDbNet()->getConstName(),
net_slack,
gNet->getTotalWeight());
}
}

debugPrint(log_,
GPL,
"timing",
1,
"Timing-driven: weighted {} nets.",
weighted_net_count);
return true;
}
}

} // namespace gpl
Loading