Skip to content
Merged
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
44 changes: 29 additions & 15 deletions src/gui/src/renderThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <QPolygon>
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <exception>
#include <iterator>
#include <mutex>
Expand Down Expand Up @@ -1552,18 +1553,14 @@ void RenderThread::setupIOPins(odb::dbBlock* block, const odb::Rect& bounds)
}

const auto die_area = block->getDieArea();
const auto die_width = die_area.dx();
const auto die_height = die_area.dy();

pin_draw_names_ = viewer_->options_->areIOPinNamesVisible();
const double scale_factor
= 0.02; // 4 Percent of bounds is used to draw pin-markers
const int die_max_dim = std::min(die_area.maxDXDY(), bounds.maxDXDY());
const double abs_min_dim = 8.0; // prevent markers from falling apart
pin_max_size_ = std::max(scale_factor * die_max_dim, abs_min_dim);
if (pin_draw_names_) {
const double scale_factor
= 0.02; // 4 Percent of bounds is used to draw pin-markers
const int die_max_dim
= std::min(std::max(die_width, die_height), bounds.maxDXDY());
const double abs_min_dim = 8.0; // prevent markers from falling apart
pin_max_size_ = std::max(scale_factor * die_max_dim, abs_min_dim);

pin_font_ = viewer_->options_->ioPinMarkersFont();
const QFontMetrics font_metrics(pin_font_);

Expand Down Expand Up @@ -1690,16 +1687,33 @@ void RenderThread::drawIOPins(Painter& painter,
};
std::vector<PinText> pin_text_spec;

const int min_bpin_size = viewer_->options_->isDetailedVisibility()
? viewer_->fineViewableResolution()
: viewer_->nominalViewableResolution();
const int64_t max_lin_bpins = bounds.minDXDY() / min_bpin_size;
const int64_t max_bpins
= std::min(kMaxBPinsPerLayer, max_lin_bpins * max_lin_bpins);

painter.setPen(layer);
painter.setBrush(layer);

auto bpins = viewer_->search_.searchBPins(
block, layer, bounds.xMin(), bounds.yMin(), bounds.xMax(), bounds.yMax());
debugPrint(logger_,
GUI,
"draw",
2,
"found {} bpins on layer {}, drawing limit {} ({}) bpins",
bpins.size(),
layer->getName(),
max_bpins,
max_lin_bpins);
if (bpins.size() > max_bpins) {
return;
}
Comment on lines +1700 to +1713
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This implementation is inefficient for a large number of bpins. bpins.size() iterates through all the search results to count them (an O(N) operation for the forward iterators used here), and then the for loop iterates over them again to draw them. This results in two passes over the data.

A more efficient approach is to iterate once, collecting the bpins into a vector and stopping as soon as the number of bpins exceeds max_bpins. This avoids a full second pass over the data when the limit is exceeded. This is especially important as this change is intended to handle cases with a very large number of bpins.

  auto bpins_range = viewer_->search_.searchBPins(
      block, layer, bounds.xMin(), bounds.yMin(), bounds.xMax(), bounds.yMax());

  std::vector<std::pair<odb::dbBox*, odb::dbBPin*>> bpins;
  bpins.reserve(max_bpins + 1);
  for (const auto& bpin : bpins_range) {
    bpins.push_back(bpin);
    if (bpins.size() > max_bpins) {
      break;
    }
  }

  debugPrint(logger_,
             GUI,
             "draw",
             2,
             "found {} bpins on layer {}, drawing limit {} ({}) bpins",
             bpins.size() > max_bpins ? std::string(">") + std::to_string(max_bpins) : std::to_string(bpins.size()),
             layer->getName(),
             max_bpins,
             max_lin_bpins);
  if (bpins.size() > max_bpins) {
    return;
  }
References
  1. When adjusting font size for multiple labels, on-the-fly adjustment while iterating can be more efficient than a two-pass approach (find max length, then adjust). The single-pass method allows for early exit if minimum font size is reached, avoiding processing all labels.


std::vector<odb::Rect> pin_text_spec_shape_rects;
for (const auto& [box, pin] : viewer_->search_.searchBPins(block,
layer,
bounds.xMin(),
bounds.yMin(),
bounds.xMax(),
bounds.yMax())) {
for (const auto& [box, pin] : bpins) {
if (restart_) {
break;
}
Expand Down
3 changes: 3 additions & 0 deletions src/gui/src/renderThread.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QString>
#include <QThread>
#include <QWaitCondition>
#include <cstdint>
#include <map>
#include <mutex>
#include <utility>
Expand Down Expand Up @@ -169,6 +170,8 @@ class RenderThread : public QThread
QFont pin_font_;
bool pin_draw_names_ = false;
double pin_max_size_ = 0.0;

static constexpr int64_t kMaxBPinsPerLayer = 100000;
};

} // namespace gui
3 changes: 3 additions & 0 deletions src/gui/src/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <QObject>
#include <atomic>
#include <iterator>
#include <map>
#include <mutex>
#include <tuple>
Expand Down Expand Up @@ -126,6 +127,8 @@ class Search : public QObject, public odb::dbBlockCallBackObj
Iterator begin() { return begin_; }
Iterator end() { return end_; }

int size() const { return std::distance(begin_, end_); }
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The size() method has a time complexity of O(N), where N is the number of elements in the range, because it uses std::distance on forward iterators. This can be inefficient if the range is large. For collections where size() is not an O(1) operation, it's a common C++ practice to name the method count() to avoid giving a false impression of its performance. Using this size() method and then iterating over the range again results in two passes over the data, which is inefficient for large datasets.

References
  1. When adjusting font size for multiple labels, on-the-fly adjustment while iterating can be more efficient than a two-pass approach (find max length, then adjust). The single-pass method allows for early exit if minimum font size is reached, avoiding processing all labels.


private:
Iterator begin_;
Iterator end_;
Expand Down