diff --git a/include/sta/CycleAccting.hh b/include/sta/CycleAccting.hh index 0f35110b..31ac94e0 100644 --- a/include/sta/CycleAccting.hh +++ b/include/sta/CycleAccting.hh @@ -16,7 +16,7 @@ #pragma once -#include "DisallowCopyAssign.hh" +#include "UnorderedSet.hh" #include "MinMax.hh" #include "TimingRole.hh" #include "StaState.hh" @@ -24,6 +24,45 @@ namespace sta { +class CycleAcctingHash +{ +public: + size_t operator()(const CycleAccting *acct) const; +}; + +class CycleAcctingEqual +{ +public: + bool operator()(const CycleAccting *acct1, + const CycleAccting *acct2) const; +}; + +class CycleAcctingLess +{ +public: + bool operator()(const CycleAccting *acct1, + const CycleAccting *acct2) const; +}; + +typedef UnorderedSet CycleAcctingSet; + +class CycleAcctings +{ +public: + CycleAcctings(Sdc *sdc); + ~CycleAcctings(); + void clear(); + // Find the cycle accounting info for paths that start at src clock + // edge and end at target clock edge. + CycleAccting *cycleAccting(const ClockEdge *src, + const ClockEdge *tgt); + void reportClkToClkMaxCycleWarnings(Report *report); + +private: + Sdc *sdc_; + CycleAcctingSet cycle_acctings_; +}; + class CycleAccting { public: @@ -81,24 +120,4 @@ private: bool max_cycles_exceeded_; }; -class CycleAcctingLess -{ -public: - bool operator()(const CycleAccting *acct1, - const CycleAccting *acct2) const; -}; - -class CycleAcctingHash -{ -public: - size_t operator()(const CycleAccting *acct) const; -}; - -class CycleAcctingEqual -{ -public: - bool operator()(const CycleAccting *acct1, - const CycleAccting *acct2) const; -}; - } // namespace diff --git a/include/sta/HashSet.hh b/include/sta/HashSet.hh deleted file mode 100644 index 58e3b933..00000000 --- a/include/sta/HashSet.hh +++ /dev/null @@ -1,453 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2020, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#pragma once - -#include // size_t -#include "Hash.hh" - -namespace sta { - -template class HashSetBucket; - -template -class HashSet -{ -public: - HashSet(); - explicit HashSet(size_t capacity, - bool auto_resize); - explicit HashSet(size_t capacity, - bool auto_resize, - HASH hash, - EQUAL equal); - ~HashSet(); - // Number of objects in the table. - size_t size() const { return size_; } - // Number of hash buckets. - size_t capacity() const { return capacity_; } - // Multi-threaded findKey is safe during resize. - void reserve(size_t capacity); - void insert(KEY key); - KEY findKey(KEY key); - KEY findKey(KEY key) const; - bool hasKey(KEY key); - void erase(KEY key); - bool empty() const; - void clear(); - void deleteContentsClear(); - int longestBucketLength() const; - size_t longestBucketHash() const; - int bucketLength(size_t hash) const; - - void - deleteContents() - { - Iterator iter(this); - while (iter.hasNext()) - delete iter.next(); - } - - // Java style container itererator - // Map::Iterator iter(map); - // while (iter.hasNext()) { - // Value *v = iter.next(); - // } - class Iterator - { - public: - Iterator() : container_(nullptr) {} - explicit Iterator(HashSet *container) - { init(container); } - explicit Iterator(HashSet &container) - { init(container); } - void init(HashSet *container) - { container_ = container; - hash_= 0; - next_ = nullptr; - if (container_) - findNext(); - } - void init(HashSet &container) - { container_ = &container; - hash_= 0; - next_ = nullptr; - if (container_) - findNext(); - } - bool hasNext() { return container_ && next_ != nullptr; } - KEY next() { - HashSetBucket *next = next_; - findNext(); - return next->key(); - } - HashSet *container() { return container_; } - - private: - void - findNext() - { - if (next_) - next_ = next_->next(); - while (next_ == nullptr - && hash_ < container_->capacity()) - next_ = container_->table_[hash_++]; - } - HashSet *container_; - size_t hash_; - HashSetBucket *next_; - }; - - class ConstIterator - { - public: - ConstIterator() : container_(nullptr) {} - explicit ConstIterator(const HashSet *container) - { init(container); } - explicit ConstIterator(const HashSet &container) - { init(container); } - void init(const HashSet *container) - { container_ = container; hash_= 0; next_ = nullptr; findNext(); } - void init(HashSet &container) - { container_ = &container; hash_= 0; next_ = nullptr; findNext(); } - bool hasNext() { return container_ && next_ != nullptr; } - KEY next() { - HashSetBucket *next = next_; - findNext(); - return next->key(); - } - HashSet *container() { return container_; } - - private: - void - findNext() - { - if (next_) - next_ = next_->next(); - while (next_ == nullptr - && hash_ < container_->capacity()) - next_ = container_->table_[hash_++]; - } - const HashSet *container_; - size_t hash_; - HashSetBucket *next_; - }; - -protected: - void initTable(); - static const int default_capacity = (2 << 6) - 1; - - // Table size. - size_t capacity_; - bool auto_resize_; - HASH hash_; - EQUAL equal_; - size_t size_; - HashSetBucket **table_; - HashSet *tmp_; -}; - -template -class HashSetBucket -{ -public: - HashSetBucket(KEY key, HashSetBucket *next); - KEY key() const { return key_; } - void setKey(KEY key) { key_ = key; } - HashSetBucket *next() const { return next_; } - void setNext(HashSetBucket *next) { next_ = next; } - -private: - KEY key_; - HashSetBucket *next_; -}; - -template -HashSetBucket::HashSetBucket(KEY key, - HashSetBucket *next) : - key_(key), - next_(next) -{ -} - -//////////////////////////////////////////////////////////////// - -template -HashSet::HashSet() : - capacity_(default_capacity), - auto_resize_(true), - hash_(HASH()), - equal_(EQUAL()) -{ - initTable(); -} - -template -HashSet::HashSet(size_t capacity, - bool auto_resize) : - capacity_(capacity), - auto_resize_(auto_resize), - hash_(HASH()), - equal_(EQUAL()) -{ - initTable(); -} - -template -HashSet::HashSet(size_t capacity, - bool auto_resize, - HASH hash, - EQUAL equal) : - capacity_(capacity), - auto_resize_(auto_resize), - hash_(hash), - equal_(equal) -{ - initTable(); -} - -template -void -HashSet::initTable() -{ - size_ = 0; - tmp_ = nullptr; - table_ = new HashSetBucket*[capacity_]; - for (size_t i = 0; i < capacity_; i++) - table_[i] = nullptr; -} - -template -HashSet::~HashSet() -{ - for (size_t hash = 0; hash < capacity_; hash++) { - HashSetBucket *next; - for (HashSetBucket *bucket = table_[hash]; - bucket; - bucket = next) { - next = bucket->next(); - delete bucket; - } - } - delete [] table_; - delete tmp_; -} - -template -KEY -HashSet::findKey(KEY key) const -{ - size_t hash = hash_(key) % capacity_; - HashSetBucket *head = table_[hash]; - for (HashSetBucket *bucket = head; bucket; bucket = bucket->next()) { - KEY bucket_key = bucket->key(); - if (equal_(bucket_key, key)) { - return bucket_key; - } - } - return nullptr; -} - -template -KEY -HashSet::findKey(KEY key) -{ - size_t hash = hash_(key) % capacity_; - HashSetBucket *head = table_[hash]; - for (HashSetBucket *bucket = head; bucket; bucket = bucket->next()) { - KEY bucket_key = bucket->key(); - if (equal_(bucket_key, key)) { - return bucket_key; - } - } - return nullptr; -} - -template -bool -HashSet::hasKey(KEY key) -{ - size_t hash = hash_(key) % capacity_; - HashSetBucket *head = table_[hash]; - for (HashSetBucket *bucket = head; bucket; bucket = bucket->next()) { - KEY bucket_key = bucket->key(); - if (equal_(bucket_key, key)) { - return true; - } - } - return false; -} - -template -void -HashSet::insert(KEY key) -{ - size_t hash = hash_(key) % capacity_; - HashSetBucket *head = table_[hash]; - for (HashSetBucket *bucket = head; bucket; bucket = bucket->next()) { - if (equal_(bucket->key(), key)) { - bucket->setKey(key); - return; - } - } - HashSetBucket *bucket = new HashSetBucket(key, head); - table_[hash] = bucket; - size_++; - if (size_ > capacity_ - && auto_resize_) - reserve(nextMersenne(capacity_)); -} - -template -void -HashSet::reserve(size_t capacity) -{ - if (capacity != capacity_) { - if (size_ == 0) { - // Table is empty. - capacity_ = capacity; - delete [] table_; - delete tmp_; - initTable(); - } - else { - delete tmp_; - // Copy entries to tmp. - tmp_ = new HashSet(capacity, auto_resize_, - hash_, equal_); - for (size_t hash = 0; hash < capacity_; hash++) { - for (HashSetBucket *bucket = table_[hash]; - bucket; - bucket = bucket->next()) - tmp_->insert(bucket->key()); - } - - size_t prev_capacity = capacity_; - HashSetBucket **prev_table = table_; - - // Switch over. - table_ = tmp_->table_; - capacity_ = capacity; - - tmp_->capacity_ = prev_capacity; - tmp_->table_ = prev_table; - } - } -} - -template -void -HashSet::erase(KEY key) -{ - size_t hash = hash_(key) % capacity_; - HashSetBucket *head = table_[hash]; - HashSetBucket *prev = nullptr; - for (HashSetBucket *bucket = head; bucket; bucket = bucket->next()) { - if (equal_(bucket->key(), key)) { - if (prev) - prev->setNext(bucket->next()); - else - table_[hash] = bucket->next(); - delete bucket; - size_--; - break; - } - prev = bucket; - } -} - -template -void -HashSet::deleteContentsClear() -{ - if (size_ > 0) { - for (size_t hash = 0; hash < capacity_; hash++) { - HashSetBucket *next; - for (HashSetBucket *bucket = table_[hash]; - bucket; - bucket = next) { - delete bucket->key(); - next = bucket->next(); - delete bucket; - } - table_[hash] = nullptr; - } - size_ = 0; - } -} - -template -void -HashSet::clear() -{ - if (size_ > 0) { - for (size_t hash = 0; hash < capacity_; hash++) { - HashSetBucket *next; - for (HashSetBucket *bucket = table_[hash]; - bucket; - bucket = next) { - next = bucket->next(); - delete bucket; - } - table_[hash] = nullptr; - } - size_ = 0; - } -} - -template -bool -HashSet::empty() const -{ - return size_ == 0; -} - -template -int -HashSet::longestBucketLength() const -{ - return bucketLength(longestBucketHash()); -} - -template -size_t -HashSet::longestBucketHash() const -{ - int longest = 0; - size_t longest_hash = 0; - for (size_t hash = 0; hash < capacity_; hash++) { - int length = bucketLength(hash); - if (length > longest) { - longest = length; - longest_hash = hash; - } - } - return longest_hash; -} - -template -int -HashSet::bucketLength(size_t hash) const -{ - int length = 0; - for (HashSetBucket *bucket = table_[hash]; - bucket; - bucket = bucket->next()) - length++; - return length; -} - -} // namespace diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index ac36b894..7289c415 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -22,7 +22,6 @@ #include "StringUtil.hh" #include "StringSet.hh" #include "Map.hh" -#include "HashSet.hh" #include "UnorderedMap.hh" #include "MinMax.hh" #include "StaState.hh" @@ -107,8 +106,6 @@ typedef Set InputDelaySet; typedef Map InputDelaysPinMap; typedef Set OutputDelaySet; typedef Map OutputDelaysPinMap; -// Use HashSet so no read lock is required. -typedef HashSet CycleAcctingSet; typedef Set InstanceSet; typedef UnorderedMap PinExceptionsMap; typedef Map ClockExceptionsMap; @@ -1286,7 +1283,7 @@ protected: ClockGatingCheckMap clk_gating_check_map_; InstanceClockGatingCheckMap inst_clk_gating_check_map_; PinClockGatingCheckMap pin_clk_gating_check_map_; - CycleAcctingSet cycle_acctings_; + CycleAcctings cycle_acctings_; std::mutex cycle_acctings_lock_; DataChecksMap data_checks_from_map_; DataChecksMap data_checks_to_map_; diff --git a/include/sta/SdcClass.hh b/include/sta/SdcClass.hh index 46f269ac..ff105c73 100644 --- a/include/sta/SdcClass.hh +++ b/include/sta/SdcClass.hh @@ -30,7 +30,6 @@ class Sdc; class Clock; class ClockEdge; class CycleAccting; -class CycleAcctingLess; class InputDelay; class OutputDelay; class FalsePath; diff --git a/sdc/CycleAccting.cc b/sdc/CycleAccting.cc index 8f87c962..8472b143 100644 --- a/sdc/CycleAccting.cc +++ b/sdc/CycleAccting.cc @@ -24,9 +24,80 @@ #include "Units.hh" #include "TimingRole.hh" #include "Clock.hh" +#include "Sdc.hh" namespace sta { +CycleAcctings::CycleAcctings(Sdc *sdc) : + sdc_(sdc) +{ +} + +CycleAcctings::~CycleAcctings() +{ + clear(); +} + +void +CycleAcctings::clear() +{ + cycle_acctings_.deleteContentsClear(); +} + +// Determine cycle accounting "on demand". +CycleAccting * +CycleAcctings::cycleAccting(const ClockEdge *src, + const ClockEdge *tgt) +{ + if (src == nullptr) + src = tgt; + CycleAccting probe(src, tgt); + CycleAccting *acct = cycle_acctings_.findKey(&probe); + if (acct == nullptr) { + acct = new CycleAccting(src, tgt); + if (src == sdc_->defaultArrivalClockEdge()) + acct->findDefaultArrivalSrcDelays(); + else + acct->findDelays(sdc_); + cycle_acctings_.insert(acct); + } + return acct; +} + +void +CycleAcctings::reportClkToClkMaxCycleWarnings(Report *report) +{ + // Find cycle acctings that exceed max cycle count. Eliminate + // duplicate warnings between different src/tgt clk edges. + ClockPairSet clk_warnings; + for (Clock *src_clk : *sdc_->clocks()) { + for (RiseFall *src_rf : RiseFall::range()) { + ClockEdge *src = src_clk->edge(src_rf); + for (Clock *tgt_clk : *sdc_->clocks()) { + for (RiseFall *tgt_rf : RiseFall::range()) { + ClockEdge *tgt = tgt_clk->edge(tgt_rf); + CycleAccting probe(src, tgt); + CycleAccting *acct = cycle_acctings_.findKey(&probe); + if (acct && acct->maxCyclesExceeded()) { + // Canonicalize the warning wrt src/tgt. + ClockPair clk_pair1(src_clk, tgt_clk); + ClockPair clk_pair2(tgt_clk, src_clk); + if (!clk_warnings.hasKey(clk_pair1) + && !clk_warnings.hasKey(clk_pair2)) { + report->warn(9, "No common period was found between clocks %s and %s.", + src_clk->name(), + tgt_clk->name()); + clk_warnings.insert(clk_pair1); + } + } + } + } + } + } +} + +//////////////////////////////////////////////////////////////// + CycleAccting::CycleAccting(const ClockEdge *src, const ClockEdge *tgt) : src_(src), diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 2cb24e96..6bd43fb9 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -92,6 +92,7 @@ Sdc::Sdc(StaState *sta) : clk_group_same_(nullptr), clk_sense_map_(network_), clk_gating_check_(nullptr), + cycle_acctings_(this), input_delay_index_(0), port_cap_map_(nullptr), net_wire_cap_map_(nullptr), @@ -2413,65 +2414,20 @@ CycleAccting * Sdc::cycleAccting(const ClockEdge *src, const ClockEdge *tgt) { - if (src == nullptr) - src = tgt; - CycleAccting *acct; - CycleAccting probe(src, tgt); - acct = cycle_acctings_.findKey(&probe); - if (acct == nullptr) { - UniqueLock lock(cycle_acctings_lock_); - // Recheck with lock. - acct = cycle_acctings_.findKey(&probe); - if (acct == nullptr) { - acct = new CycleAccting(src, tgt); - if (src == defaultArrivalClockEdge()) - acct->findDefaultArrivalSrcDelays(); - else - acct->findDelays(this); - cycle_acctings_.insert(acct); - } - } - return acct; + UniqueLock lock(cycle_acctings_lock_); + return cycle_acctings_.cycleAccting(src, tgt); } void Sdc::reportClkToClkMaxCycleWarnings() { - // Find cycle acctings that exceed max cycle count. Eliminate - // duplicate warnings between different src/tgt clk edges. - ClockPairSet clk_warnings; - ClockPairSeq clk_warnings2; - CycleAcctingSet::Iterator acct_iter(cycle_acctings_); - while (acct_iter.hasNext()) { - CycleAccting *acct = acct_iter.next(); - if (acct->maxCyclesExceeded()) { - Clock *src = acct->src()->clock(); - Clock *tgt = acct->target()->clock(); - // Canonicalize the warning wrt src/tgt. - if (src->index() > tgt->index()) - std::swap(src, tgt); - ClockPair clk_pair(src, tgt); - if (!clk_warnings.hasKey(clk_pair)) { - clk_warnings.insert(clk_pair); - clk_warnings2.push_back(clk_pair); - } - } - } - - // Sort clk pairs so that results are stable. - sort(clk_warnings2, ClockPairLess()); - - for (auto pair : clk_warnings2) { - report_->warn(9, "No common period was found between clocks %s and %s.", - pair.first->name(), - pair.second->name()); - } + cycle_acctings_.reportClkToClkMaxCycleWarnings(report_); } void Sdc::clearCycleAcctings() { - cycle_acctings_.deleteContentsClear(); + cycle_acctings_.clear(); } //////////////////////////////////////////////////////////////// diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 405f65cc..706d3a62 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -844,13 +844,12 @@ public: const Corner *corner, const MinMaxAll *min_max, const StaState *sta); + MakeEndpointPathEnds(const MakeEndpointPathEnds &make_path_ends); ~MakeEndpointPathEnds(); virtual VertexVisitor *copy() const; virtual void visit(Vertex *vertex); private: - DISALLOW_COPY_AND_ASSIGN(MakeEndpointPathEnds); - VisitPathEnds *visit_path_ends_; PathEndVisitor *path_end_visitor_; const Corner *corner_; @@ -870,6 +869,15 @@ MakeEndpointPathEnds::MakeEndpointPathEnds(PathEndVisitor *path_end_visitor, { } +MakeEndpointPathEnds::MakeEndpointPathEnds(const MakeEndpointPathEnds &make_path_ends) : + visit_path_ends_(new VisitPathEnds(make_path_ends.sta_)), + path_end_visitor_(make_path_ends.path_end_visitor_->copy()), + corner_(make_path_ends.corner_), + min_max_(make_path_ends.min_max_), + sta_(make_path_ends.sta_) +{ +} + MakeEndpointPathEnds::~MakeEndpointPathEnds() { delete visit_path_ends_; @@ -903,15 +911,14 @@ PathGroups::makeGroupPathEnds(VertexSet *endpoints, end_visitor.visit(endpoint); } else { - Vector visitors; - for (int i = 0; i < thread_count_; i++) - visitors.push_back(new MakeEndpointPathEnds(visitor, corner, min_max, this)); + Vector visitors(thread_count_, + MakeEndpointPathEnds(visitor, corner, + min_max, this)); for (auto endpoint : *endpoints) { dispatch_queue_->dispatch( [endpoint, &visitors](int i) - { visitors[i]->visit(endpoint); } ); + { visitors[i].visit(endpoint); } ); } dispatch_queue_->finishTasks(); - visitors.deleteContents(); } }