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
212 "Cannot compare BufferIterators created by different buffers.");
213 return getIndex_() < rhs.getIndex_();
217 bool operator>(
const BufferIterator& rhs)
const
220 "Cannot compare BufferIterators created by different buffers.");
221 return getIndex_() > rhs.getIndex_();
225 bool operator==(
const BufferIterator& rhs)
const
228 "Cannot compare BufferIterators created by different buffers.");
229 return (buffer_entry_ == rhs.buffer_entry_);
233 bool operator!=(
const BufferIterator& rhs)
const
236 "Cannot compare BufferIterators created by different buffers.");
237 return !operator==(rhs);
244 if(buffer_entry_ !=
nullptr) {
245 return attached_buffer_->validator_->isValid(buffer_entry_);
251 DataReferenceType operator* ()
const {
253 "The iterator is not attached to a buffer. Was it initialized?");
254 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
255 return *(buffer_entry_->data);
259 value_type * operator -> () {
261 "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;
266 value_type
const * operator -> ()
const {
268 "The iterator is not attached to a buffer. Was it initialized?");
269 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
270 return buffer_entry_->data;
275 BufferIterator & operator++() {
277 "The iterator is not attached to a buffer. Was it initialized?");
278 sparta_assert(isValid(),
"Incrementing an iterator that is not valid");
279 const uint32_t idx = buffer_entry_->physical_idx + 1;
280 if(attached_buffer_->isValid(idx)) {
281 buffer_entry_ = attached_buffer_->buffer_map_[idx];
284 buffer_entry_ =
nullptr;
290 BufferIterator operator++ (
int) {
291 BufferIterator buf_iter(*
this);
297 BufferIterator & operator-- ()
299 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
301 uint32_t idx = buffer_entry_->physical_idx;
303 if(attached_buffer_->isValid(idx)) {
304 buffer_entry_ = attached_buffer_->buffer_map_[idx];
307 sparta_assert(idx < attached_buffer_->
capacity(),
"Decrementing the iterator results in buffer underrun");
308 buffer_entry_ =
nullptr;
311 else if (attached_buffer_->size()) {
312 buffer_entry_ = attached_buffer_->buffer_map_[attached_buffer_->size()-1];
318 BufferIterator operator-- (
int) {
319 BufferIterator buf_iter(*
this);
328 friend class BufferIterator<true>;
383 const uint32_t num_entries,
425 const value_type &
read(uint32_t idx)
const {
427 return *(buffer_map_[idx]->data);
436 return read(entry.getIndex_());
445 return read(std::prev(entry.base()));
456 return *(buffer_map_[idx]->data);
464 return access(entry.getIndex_());
472 return access(std::prev(entry.base()));
482 return *(buffer_map_[num_valid_ - 1]->data);
522 return push_backImpl_(dat);
536 return push_backImpl_(std::move(dat));
559 return insertImpl_(idx, dat);
582 return insertImpl_(idx, std::move(dat));
588 return insert(entry.getIndex_(), dat);
594 return insert(entry.getIndex_(), std::move(dat));
600 return insert(entry.base().getIndex_(), dat);
606 return insert(entry.base().getIndex_(), std::move(dat));
627 "Cannot erase an index that is not already valid");
633 DataPointer* oldFree = free_position_;
634 free_position_ = buffer_map_[idx];
635 free_position_->data->~value_type();
636 free_position_->next_free = oldFree;
639 validator_->detachDataPointer(free_position_);
643 const uint32_t top_idx_of_buffer = num_valid_ - 1;
644 while(idx < top_idx_of_buffer)
648 buffer_map_[idx] = buffer_map_[idx + 1];
649 buffer_map_[idx]->physical_idx = idx;
652 address_map_[idx] = address_map_[idx + 1];
657 buffer_map_[top_idx_of_buffer] =
nullptr;
660 address_map_.erase(top_idx_of_buffer);
664 updateUtilizationCounters_();
674 "Cannot erase an entry created by another Buffer");
676 erase(entry.getIndex_());
677 return {
this, buffer_map_[entry.getIndex_()]};
696 std::for_each(buffer_map_.begin(), buffer_map_.end(),
700 map_entry->data->~value_type();
703 std::fill(buffer_map_.begin(), buffer_map_.end(),
nullptr);
704 for(uint32_t i = 0; i < data_pool_size_ - 1; ++i) {
705 data_pool_[i].next_free = &data_pool_[i + 1];
707 data_pool_[data_pool_size_ - 1].next_free = &data_pool_[data_pool_size_ - 1];
708 free_position_ = &data_pool_[0];
709 first_position_ = &data_pool_[0];
711 address_map_.clear();
712 updateUtilizationCounters_();
721 return num_valid_ == 0;
746 return iterator(
this, buffer_map_[0]);
809 is_infinite_mode_ =
true;
810 resize_delta_ = resize_delta;
815 typedef std::vector<DataPointer> DataPool;
816 typedef std::vector<DataPointer*> PointerList;
818 struct DataPointerValidator
822 const DataPool * data_pool_;
823 std::vector<uint32_t> validator_;
824 size_type getIndex_(
const DataPointer * dp)
const {
825 auto i = (dp - &(*data_pool_)[0]);
826 return static_cast<size_type
>(i);
829 DataPointerValidator(
const Buffer &b):
830 data_pool_(&b.data_pool_),
831 validator_(b.num_entries_, 0)
834 void attachDataPointer(
const DataPointer* dp){
835 validator_[getIndex_(dp)] = 1;
838 bool isValid(
const DataPointer * dp)
const {
839 return bool(validator_[getIndex_(dp)]);
842 void detachDataPointer(DataPointer * dp) {
843 validator_[getIndex_(dp)] = 0;
847 std::fill(validator_.begin(), validator_.end(), 0);
855 void resizeIteratorValidator(
const uint32_t resize_delta,
856 const DataPool & data_pool) {
857 validator_.resize(validator_.capacity() + resize_delta);
858 data_pool_ = &data_pool;
862 void updateUtilizationCounters_() {
865 utilization_->setValue(num_valid_);
875 void resizeInternalContainers_() {
879 "The Buffer class must be in Infinite-Mode in order to resize itself.");
887 buffer_map_.resize(buffer_map_.capacity() + resize_delta_);
890 num_entries_ = buffer_map_.capacity();
893 data_pool_.resize(num_entries_ * 2);
896 data_pool_size_ = data_pool_.capacity();
901 for(uint32_t i = 0; i < data_pool_size_ - 1; ++i) {
902 data_pool_[i].next_free = &data_pool_[i + 1];
906 data_pool_[data_pool_size_ - 1].next_free = &data_pool_[data_pool_size_ - 1];
909 first_position_ = &data_pool_[0];
913 free_position_ = &data_pool_[num_valid_];
916 for(uint32_t i = 0; i < num_valid_; ++i) {
917 buffer_map_[i] = &data_pool_[address_map_[i]];
921 validator_->resizeIteratorValidator(resize_delta_, data_pool_);
925 iterator push_backImpl_(U&& dat)
930 resizeInternalContainers_();
934 free_position_->allocate(std::forward<U>(dat));
935 free_position_->physical_idx = num_valid_;
938 iterator entry(
this, free_position_);
942 buffer_map_[num_valid_] = free_position_;
947 address_map_[num_valid_] =
948 static_cast<uint32_t
>(free_position_ - &data_pool_[0]);
950 validator_->attachDataPointer(free_position_);
952 free_position_ = free_position_->next_free;
953 updateUtilizationCounters_();
959 iterator insertImpl_(uint32_t idx, U&& dat)
963 resizeInternalContainers_();
965 sparta_assert(numFree(),
"Buffer '" << getName() <<
"' exhausted");
967 <<
"': Cannot insert before a non valid index");
969 free_position_->allocate(std::forward<U>(dat));
970 free_position_->physical_idx = idx;
973 validator_->attachDataPointer(free_position_);
976 iterator entry(
this, free_position_);
979 uint32_t i = num_valid_;
983 buffer_map_[i] = buffer_map_[i - 1];
984 buffer_map_[i]->physical_idx = i ;
987 address_map_[i] = address_map_[i - 1];
991 buffer_map_[idx] = free_position_;
996 address_map_[num_valid_] =
997 static_cast<uint32_t
>(free_position_ - &data_pool_[0]);
999 free_position_ = free_position_->next_free;
1000 updateUtilizationCounters_();
1005 const Clock * clk_ =
nullptr;
1006 size_type num_entries_ = 0;
1007 PointerList buffer_map_;
1008 size_type data_pool_size_ = 0;
1009 DataPool data_pool_;
1012 DataPointer* free_position_ =
nullptr;
1013 DataPointer* first_position_ =
nullptr;
1014 size_type num_valid_ = 0;
1015 std::unique_ptr<DataPointerValidator> validator_;
1019 std::unique_ptr<sparta::CycleHistogramStandalone> utilization_;
1023 std::unique_ptr<collection::IterableCollector<Buffer<value_type> > > collector_;
1027 bool is_infinite_mode_ {
false};
1034 std::unordered_map<uint32_t, uint32_t> address_map_;
1039 template<
class DataT>
1041 uint32_t num_entries,
1050 num_entries_(num_entries),
1051 data_pool_size_(num_entries* 2)
1053 if((num_entries > 0) && statset)
1056 name_ +
"_utilization",
1057 name_ +
" occupancy histogram",
1058 0, num_entries, 1, 0,
1065 buffer_map_.resize(num_entries_);
1066 data_pool_.resize(data_pool_size_);
1069 validator_.reset(
new DataPointerValidator(*
this));
1074 template<
typename DataT>
1076 name_(std::move(rval.name_)),
1078 num_entries_(rval.num_entries_),
1079 buffer_map_(std::move(rval.buffer_map_)),
1080 data_pool_size_(rval.data_pool_size_),
1081 data_pool_(std::move(rval.data_pool_)),
1082 free_position_(rval.free_position_),
1083 first_position_(rval.first_position_),
1084 num_valid_(rval.num_valid_),
1085 validator_(new DataPointerValidator(*this)),
1086 utilization_(std::move(rval.utilization_)),
1087 collector_(std::move(rval.collector_)),
1088 is_infinite_mode_(rval.is_infinite_mode_),
1089 resize_delta_(std::move(rval.resize_delta_)),
1090 address_map_(std::move(rval.address_map_)){
1091 rval.clk_ =
nullptr;
1092 rval.num_entries_ = 0;
1093 rval.data_pool_size_ = 0;
1094 rval.free_position_ =
nullptr;
1095 rval.first_position_ =
nullptr;
1096 rval.num_valid_ = 0;
1097 rval.utilization_ =
nullptr;
1098 rval.collector_ =
nullptr;
1099 validator_->validator_ = std::move(rval.validator_->validator_);
1101 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.
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.
void erase(uint32_t idx)
erase a position in the Buffer immediately.
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.
iterator erase(const const_iterator &entry)
erase the index at which the entry exists in the Buffer.
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.
reverse_iterator erase(const const_reverse_iterator &entry)
erase the index at which the entry exists in the Buffer.
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.
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.
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.