Skip to content

gpl: use cached pin count in reportInstanceExtensionByPinDensity - #11072

Open
oharboe wants to merge 4 commits into
The-OpenROAD-Project:masterfrom
oharboe:gpl-cached-pin-count-reporting
Open

gpl: use cached pin count in reportInstanceExtensionByPinDensity#11072
oharboe wants to merge 4 commits into
The-OpenROAD-Project:masterfrom
oharboe:gpl-cached-pin-count-reporting

Conversation

@oharboe

@oharboe oharboe commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Optimizes gpl::NesterovBaseCommon::reportInstanceExtensionByPinDensity() to use the cached stats.pin_count per cell master rather than querying db_inst->getITerms().size() redundantly for every instance across the design.

Rationale

reportInstanceExtensionByPinDensity() collects per-master statistics and calculates area-per-pin metrics across all instances in the placement graph. Previously, db_inst->getITerms().size() was invoked on every instance. Since db_inst->getITerms().size() traverses an unindexed linked list of _dbITerm pointers in OpenDB, calling it on large designs (>2M instances) spent 99.5% of reporting execution time inside linked-list traversals.

Using the stats.pin_count already cached per cell master on line 1981 avoids 2.4 million linked-list traversals while producing identical statistics output.

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe
oharboe requested a review from a team as a code owner August 5, 2026 08:25
@oharboe
oharboe requested a review from LucasYuki August 5, 2026 08:25

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the reportInstanceExtensionByPinDensity function in nesterovBase.cpp by utilizing the cached stats.pin_count instead of recalculating the pin count for each instance. The reviewer identified an existing logical issue where master statistics are overwritten in each iteration rather than accumulated, resulting in final reports that only reflect the last processed instance. The reviewer provided a suggestion to accumulate these areas and calculate the averages after the loop.

Comment thread src/gpl/src/nesterovBase.cpp Outdated
…tInstanceExtensionByPinDensity

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@github-actions github-actions Bot added size/S and removed size/XS labels Aug 5, 2026
@oharboe

oharboe commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the calculation of per-master derived metrics in reportInstanceExtensionByPinDensity to run post-loop, accumulating areas using +=. Feedback highlights a critical issue where master_stats_map is declared as static, causing accumulated statistics to persist and grow incorrectly across multiple calls. Additionally, there is a risk of signed integer overflow when multiplying pin_count and instance_count on large designs, which can be mitigated by casting to double.

Comment thread src/gpl/src/nesterovBase.cpp
Comment thread src/gpl/src/nesterovBase.cpp Outdated
Signed-off-by: Øyvind Harboe <oyvind.harboe@zylin.com>
@oharboe

oharboe commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors nesterovBase.cpp by removing the static qualifier from master_stats_map and moving the calculation of per-master derived metrics post-loop. Feedback is provided to optimize performance by accumulating raw DBU areas inside the loop and converting them to microns post-loop, which avoids repetitive floating-point divisions.

Comment on lines +1983 to 2005
stats.total_original_area += block->dbuAreaToMicrons(orig_area);
stats.total_extended_area += block->dbuAreaToMicrons(ext_area);
}

// Save area per pin
int pin_count = db_inst->getITerms().size();
if (pin_count > 0) {
// Calculate per-master derived metrics post-loop
for (auto& entry : master_stats_map) {
MasterStats& stats = entry.second;
if (stats.pin_count > 0 && stats.instance_count > 0) {
stats.original_area_per_pin
= block->dbuAreaToMicrons(orig_area) / pin_count;
= stats.total_original_area
/ (static_cast<double>(stats.pin_count) * stats.instance_count);
stats.extended_area_per_pin
= block->dbuAreaToMicrons(ext_area) / pin_count;
= stats.total_extended_area
/ (static_cast<double>(stats.pin_count) * stats.instance_count);
}
// Populate area_diff as the percentage difference between extended and
// original area
if (orig_area != 0) {
if (stats.total_original_area != 0.0) {
stats.area_diff = 100.0f
* (static_cast<float>(ext_area - orig_area)
/ static_cast<float>(orig_area));
* (static_cast<float>(stats.total_extended_area
- stats.total_original_area)
/ static_cast<float>(stats.total_original_area));
} else {
stats.area_diff = 0.0f;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Performance Optimization

Currently, block->dbuAreaToMicrons() is called inside the loop for every single instance (potentially millions of times). Since dbuAreaToMicrons performs a floating-point division, doing this inside the loop adds unnecessary overhead.

We can optimize this by accumulating the raw DBU areas as integers/doubles inside the loop, and then converting the final accumulated totals to microns once per master in the post-loop. This avoids millions of division operations.

    stats.total_original_area += orig_area;
    stats.total_extended_area += ext_area;
  }

  // Calculate per-master derived metrics post-loop
  for (auto& entry : master_stats_map) {
    MasterStats& stats = entry.second;
    stats.total_original_area = block->dbuAreaToMicrons(static_cast<int64_t>(stats.total_original_area));
    stats.total_extended_area = block->dbuAreaToMicrons(static_cast<int64_t>(stats.total_extended_area));
    if (stats.pin_count > 0 && stats.instance_count > 0) {
      stats.original_area_per_pin
          = stats.total_original_area
            / (static_cast<double>(stats.pin_count) * stats.instance_count);
      stats.extended_area_per_pin
          = stats.total_extended_area
            / (static_cast<double>(stats.pin_count) * stats.instance_count);
    }
    if (stats.total_original_area != 0.0) {
      stats.area_diff = static_cast<float>(100.0 * (stats.total_extended_area - stats.total_original_area) / stats.total_original_area);
    } else {
      stats.area_diff = 0.0f;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant