From 450b27ac36f4fc26fbbee5e737b3fdd26c8e80fe Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Fri, 3 Apr 2026 18:29:11 -0400 Subject: [PATCH 1/3] ord: move report design metrics to c++ Signed-off-by: Peter Gadfort --- include/ord/OpenRoad.hh | 2 + src/Metrics.tcl | 112 +---------------------------------- src/OpenRoad.cc | 127 ++++++++++++++++++++++++++++++++++++++++ src/OpenRoad.i | 6 ++ 4 files changed, 136 insertions(+), 111 deletions(-) diff --git a/include/ord/OpenRoad.hh b/include/ord/OpenRoad.hh index 35b6ad067a1..1cd55014d22 100644 --- a/include/ord/OpenRoad.hh +++ b/include/ord/OpenRoad.hh @@ -251,6 +251,8 @@ class OpenRoad static bool getPythonCompileOption(); static bool getGUICompileOption(); + void designMetrics(); + protected: ~OpenRoad(); diff --git a/src/Metrics.tcl b/src/Metrics.tcl index d8c86725d55..b56980fc42e 100644 --- a/src/Metrics.tcl +++ b/src/Metrics.tcl @@ -187,117 +187,7 @@ proc report_units_metric { args } { define_cmd_args "report_design_area_metrics" {} proc report_design_area_metrics { args } { - set db [::ord::get_db] - set dbu_per_uu [expr double([[$db getTech] getDbUnitsPerMicron])] - set block [[$db getChip] getBlock] - set die_bbox [$block getDieArea] - set die_area [expr [$die_bbox dx] * [$die_bbox dy]] - set core_bbox [$block getCoreArea] - set core_area [expr [$core_bbox dx] * [$core_bbox dy]] - - set num_ios [llength [$block getBTerms]] - - set num_insts 0 - set num_stdcells 0 - set num_macros 0 - set num_padcells 0 - set num_cover 0 - - set total_area 0.0 - set stdcell_area 0.0 - set macro_area 0.0 - set padcell_area 0.0 - set cover_area 0.0 - - foreach inst [$block getInsts] { - set inst_master [$inst getMaster] - if { [$inst_master isFiller] } { - continue - } - set wid [$inst_master getWidth] - set ht [$inst_master getHeight] - set inst_area [expr $wid * $ht] - set total_area [expr $total_area + $inst_area] - set num_insts [expr $num_insts + 1] - - if { [$inst_master isBlock] } { - set num_macros [expr $num_macros + 1] - set macro_area [expr $macro_area + $inst_area] - } elseif { [$inst_master isCover] } { - set num_cover [expr $num_cover + 1] - set cover_area [expr $cover_area + $inst_area] - } elseif { [$inst_master isPad] } { - set num_padcells [expr $num_padcells + 1] - set padcell_area [expr $padcell_area + $inst_area] - } else { - set num_stdcells [expr $num_stdcells + 1] - set stdcell_area [expr $stdcell_area + $inst_area] - } - } - - set die_area [expr $die_area / [expr $dbu_per_uu * $dbu_per_uu]] - set core_area [expr $core_area / [expr $dbu_per_uu * $dbu_per_uu]] - set total_area [expr $total_area / [expr $dbu_per_uu * $dbu_per_uu]] - set stdcell_area [expr $stdcell_area / [expr $dbu_per_uu * $dbu_per_uu]] - set macro_area [expr $macro_area / [expr $dbu_per_uu * $dbu_per_uu]] - set padcell_area [expr $padcell_area / [expr $dbu_per_uu * $dbu_per_uu]] - set cover_area [expr $cover_area / [expr $dbu_per_uu * $dbu_per_uu]] - - set total_active_area [expr $stdcell_area + $macro_area] - - if { $core_area > 0 } { - set core_util [expr $total_active_area / $core_area] - if { $core_area > $macro_area } { - set stdcell_util [expr $stdcell_area / [expr $core_area - $macro_area]] - } else { - set stdcell_util 0.0 - } - } else { - set core_util -1.0 - set stdcell_util -1.0 - } - - set std_rows 0 - set std_sites 0 - set rows [dict create] - set sites [dict create] - foreach row [$block getRows] { - set site [$row getSite] - - if { [$site getClass] == "NONE" || [$site getClass] == "CORE" } { - incr std_rows - set std_sites [expr { $std_sites + [$row getSiteCount] }] - } - - dict incr rows [$site getName] 1 - dict incr sites [$site getName] [$row getSiteCount] - } - - utl::metric_int "design__io" $num_ios - utl::metric_float "design__die__area" $die_area - utl::metric_float "design__core__area" $core_area - utl::metric_int "design__instance__count" $num_insts - utl::metric_float "design__instance__area" $total_active_area - utl::metric_int "design__instance__count__stdcell" $num_stdcells - utl::metric_float "design__instance__area__stdcell" $stdcell_area - utl::metric_int "design__instance__count__macros" $num_macros - utl::metric_float "design__instance__area__macros" $macro_area - utl::metric_int "design__instance__count__padcells" $num_padcells - utl::metric_float "design__instance__area__padcells" $padcell_area - utl::metric_int "design__instance__count__cover" $num_cover - utl::metric_float "design__instance__area__cover" $cover_area - utl::metric_float "design__instance__utilization" $core_util - utl::metric_float "design__instance__utilization__stdcell" $stdcell_util - - utl::metric_int "design__rows" $std_rows - dict for {site_name count} $rows { - utl::metric_int "design__rows:$site_name" $count - } - - utl::metric_int "design__sites" $std_sites - dict for {site_name count} $sites { - utl::metric_int "design__sites:$site_name" $count - } + ord::report_design_area_metrics_cmd } # namespace diff --git a/src/OpenRoad.cc b/src/OpenRoad.cc index eef476375e0..4ce140b82b1 100644 --- a/src/OpenRoad.cc +++ b/src/OpenRoad.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -749,4 +750,130 @@ bool OpenRoad::getGUICompileOption() return BUILD_GUI; } +void OpenRoad::designMetrics() +{ + odb::dbChip* chip = db_->getChip(); + + if (chip == nullptr) { + return; + } + + odb::dbBlock* block = chip->getBlock(); + + if (block == nullptr) { + return; + } + + const double dbu_per_uu = db_->getDbuPerMicron(); + + const odb::Rect die_bbox = block->getDieArea(); + const auto die_area = die_bbox.area(); + + const odb::Rect core_bbox = block->getCoreArea(); + const auto core_area = core_bbox.area(); + + const int num_ios = block->getBTerms().size(); + + const int num_insts = block->getInsts().size(); + int num_stdcells = 0; + int num_macros = 0; + int num_padcells = 0; + int num_cover = 0; + + double total_area = 0.0; + double stdcell_area = 0.0; + double macro_area = 0.0; + double padcell_area = 0.0; + double cover_area = 0.0; + + for (odb::dbInst* inst : block->getInsts()) { + odb::dbMaster* inst_master = inst->getMaster(); + if (inst_master->isFiller()) { + continue; + } + + const int wid = inst_master->getWidth(); + const int ht = inst_master->getHeight(); + const double inst_area = static_cast(wid) * ht; + total_area += inst_area; + + if (inst_master->isBlock()) { + num_macros++; + macro_area += inst_area; + } else if (inst_master->isCover()) { + num_cover++; + cover_area += inst_area; + } else if (inst_master->isPad()) { + num_padcells++; + padcell_area += inst_area; + } else { + num_stdcells++; + stdcell_area += inst_area; + } + } + + const double die_area_um = die_area / (dbu_per_uu * dbu_per_uu); + const double core_area_um = core_area / (dbu_per_uu * dbu_per_uu); + total_area /= (dbu_per_uu * dbu_per_uu); + stdcell_area /= (dbu_per_uu * dbu_per_uu); + macro_area /= (dbu_per_uu * dbu_per_uu); + padcell_area /= (dbu_per_uu * dbu_per_uu); + cover_area /= (dbu_per_uu * dbu_per_uu); + + const double total_active_area = stdcell_area + macro_area; + + logger_->metric("design__io", num_ios); + logger_->metric("design__nets", block->getNets().size()); + logger_->metric("design__die__area", die_area_um); + logger_->metric("design__core__area", core_area_um); + logger_->metric("design__instance__count", num_insts); + logger_->metric("design__instance__area", total_active_area); + logger_->metric("design__instance__count__stdcell", num_stdcells); + logger_->metric("design__instance__area__stdcell", stdcell_area); + logger_->metric("design__instance__count__macros", num_macros); + logger_->metric("design__instance__area__macros", macro_area); + logger_->metric("design__instance__count__padcells", num_padcells); + logger_->metric("design__instance__area__padcells", padcell_area); + logger_->metric("design__instance__count__cover", num_cover); + logger_->metric("design__instance__area__cover", cover_area); + + if (core_area > 0) { + logger_->metric("design__instance__utilization", + total_active_area / core_area); + double stdcell_util = 0.0; + if (core_area > macro_area) { + stdcell_util = stdcell_area / (core_area - macro_area); + } + logger_->metric("design__instance__utilization__stdcell", stdcell_util); + } + + int std_rows = 0; + int64_t std_sites = 0; + std::map rows; + std::map sites; + + for (odb::dbRow* row : block->getRows()) { + odb::dbSite* site = row->getSite(); + + if (site->getClass() == odb::dbSiteClass::NONE + || site->getClass() == odb::dbSiteClass::CORE) { + std_rows++; + std_sites += row->getSiteCount(); + } + + rows[site->getName()]++; + sites[site->getName()] += row->getSiteCount(); + } + + logger_->metric("design__rows", std_rows); + for (const auto& [site_name, count] : rows) { + logger_->metric("design__rows:" + site_name, count); + } + + logger_->metric("design__sites", std_sites); + for (const auto& [site_name, count] : sites) { + logger_->metric("design__sites:" + site_name, count); + } +} + } // namespace ord diff --git a/src/OpenRoad.i b/src/OpenRoad.i index a61648388fe..41c7d4e5099 100644 --- a/src/OpenRoad.i +++ b/src/OpenRoad.i @@ -644,6 +644,12 @@ void report_hpwl() w.reportHpwl(getLogger()); } +void report_design_area_metrics_cmd() +{ + OpenRoad *ord = getOpenRoad(); + ord->designMetrics(); } +} // namespace ord + %} // inline From c8bee57692b91bd23070ddc7b61e62e25a2632c2 Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Fri, 3 Apr 2026 20:29:24 -0400 Subject: [PATCH 2/3] ord: remove unused variable and add headers Signed-off-by: Peter Gadfort --- src/OpenRoad.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/OpenRoad.cc b/src/OpenRoad.cc index 4ce140b82b1..661167a6a11 100644 --- a/src/OpenRoad.cc +++ b/src/OpenRoad.cc @@ -3,6 +3,7 @@ #include "ord/OpenRoad.hh" +#include #include #include #include @@ -57,6 +58,7 @@ #include "odb/MakeOdb.h" #include "odb/cdl.h" #include "odb/db.h" +#include "odb/dbTypes.h" #include "odb/defin.h" #include "odb/defout.h" #include "odb/lefin.h" @@ -780,7 +782,6 @@ void OpenRoad::designMetrics() int num_padcells = 0; int num_cover = 0; - double total_area = 0.0; double stdcell_area = 0.0; double macro_area = 0.0; double padcell_area = 0.0; @@ -795,7 +796,6 @@ void OpenRoad::designMetrics() const int wid = inst_master->getWidth(); const int ht = inst_master->getHeight(); const double inst_area = static_cast(wid) * ht; - total_area += inst_area; if (inst_master->isBlock()) { num_macros++; @@ -814,7 +814,6 @@ void OpenRoad::designMetrics() const double die_area_um = die_area / (dbu_per_uu * dbu_per_uu); const double core_area_um = core_area / (dbu_per_uu * dbu_per_uu); - total_area /= (dbu_per_uu * dbu_per_uu); stdcell_area /= (dbu_per_uu * dbu_per_uu); macro_area /= (dbu_per_uu * dbu_per_uu); padcell_area /= (dbu_per_uu * dbu_per_uu); @@ -837,12 +836,12 @@ void OpenRoad::designMetrics() logger_->metric("design__instance__count__cover", num_cover); logger_->metric("design__instance__area__cover", cover_area); - if (core_area > 0) { + if (core_area_um > 0) { logger_->metric("design__instance__utilization", - total_active_area / core_area); + total_active_area / core_area_um); double stdcell_util = 0.0; - if (core_area > macro_area) { - stdcell_util = stdcell_area / (core_area - macro_area); + if (core_area_um > macro_area) { + stdcell_util = stdcell_area / (core_area_um - macro_area); } logger_->metric("design__instance__utilization__stdcell", stdcell_util); } From a3e1445c35f54aaca1c2760ec4ffbef4a951a787 Mon Sep 17 00:00:00 2001 From: Peter Gadfort Date: Sat, 4 Apr 2026 11:59:23 -0400 Subject: [PATCH 3/3] ord/odb: move designMetrics to blockMetrics in zutil Signed-off-by: Peter Gadfort --- include/ord/OpenRoad.hh | 2 - src/OpenRoad.cc | 126 ------------------------------------- src/OpenRoad.i | 9 ++- src/odb/include/odb/util.h | 2 + src/odb/src/zutil/util.cpp | 115 +++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 130 deletions(-) diff --git a/include/ord/OpenRoad.hh b/include/ord/OpenRoad.hh index 1cd55014d22..35b6ad067a1 100644 --- a/include/ord/OpenRoad.hh +++ b/include/ord/OpenRoad.hh @@ -251,8 +251,6 @@ class OpenRoad static bool getPythonCompileOption(); static bool getGUICompileOption(); - void designMetrics(); - protected: ~OpenRoad(); diff --git a/src/OpenRoad.cc b/src/OpenRoad.cc index 661167a6a11..eef476375e0 100644 --- a/src/OpenRoad.cc +++ b/src/OpenRoad.cc @@ -3,13 +3,11 @@ #include "ord/OpenRoad.hh" -#include #include #include #include #include #include -#include #include #include #include @@ -58,7 +56,6 @@ #include "odb/MakeOdb.h" #include "odb/cdl.h" #include "odb/db.h" -#include "odb/dbTypes.h" #include "odb/defin.h" #include "odb/defout.h" #include "odb/lefin.h" @@ -752,127 +749,4 @@ bool OpenRoad::getGUICompileOption() return BUILD_GUI; } -void OpenRoad::designMetrics() -{ - odb::dbChip* chip = db_->getChip(); - - if (chip == nullptr) { - return; - } - - odb::dbBlock* block = chip->getBlock(); - - if (block == nullptr) { - return; - } - - const double dbu_per_uu = db_->getDbuPerMicron(); - - const odb::Rect die_bbox = block->getDieArea(); - const auto die_area = die_bbox.area(); - - const odb::Rect core_bbox = block->getCoreArea(); - const auto core_area = core_bbox.area(); - - const int num_ios = block->getBTerms().size(); - - const int num_insts = block->getInsts().size(); - int num_stdcells = 0; - int num_macros = 0; - int num_padcells = 0; - int num_cover = 0; - - double stdcell_area = 0.0; - double macro_area = 0.0; - double padcell_area = 0.0; - double cover_area = 0.0; - - for (odb::dbInst* inst : block->getInsts()) { - odb::dbMaster* inst_master = inst->getMaster(); - if (inst_master->isFiller()) { - continue; - } - - const int wid = inst_master->getWidth(); - const int ht = inst_master->getHeight(); - const double inst_area = static_cast(wid) * ht; - - if (inst_master->isBlock()) { - num_macros++; - macro_area += inst_area; - } else if (inst_master->isCover()) { - num_cover++; - cover_area += inst_area; - } else if (inst_master->isPad()) { - num_padcells++; - padcell_area += inst_area; - } else { - num_stdcells++; - stdcell_area += inst_area; - } - } - - const double die_area_um = die_area / (dbu_per_uu * dbu_per_uu); - const double core_area_um = core_area / (dbu_per_uu * dbu_per_uu); - stdcell_area /= (dbu_per_uu * dbu_per_uu); - macro_area /= (dbu_per_uu * dbu_per_uu); - padcell_area /= (dbu_per_uu * dbu_per_uu); - cover_area /= (dbu_per_uu * dbu_per_uu); - - const double total_active_area = stdcell_area + macro_area; - - logger_->metric("design__io", num_ios); - logger_->metric("design__nets", block->getNets().size()); - logger_->metric("design__die__area", die_area_um); - logger_->metric("design__core__area", core_area_um); - logger_->metric("design__instance__count", num_insts); - logger_->metric("design__instance__area", total_active_area); - logger_->metric("design__instance__count__stdcell", num_stdcells); - logger_->metric("design__instance__area__stdcell", stdcell_area); - logger_->metric("design__instance__count__macros", num_macros); - logger_->metric("design__instance__area__macros", macro_area); - logger_->metric("design__instance__count__padcells", num_padcells); - logger_->metric("design__instance__area__padcells", padcell_area); - logger_->metric("design__instance__count__cover", num_cover); - logger_->metric("design__instance__area__cover", cover_area); - - if (core_area_um > 0) { - logger_->metric("design__instance__utilization", - total_active_area / core_area_um); - double stdcell_util = 0.0; - if (core_area_um > macro_area) { - stdcell_util = stdcell_area / (core_area_um - macro_area); - } - logger_->metric("design__instance__utilization__stdcell", stdcell_util); - } - - int std_rows = 0; - int64_t std_sites = 0; - std::map rows; - std::map sites; - - for (odb::dbRow* row : block->getRows()) { - odb::dbSite* site = row->getSite(); - - if (site->getClass() == odb::dbSiteClass::NONE - || site->getClass() == odb::dbSiteClass::CORE) { - std_rows++; - std_sites += row->getSiteCount(); - } - - rows[site->getName()]++; - sites[site->getName()] += row->getSiteCount(); - } - - logger_->metric("design__rows", std_rows); - for (const auto& [site_name, count] : rows) { - logger_->metric("design__rows:" + site_name, count); - } - - logger_->metric("design__sites", std_sites); - for (const auto& [site_name, count] : sites) { - logger_->metric("design__sites:" + site_name, count); - } -} - } // namespace ord diff --git a/src/OpenRoad.i b/src/OpenRoad.i index 41c7d4e5099..db60b1c1a41 100644 --- a/src/OpenRoad.i +++ b/src/OpenRoad.i @@ -646,8 +646,13 @@ void report_hpwl() void report_design_area_metrics_cmd() { - OpenRoad *ord = getOpenRoad(); - ord->designMetrics(); + dbDatabase* db = OpenRoad::openRoad()->getDb(); + odb::dbChip* chip = db->getChip(); + if (chip == nullptr) { + return; + } + dbBlock* block = chip->getBlock(); + odb::blockMetrics(block, getLogger()); } } // namespace ord diff --git a/src/odb/include/odb/util.h b/src/odb/include/odb/util.h index 2402e73f77a..60912f80b9a 100644 --- a/src/odb/include/odb/util.h +++ b/src/odb/include/odb/util.h @@ -49,6 +49,8 @@ void set_bterm_top_layer_grid(dbBlock* block, bool dbHasCoreRows(dbDatabase* db); +void blockMetrics(dbBlock* block, utl::Logger* logger); + class WireLengthEvaluator { public: diff --git a/src/odb/src/zutil/util.cpp b/src/odb/src/zutil/util.cpp index c009fce8a9e..411706ea9a7 100644 --- a/src/odb/src/zutil/util.cpp +++ b/src/odb/src/zutil/util.cpp @@ -376,6 +376,121 @@ bool hasOneSiteMaster(dbDatabase* db) return false; } +void blockMetrics(dbBlock* block, utl::Logger* logger) +{ + if (block == nullptr) { + return; + } + + const double dbu_per_uu = block->getDbUnitsPerMicron(); + + const odb::Rect die_bbox = block->getDieArea(); + const auto die_area = die_bbox.area(); + + const odb::Rect core_bbox = block->getCoreArea(); + const auto core_area = core_bbox.area(); + + const int num_ios = block->getBTerms().size(); + + const int num_insts = block->getInsts().size(); + int num_stdcells = 0; + int num_macros = 0; + int num_padcells = 0; + int num_cover = 0; + + double stdcell_area = 0.0; + double macro_area = 0.0; + double padcell_area = 0.0; + double cover_area = 0.0; + + for (odb::dbInst* inst : block->getInsts()) { + odb::dbMaster* inst_master = inst->getMaster(); + if (inst_master->isFiller()) { + continue; + } + + const int wid = inst_master->getWidth(); + const int ht = inst_master->getHeight(); + const double inst_area = static_cast(wid) * ht; + + if (inst_master->isBlock()) { + num_macros++; + macro_area += inst_area; + } else if (inst_master->isCover()) { + num_cover++; + cover_area += inst_area; + } else if (inst_master->isPad()) { + num_padcells++; + padcell_area += inst_area; + } else { + num_stdcells++; + stdcell_area += inst_area; + } + } + + const double die_area_um = die_area / (dbu_per_uu * dbu_per_uu); + const double core_area_um = core_area / (dbu_per_uu * dbu_per_uu); + stdcell_area /= (dbu_per_uu * dbu_per_uu); + macro_area /= (dbu_per_uu * dbu_per_uu); + padcell_area /= (dbu_per_uu * dbu_per_uu); + cover_area /= (dbu_per_uu * dbu_per_uu); + + const double total_active_area = stdcell_area + macro_area; + + logger->metric("design__io", num_ios); + logger->metric("design__nets", block->getNets().size()); + logger->metric("design__die__area", die_area_um); + logger->metric("design__core__area", core_area_um); + logger->metric("design__instance__count", num_insts); + logger->metric("design__instance__area", total_active_area); + logger->metric("design__instance__count__stdcell", num_stdcells); + logger->metric("design__instance__area__stdcell", stdcell_area); + logger->metric("design__instance__count__macros", num_macros); + logger->metric("design__instance__area__macros", macro_area); + logger->metric("design__instance__count__padcells", num_padcells); + logger->metric("design__instance__area__padcells", padcell_area); + logger->metric("design__instance__count__cover", num_cover); + logger->metric("design__instance__area__cover", cover_area); + + if (core_area_um > 0) { + logger->metric("design__instance__utilization", + total_active_area / core_area_um); + double stdcell_util = 0.0; + if (core_area_um > macro_area) { + stdcell_util = stdcell_area / (core_area_um - macro_area); + } + logger->metric("design__instance__utilization__stdcell", stdcell_util); + } + + int std_rows = 0; + int64_t std_sites = 0; + std::map rows; + std::map sites; + + for (odb::dbRow* row : block->getRows()) { + odb::dbSite* site = row->getSite(); + + if (site->getClass() == odb::dbSiteClass::NONE + || site->getClass() == odb::dbSiteClass::CORE) { + std_rows++; + std_sites += row->getSiteCount(); + } + + rows[site->getName()]++; + sites[site->getName()] += row->getSiteCount(); + } + + logger->metric("design__rows", std_rows); + for (const auto& [site_name, count] : rows) { + logger->metric("design__rows:" + site_name, count); + } + + logger->metric("design__sites", std_sites); + for (const auto& [site_name, count] : sites) { + logger->metric("design__sites:" + site_name, count); + } +} + int64_t WireLengthEvaluator::hpwl() const { int64_t hpwl_sum = 0;