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)];
104 DataPointer(DataPointer &&orig)
noexcept {
105 ::memcpy(&object_memory_, &orig.object_memory_,
sizeof(object_memory_));
106 data =
reinterpret_cast<value_type*
>(&object_memory_);
110 DataPointer(
const DataPointer &) =
delete;
113 void allocate(U && dat) {
114 data =
new (&object_memory_) value_type(std::forward<U>(dat));
117 value_type * data =
nullptr;
118 DataPointer* next_free =
nullptr;
119 uint32_t physical_idx = 0;
122 struct DataPointerValidator;
138 template <
bool is_const_iterator = true>
142 friend class Buffer<value_type>;
143 typedef typename std::conditional<is_const_iterator,
144 const value_type &, value_type &>::type DataReferenceType;
145 typedef typename std::conditional<is_const_iterator,
147 typedef typename std::conditional<is_const_iterator,
148 const DataPointer *, DataPointer *>::type DataPointerType;
155 uint32_t getIndex_()
const {
156 if(buffer_entry_ ==
nullptr) {
157 return attached_buffer_->capacity();
159 return buffer_entry_->physical_idx;
163 BufferPointerType attached_buffer_ =
nullptr;
166 DataPointerType buffer_entry_ =
nullptr;
173 BufferIterator(BufferPointerType buffer, DataPointerType entry) :
174 attached_buffer_(buffer),
184 BufferIterator() =
default;
190 BufferIterator(
const BufferIterator<false> & iter) :
191 attached_buffer_(iter.attached_buffer_),
192 buffer_entry_(iter.buffer_entry_)
199 BufferIterator(
const BufferIterator<true> & iter) :
200 attached_buffer_(iter.attached_buffer_),
201 buffer_entry_(iter.buffer_entry_)
207 BufferIterator& operator=(
const BufferIterator&) =
default;
210 bool operator<(
const BufferIterator& rhs)
const
213 "Cannot compare BufferIterators created by different buffers.");
214 return getIndex_() < rhs.getIndex_();
218 bool operator>(
const BufferIterator& rhs)
const
221 "Cannot compare BufferIterators created by different buffers.");
222 return getIndex_() > rhs.getIndex_();
226 bool operator==(
const BufferIterator& rhs)
const
229 "Cannot compare BufferIterators created by different buffers.");
230 return (buffer_entry_ == rhs.buffer_entry_);
234 bool operator!=(
const BufferIterator& rhs)
const
237 "Cannot compare BufferIterators created by different buffers.");
238 return !operator==(rhs);
245 if(buffer_entry_ !=
nullptr) {
246 return attached_buffer_->validator_->isValid(buffer_entry_);
252 DataReferenceType operator* ()
const {
254 "The iterator is not attached to a buffer. Was it initialized?");
255 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
256 return *(buffer_entry_->data);
260 value_type * operator -> () {
262 "The iterator is not attached to a buffer. Was it initialized?");
263 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
264 return buffer_entry_->data;
267 value_type
const * operator -> ()
const {
269 "The iterator is not attached to a buffer. Was it initialized?");
270 sparta_assert(isValid(),
"Iterator is not valid for dereferencing");
271 return buffer_entry_->data;
276 BufferIterator & operator++() {
278 "The iterator is not attached to a buffer. Was it initialized?");
279 sparta_assert(isValid(),
"Incrementing an iterator that is not valid");
280 const uint32_t idx = buffer_entry_->physical_idx + 1;
281 if(attached_buffer_->isValid(idx)) {
282 buffer_entry_ = attached_buffer_->buffer_map_[idx];
285 buffer_entry_ =
nullptr;
291 BufferIterator operator++ (
int) {
292 BufferIterator buf_iter(*
this);
298 BufferIterator & operator-- ()
300 sparta_assert(attached_buffer_,
"The iterator is not attached to a buffer. Was it initialized?");
302 uint32_t idx = buffer_entry_->physical_idx;
304 if(attached_buffer_->isValid(idx)) {
305 buffer_entry_ = attached_buffer_->buffer_map_[idx];
308 sparta_assert(idx < attached_buffer_->
capacity(),
"Decrementing the iterator results in buffer underrun");
309 buffer_entry_ =
nullptr;
312 else if (attached_buffer_->size()) {
313 buffer_entry_ = attached_buffer_->buffer_map_[attached_buffer_->size()-1];
319 BufferIterator operator-- (
int) {
320 BufferIterator buf_iter(*
this);
329 friend class BufferIterator<true>;
384 const uint32_t num_entries,
426 const value_type &
read(uint32_t idx)
const {
428 return *(buffer_map_[idx]->data);
437 return read(entry.getIndex_());
446 return read(std::prev(entry.base()));
457 return *(buffer_map_[idx]->data);
465 return access(entry.getIndex_());
473 return access(std::prev(entry.base()));
483 return *(buffer_map_[num_valid_ - 1]->data);
523 return push_backImpl_(dat);
537 return push_backImpl_(std::move(dat));
560 return insertImpl_(idx, dat);
583 return insertImpl_(idx, std::move(dat));
589 return insert(entry.getIndex_(), dat);
595 return insert(entry.getIndex_(), std::move(dat));
601 return insert(entry.base().getIndex_(), dat);
607 return insert(entry.base().getIndex_(), std::move(dat));
628 "Cannot erase an index that is not already valid");
634 DataPointer* oldFree = free_position_;
635 free_position_ = buffer_map_[idx];
636 free_position_->data->~value_type();
637 free_position_->next_free = oldFree;
640 validator_->detachDataPointer(free_position_);
644 const uint32_t top_idx_of_buffer = num_valid_ - 1;
645 while(idx < top_idx_of_buffer)
649 buffer_map_[idx] = buffer_map_[idx + 1];
650 buffer_map_[idx]->physical_idx = idx;
653 address_map_[idx] = address_map_[idx + 1];
658 buffer_map_[top_idx_of_buffer] =
nullptr;
661 address_map_.erase(top_idx_of_buffer);
665 updateUtilizationCounters_();
675 "Cannot erase an entry created by another Buffer");
677 erase(entry.getIndex_());
678 return {
this, buffer_map_[entry.getIndex_()]};
697 std::for_each(buffer_map_.begin(), buffer_map_.end(),
701 map_entry->data->~value_type();
704 std::fill(buffer_map_.begin(), buffer_map_.end(),
nullptr);
705 for(uint32_t i = 0; i < data_pool_size_ - 1; ++i) {
706 data_pool_[i].next_free = &data_pool_[i + 1];
708 data_pool_[data_pool_size_ - 1].next_free = &data_pool_[data_pool_size_ - 1];
709 free_position_ = &data_pool_[0];
710 first_position_ = &data_pool_[0];
712 address_map_.clear();
713 updateUtilizationCounters_();
722 return num_valid_ == 0;
747 return iterator(
this, buffer_map_[0]);
810 is_infinite_mode_ =
true;
811 resize_delta_ = resize_delta;
816 typedef std::vector<DataPointer> DataPool;
817 typedef std::vector<DataPointer*> PointerList;
819 struct DataPointerValidator
823 const DataPool * data_pool_;
824 std::vector<uint32_t> validator_;
825 size_type getIndex_(
const DataPointer * dp)
const {
826 auto i = (dp - &(*data_pool_)[0]);
827 return static_cast<size_type
>(i);
830 DataPointerValidator(
const Buffer &b):
831 data_pool_(&b.data_pool_),
832 validator_(b.num_entries_, 0)
835 void attachDataPointer(
const DataPointer* dp){
836 validator_[getIndex_(dp)] = 1;
839 bool isValid(
const DataPointer * dp)
const {
840 return bool(validator_[getIndex_(dp)]);
843 void detachDataPointer(DataPointer * dp) {
844 validator_[getIndex_(dp)] = 0;
848 std::fill(validator_.begin(), validator_.end(), 0);
856 void resizeIteratorValidator(
const uint32_t resize_delta,
857 const DataPool & data_pool) {
858 validator_.resize(validator_.capacity() + resize_delta);
859 data_pool_ = &data_pool;
863 void updateUtilizationCounters_() {
866 utilization_->setValue(num_valid_);
876 void resizeInternalContainers_() {
880 "The Buffer class must be in Infinite-Mode in order to resize itself.");
888 buffer_map_.resize(buffer_map_.capacity() + resize_delta_);
891 num_entries_ = buffer_map_.capacity();
894 data_pool_.resize(num_entries_ * 2);
897 data_pool_size_ = data_pool_.capacity();
902 for(uint32_t i = 0; i < data_pool_size_ - 1; ++i) {
903 data_pool_[i].next_free = &data_pool_[i + 1];
907 data_pool_[data_pool_size_ - 1].next_free = &data_pool_[data_pool_size_ - 1];
910 first_position_ = &data_pool_[0];
914 free_position_ = &data_pool_[num_valid_];
917 for(uint32_t i = 0; i < num_valid_; ++i) {
918 buffer_map_[i] = &data_pool_[address_map_[i]];
922 validator_->resizeIteratorValidator(resize_delta_, data_pool_);
926 iterator push_backImpl_(U&& dat)
931 resizeInternalContainers_();
935 free_position_->allocate(std::forward<U>(dat));
936 free_position_->physical_idx = num_valid_;
939 iterator entry(
this, free_position_);
943 buffer_map_[num_valid_] = free_position_;
948 address_map_[num_valid_] =
949 static_cast<uint32_t
>(free_position_ - &data_pool_[0]);
951 validator_->attachDataPointer(free_position_);
953 free_position_ = free_position_->next_free;
954 updateUtilizationCounters_();
960 iterator insertImpl_(uint32_t idx, U&& dat)
964 resizeInternalContainers_();
966 sparta_assert(numFree(),
"Buffer '" << getName() <<
"' exhausted");
968 <<
"': Cannot insert before a non valid index");
970 free_position_->allocate(std::forward<U>(dat));
971 free_position_->physical_idx = idx;
974 validator_->attachDataPointer(free_position_);
977 iterator entry(
this, free_position_);
980 uint32_t i = num_valid_;
984 buffer_map_[i] = buffer_map_[i - 1];
985 buffer_map_[i]->physical_idx = i ;
988 address_map_[i] = address_map_[i - 1];
992 buffer_map_[idx] = free_position_;
997 address_map_[num_valid_] =
998 static_cast<uint32_t
>(free_position_ - &data_pool_[0]);
1000 free_position_ = free_position_->next_free;
1001 updateUtilizationCounters_();
1006 const Clock * clk_ =
nullptr;
1007 size_type num_entries_ = 0;
1008 PointerList buffer_map_;
1009 size_type data_pool_size_ = 0;
1010 DataPool data_pool_;
1013 DataPointer* free_position_ =
nullptr;
1014 DataPointer* first_position_ =
nullptr;
1015 size_type num_valid_ = 0;
1016 std::unique_ptr<DataPointerValidator> validator_;
1020 std::unique_ptr<sparta::CycleHistogramStandalone> utilization_;
1024 std::unique_ptr<collection::IterableCollector<Buffer<value_type> > > collector_;
1028 bool is_infinite_mode_ {
false};
1035 std::unordered_map<uint32_t, uint32_t> address_map_;
1040 template<
class DataT>
1042 uint32_t num_entries,
1051 num_entries_(num_entries),
1052 data_pool_size_(num_entries* 2)
1054 if((num_entries > 0) && statset)
1057 name_ +
"_utilization",
1058 name_ +
" occupancy histogram",
1059 0, num_entries, 1, 0,
1066 buffer_map_.resize(num_entries_);
1067 data_pool_.resize(data_pool_size_);
1070 validator_.reset(
new DataPointerValidator(*
this));
1075 template<
typename DataT>
1077 name_(std::move(rval.name_)),
1079 num_entries_(rval.num_entries_),
1080 buffer_map_(std::move(rval.buffer_map_)),
1081 data_pool_size_(rval.data_pool_size_),
1082 data_pool_(std::move(rval.data_pool_)),
1083 free_position_(rval.free_position_),
1084 first_position_(rval.first_position_),
1085 num_valid_(rval.num_valid_),
1086 validator_(new DataPointerValidator(*this)),
1087 utilization_(std::move(rval.utilization_)),
1088 collector_(std::move(rval.collector_)),
1089 is_infinite_mode_(rval.is_infinite_mode_),
1090 resize_delta_(std::move(rval.resize_delta_)),
1091 address_map_(std::move(rval.address_map_)){
1092 rval.clk_ =
nullptr;
1093 rval.num_entries_ = 0;
1094 rval.data_pool_size_ = 0;
1095 rval.free_position_ =
nullptr;
1096 rval.first_position_ =
nullptr;
1097 rval.num_valid_ = 0;
1098 rval.utilization_ =
nullptr;
1099 rval.collector_ =
nullptr;
1100 validator_->validator_ = std::move(rval.validator_->validator_);
1102 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.
std::reverse_iterator< iterator > reverse_iterator
Typedef for constant reverse iterator.
void clear()
Empty the contents of the Buffer.
size_type numFree() const
Return the number of free entries.
std::reverse_iterator< const_iterator > const_reverse_iterator
Typedef for regular reverse iterator.
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.
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.
BufferIterator< true > const_iterator
Typedef for constant iterator.
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.
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.
BufferIterator< false > iterator
Typedef for regular iterator.
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.
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.
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.