22#include "sparta/collection/IterableCollector.hpp"
23#include "sparta/statistics/Counter.hpp"
72 template <
class DataT>
82 typedef DataT value_type;
85 typedef uint32_t size_type;
98 alignas(value_type) std::byte object_memory_[
sizeof(value_type)];
103 DataPointer(DataPointer &&orig) {
104 ::memcpy(&object_memory_, &orig.object_memory_,
sizeof(object_memory_));
105 data =
reinterpret_cast<value_type*
>(&object_memory_);
109 DataPointer(
const DataPointer &) =
delete;
112 void allocate(U && dat) {
113 data =
new (&object_memory_) value_type(std::forward<U>(dat));
116 value_type * data =
nullptr;
117 DataPointer* next_free =
nullptr;
118 uint32_t physical_idx = 0;
121 struct DataPointerValidator;
137 template <
bool is_const_iterator = true>
141 friend class Buffer<value_type>;
142 typedef typename std::conditional<is_const_iterator,
143 const value_type &, value_type &>::type DataReferenceType;
144 typedef typename std::conditional<is_const_iterator,
146 typedef typename std::conditional<is_const_iterator,
147 const DataPointer *, DataPointer *>::type DataPointerType;
154 uint32_t getIndex_()
const {
155 if(buffer_entry_ ==
nullptr) {
156 return attached_buffer_->
capacity();
158 return buffer_entry_->physical_idx;
162 BufferPointerType attached_buffer_ =
nullptr;
165 DataPointerType buffer_entry_ =
nullptr;
172 BufferIterator(BufferPointerType buffer, DataPointerType entry) :
173 attached_buffer_(buffer),
183 BufferIterator() =
default;
189 BufferIterator(
const BufferIterator<false> & iter) :
190 attached_buffer_(iter.attached_buffer_),
191 buffer_entry_(iter.buffer_entry_)
198 BufferIterator(
const BufferIterator<true> & iter) :
199 attached_buffer_(iter.attached_buffer_),
200 buffer_entry_(iter.buffer_entry_)
206 BufferIterator& operator=(
const BufferIterator&) =
default;
209 bool operator<(
const BufferIterator& rhs)
const
211 sparta_assert(attached_buffer_ == rhs.attached_buffer_,
"Cannot compare BufferIterators created by different buffers.");
212 return getIndex_() < rhs.getIndex_();
216 bool operator>(
const BufferIterator& rhs)
const
218 sparta_assert(attached_buffer_ == rhs.attached_buffer_,
"Cannot compare BufferIterators created by different buffers.");
219 return getIndex_() > rhs.getIndex_();
223 bool operator==(
const BufferIterator& rhs)
const
225 sparta_assert(attached_buffer_ == rhs.attached_buffer_,
"Cannot compare BufferIterators created by different buffers.");
226 return (buffer_entry_ == rhs.buffer_entry_);
230 bool operator!=(
const BufferIterator& rhs)
const
232 sparta_assert(attached_buffer_ == rhs.attached_buffer_,
"Cannot compare BufferIterators created by different buffers.");
233 return !operator==(rhs);
240 if(buffer_entry_ !=
nullptr) {
241 return attached_buffer_->validator_->isValid(buffer_entry_);
247 DataReferenceType operator* ()
const {
248 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
249 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
250 return *(buffer_entry_->data);
254 value_type * operator -> () {
255 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
256 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
257 return buffer_entry_->data;
260 value_type
const * operator -> ()
const {
261 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
262 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
263 return buffer_entry_->data;
268 BufferIterator & operator++() {
269 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
271 uint32_t idx = buffer_entry_->physical_idx;
273 if(attached_buffer_->isValid(idx)) {
274 buffer_entry_ = attached_buffer_->buffer_map_[idx];
277 buffer_entry_ =
nullptr;
280 sparta_assert(attached_buffer_->numFree() > 0,
"Incrementing the iterator to entry that is not valid");
286 BufferIterator operator++ (
int) {
287 BufferIterator buf_iter(*
this);
293 BufferIterator & operator-- ()
295 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
297 uint32_t idx = buffer_entry_->physical_idx;
299 if(attached_buffer_->isValid(idx)) {
300 buffer_entry_ = attached_buffer_->buffer_map_[idx];
303 sparta_assert(idx < attached_buffer_->
capacity(),
"Decrementing the iterator results in buffer underrun");
304 buffer_entry_ =
nullptr;
307 else if (attached_buffer_->size()) {
308 buffer_entry_ = attached_buffer_->buffer_map_[attached_buffer_->size()-1];
314 BufferIterator operator-- (
int) {
315 BufferIterator buf_iter(*
this);
324 friend class BufferIterator<true>;
379 const uint32_t num_entries,
421 const value_type &
read(uint32_t idx)
const {
423 return *(buffer_map_[idx]->data);
432 return read(entry.getIndex_());
441 return read(entry.base().getIndex_());
452 return *(buffer_map_[idx]->data);
460 return access(entry.getIndex_());
468 return access(entry.base().getIndex_());
478 return *(buffer_map_[num_valid_ - 1]->data);
518 return push_backImpl_(dat);
532 return push_backImpl_(std::move(dat));
555 return insertImpl_(idx, dat);
578 return insertImpl_(idx, std::move(dat));
584 return insert(entry.getIndex_(), dat);
590 return insert(entry.getIndex_(), std::move(dat));
596 return insert(entry.base().getIndex_(), dat);
602 return insert(entry.base().getIndex_(), std::move(dat));
628 DataPointer* oldFree = free_position_;
629 free_position_ = buffer_map_[idx];
630 free_position_->data->~value_type();
631 free_position_->next_free = oldFree;
634 validator_->detachDataPointer(free_position_);
639 const uint32_t top_idx_of_buffer = num_valid_ - 1;
640 while(i < top_idx_of_buffer)
644 buffer_map_[i] = buffer_map_[i + 1];
645 buffer_map_[i]->physical_idx = i;
648 address_map_[i] = address_map_[i + 1];
653 buffer_map_[top_idx_of_buffer] =
nullptr;
656 address_map_.erase(top_idx_of_buffer);
660 updateUtilizationCounters_();
669 sparta_assert(entry.attached_buffer_ ==
this,
"Cannot erase an entry created by another Buffer");
671 erase(entry.getIndex_());
680 sparta_assert(entry.base().attached_buffer_ ==
this,
"Cannot erase an entry created by another Buffer");
682 erase(entry.base().getIndex_());
692 std::for_each(buffer_map_.begin(), buffer_map_.end(),
696 map_entry->data->~value_type();
699 std::fill(buffer_map_.begin(), buffer_map_.end(),
nullptr);
700 for(uint32_t i = 0; i < data_pool_size_ - 1; ++i) {
701 data_pool_[i].next_free = &data_pool_[i + 1];
703 data_pool_[data_pool_size_ - 1].next_free = &data_pool_[data_pool_size_ - 1];
704 free_position_ = &data_pool_[0];
705 first_position_ = &data_pool_[0];
707 address_map_.clear();
708 updateUtilizationCounters_();
717 return num_valid_ == 0;
742 return iterator(
this, buffer_map_[0]);
805 is_infinite_mode_ =
true;
806 resize_delta_ = resize_delta;
811 typedef std::vector<DataPointer> DataPool;
812 typedef std::vector<DataPointer*> PointerList;
814 struct DataPointerValidator
818 const DataPool * data_pool_;
819 std::vector<uint32_t> validator_;
820 size_type getIndex_(
const DataPointer * dp)
const {
821 auto i = (dp - &(*data_pool_)[0]);
822 return static_cast<size_type
>(i);
825 DataPointerValidator(
const Buffer &b):
826 data_pool_(&b.data_pool_),
827 validator_(b.num_entries_, 0)
830 void attachDataPointer(
const DataPointer* dp){
831 validator_[getIndex_(dp)] = 1;
834 bool isValid(
const DataPointer * dp)
const {
835 return bool(validator_[getIndex_(dp)]);
838 void detachDataPointer(DataPointer * dp) {
839 validator_[getIndex_(dp)] = 0;
843 std::fill(validator_.begin(), validator_.end(), 0);
851 void resizeIteratorValidator(
const uint32_t resize_delta,
852 const DataPool & data_pool) {
853 validator_.resize(validator_.capacity() + resize_delta);
854 data_pool_ = &data_pool;
858 void updateUtilizationCounters_() {
861 utilization_->setValue(num_valid_);
871 void resizeInternalContainers_() {
874 sparta_assert(is_infinite_mode_,
"The Buffer class must be in Infinite-Mode in order to resize itself.");
882 buffer_map_.resize(buffer_map_.capacity() + resize_delta_);
885 num_entries_ = buffer_map_.capacity();
888 data_pool_.resize(num_entries_ * 2);
891 data_pool_size_ = data_pool_.capacity();
896 for(uint32_t i = 0; i < data_pool_size_ - 1; ++i) {
897 data_pool_[i].next_free = &data_pool_[i + 1];
901 data_pool_[data_pool_size_ - 1].next_free = &data_pool_[data_pool_size_ - 1];
904 first_position_ = &data_pool_[0];
908 free_position_ = &data_pool_[num_valid_];
911 for(uint32_t i = 0; i < num_valid_; ++i) {
912 buffer_map_[i] = &data_pool_[address_map_[i]];
916 validator_->resizeIteratorValidator(resize_delta_, data_pool_);
920 iterator push_backImpl_(U&& dat)
925 resizeInternalContainers_();
929 free_position_->allocate(std::forward<U>(dat));
930 free_position_->physical_idx = num_valid_;
933 iterator entry(
this, free_position_);
937 buffer_map_[num_valid_] = free_position_;
942 address_map_[num_valid_] =
943 static_cast<uint32_t
>(free_position_ - &data_pool_[0]);
945 validator_->attachDataPointer(free_position_);
947 free_position_ = free_position_->next_free;
948 updateUtilizationCounters_();
954 iterator insertImpl_(uint32_t idx, U&& dat)
958 resizeInternalContainers_();
960 sparta_assert(numFree(),
"Buffer '" << getName() <<
"' exhausted");
962 <<
"': Cannot insert before a non valid index");
964 free_position_->allocate(std::forward<U>(dat));
965 free_position_->physical_idx = idx;
968 validator_->attachDataPointer(free_position_);
971 iterator entry(
this, free_position_);
974 uint32_t i = num_valid_;
978 buffer_map_[i] = buffer_map_[i - 1];
979 buffer_map_[i]->physical_idx = i ;
982 address_map_[i] = address_map_[i - 1];
986 buffer_map_[idx] = free_position_;
991 address_map_[num_valid_] =
992 static_cast<uint32_t
>(free_position_ - &data_pool_[0]);
994 free_position_ = free_position_->next_free;
995 updateUtilizationCounters_();
1000 const Clock * clk_ =
nullptr;
1001 size_type num_entries_;
1002 PointerList buffer_map_;
1003 size_type data_pool_size_;
1004 DataPool data_pool_;
1006 DataPointer* free_position_ = 0;
1007 DataPointer* first_position_ = 0;
1008 size_type num_valid_ = 0;
1009 std::unique_ptr<DataPointerValidator> validator_;
1013 std::unique_ptr<sparta::CycleHistogramStandalone> utilization_;
1017 std::unique_ptr<collection::IterableCollector<Buffer<value_type> > > collector_;
1021 bool is_infinite_mode_ {
false};
1028 std::unordered_map<uint32_t, uint32_t> address_map_;
1033 template<
class DataT>
1035 uint32_t num_entries,
1044 num_entries_(num_entries),
1045 data_pool_size_(num_entries* 2)
1047 if((num_entries > 0) && statset)
1050 name_ +
"_utilization",
1051 name_ +
" occupancy histogram",
1052 0, num_entries, 1, 0,
1059 buffer_map_.resize(num_entries_);
1060 data_pool_.resize(data_pool_size_);
1063 validator_.reset(
new DataPointerValidator(*
this));
1068 template<
typename DataT>
1070 name_(std::move(rval.name_)),
1072 num_entries_(rval.num_entries_),
1073 buffer_map_(std::move(rval.buffer_map_)),
1074 data_pool_size_(rval.data_pool_size_),
1075 data_pool_(std::move(rval.data_pool_)),
1076 free_position_(rval.free_position_),
1077 first_position_(rval.first_position_),
1078 num_valid_(rval.num_valid_),
1079 validator_(new DataPointerValidator(*this)),
1080 utilization_(std::move(rval.utilization_)),
1081 collector_(std::move(rval.collector_)),
1082 is_infinite_mode_(rval.is_infinite_mode_),
1083 resize_delta_(std::move(rval.resize_delta_)),
1084 address_map_(std::move(rval.address_map_)){
1085 rval.clk_ =
nullptr;
1086 rval.num_entries_ = 0;
1087 rval.data_pool_size_ = 0;
1088 rval.free_position_ =
nullptr;
1089 rval.first_position_ =
nullptr;
1090 rval.num_valid_ = 0;
1091 rval.utilization_ =
nullptr;
1092 rval.collector_ =
nullptr;
1093 validator_->validator_ = std::move(rval.validator_->validator_);
1095 collector_->reattach(
this);
CycleHistogram implementation using sparta CycleCounter.
Defines a few handy (and now deprecated) C++ iterator traits.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
Contains a statistic definition (some useful information which can be computed)
Contains a StatisticInstance which refers to a StatisticDef or Counter and some local state to comput...
A data structure allowing appending at the end, beginning, or middle, but erase anywhere with collaps...
iterator insert(uint32_t idx, const value_type &dat)
Insert the item BEFORE the given index.
void clear()
Empty the contents of the Buffer.
size_type numFree() const
Return the number of free entries.
const std::string & getName() const
Name of this resource.
Buffer(Buffer< value_type > &&)
Move Constructor to allow moves.
const value_type & read(const const_iterator &entry) const
read the entry at the BufferIterator's location
iterator insert(const const_iterator &entry, value_type &&dat)
Do an insert before a BufferIterator see insert method above.
std::reverse_iterator< iterator > reverse_iterator
Typedef for constant reverse iterator.
const_reverse_iterator rend() const
Returns a const_reverse_iterator referring to start element in the Buffer container.
void erase(const uint32_t &idx)
erase a position in the Buffer immediately.
Buffer(const std::string &name, const uint32_t num_entries, const Clock *clk, StatisticSet *statset=nullptr, InstrumentationNode::visibility_t stat_vis_general=InstrumentationNode::AUTO_VISIBILITY, InstrumentationNode::visibility_t stat_vis_detailed=InstrumentationNode::VIS_HIDDEN, InstrumentationNode::visibility_t stat_vis_max=InstrumentationNode::AUTO_VISIBILITY, InstrumentationNode::visibility_t stat_vis_avg=InstrumentationNode::AUTO_VISIBILITY)
Construct a buffer.
size_type size() const
Return the number of valid entries.
bool empty() const
Query if the buffer is empty.
const_iterator begin() const
Get the const_iterator pointing to the begin of Buffer.
iterator push_back(const value_type &dat)
Append data to the end of Buffer, and return a BufferIterator.
reverse_iterator rend()
Returns an reverse iterator referring to starting element in the Buffer container.
BufferIterator< true > const_iterator
Typedef for constant iterator.
void makeInfinite(const uint32_t resize_delta=1)
Makes the Buffer grow beyond its capacity. The buffer grows by adding new entries in its internal vec...
iterator begin()
Get the iterator pointing to the beginning of Buffer.
value_type & access(const const_reverse_iterator &entry)
Read and return the data at the given BufferIterator's location, reference.
iterator push_back(value_type &&dat)
Append data to the end of Buffer, and return a BufferIterator.
const_iterator end() const
Returns a const_iterator referring to past-the-end element in the Buffer container.
Buffer & operator=(const Buffer< value_type > &)=delete
No copies allowed for Buffer.
const value_type & read(uint32_t idx) const
Read and return the data at the given index, const reference.
iterator insert(const const_iterator &entry, const value_type &dat)
Do an insert before a BufferIterator see insert method above.
const value_type & read(const const_reverse_iterator &entry) const
read the entry at the BufferIterator's location
reverse_iterator rbegin()
Get the iterator pointing to the pass-the-end element of Buffer.
iterator insert(const const_reverse_iterator &entry, value_type &&dat)
Do an insert before a BufferIterator see insert method above.
value_type & access(const const_iterator &entry)
Read and return the data at the given BufferIterator's location, reference.
value_type & accessBack()
Read and return the data at the bottom of the Buffer.
std::reverse_iterator< const_iterator > const_reverse_iterator
Typedef for regular reverse iterator.
bool isValid(uint32_t idx) const
Determine if data at the index is valid.
iterator insert(uint32_t idx, value_type &&dat)
Insert the item BEFORE the given index.
size_type capacity() const
Return the fixed size of this buffer.
void enableCollection(TreeNode *parent)
Request that this queue begin collecting its contents for pipeline collection.
Buffer(const Buffer< value_type > &)=delete
No copies allowed for Buffer.
iterator insert(const const_reverse_iterator &entry, const value_type &dat)
Do an insert before a BufferIterator see insert method above.
value_type & access(uint32_t idx)
Read and return the data at the given index, reference.
void erase(const const_iterator &entry)
erase the index at which the entry exists in the Buffer.
BufferIterator< false > iterator
Typedef for regular iterator.
const_reverse_iterator rbegin() const
Get the const_reverse_iterator pointing to the pass-the-end of Buffer.
void erase(const const_reverse_iterator &entry)
erase the index at which the entry exists in the Buffer.
iterator end()
Returns an iterator referring to past-the-end element in the Buffer container.
~Buffer()
Clear (and destruct the Buffer's contents)
A representation of simulated time.
CycleHistogramStandalone class for uint64_t values.
uint32_t visibility_t
Continuous visibility level. Several key points along continum are indicated within Visibility.
@ VIS_HIDDEN
Hidden hint. Lowest possible visibility.
static constexpr visibility_t AUTO_VISIBILITY
The default sparta resource visibility value that should be used. This is an alias of VIS_MAX at the ...
Set of StatisticDef and CounterBase-derived objects for visiblility through a sparta Tree.
Node in a composite tree representing a sparta Tree item.
A collector of any iterable type (std::vector, std::list, sparta::Buffer, etc)
Provides a wrapper around a value to ensure that the value is assigned.
Macros for handling exponential backoff.