Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into map_v2
Browse files Browse the repository at this point in the history
  • Loading branch information
Knute Lingaard authored and Knute Lingaard committed Nov 2, 2023
2 parents 2beb569 + 16bc957 commit 0fc8a9b
Show file tree
Hide file tree
Showing 9 changed files with 500 additions and 30 deletions.
16 changes: 16 additions & 0 deletions sparta/doc/sparta_docs/modeling.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@
sparta::StartupEvent | \copybrief sparta::StartupEvent  
sparta::UniqueEvent | \copybrief sparta::UniqueEvent  

================================================================================
\subsection sparta_resources Sparta Resources (sparta/resources)

Class | Brief Description
--------------------------- | ------------------
sparta::Array | \copybrief sparta::Array  
sparta::Buffer | \copybrief sparta::Buffer  
sparta::CircularBuffer | \copybrief sparta::CircularBuffer  
sparta::FrontArray | \copybrief sparta::FrontArray  
sparta::Pipe | \copybrief sparta::Pipe  
sparta::Pipeline | \copybrief sparta::Pipeline  
sparta::PriorityQueue | \copybrief sparta::PriorityQueue  
sparta::Queue | \copybrief sparta::Queue  
sparta::Scoreboard | \copybrief sparta::Scoreboard  
sparta::SharedData | \copybrief sparta::SharedData  

================================================================================
\subsection ports_overview Sparta Ports API (sparta/ports)

Expand Down
188 changes: 188 additions & 0 deletions sparta/sparta/resources/PriorityQueue.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// <PriorityQueue.hpp> -*- C++ -*-


/**
* \file PriorityQueue.hpp
* \brief Defines a Priority queue similar to STL's, but with more functionality
*/

#pragma once

#include <list>
#include <algorithm>
#include <functional>

#include "sparta/utils/SpartaAssert.hpp"
#include "sparta/utils/FastList.hpp"

namespace sparta
{

/**
* \class PriorityQueue
* \brief A data structure that allows pushing/emplacing into it
* with a given sorter
* \tparam DataT The data to be contained and sorted
* \tparam SortingAlgorithmT The sorting algorithm to use
* \tparam bounded_cnt The max number of elements in this PriorityQueue
*
* The PriorityQueue can be used by picking algorithms in a model
* where more than one entry of a block is ready (for whatever
* reason) and the model needs to know which one to "pick" for the
* next operation.
*
* The queue defines a less-than type of sorter by default, but
* allows the modeler to define an operator object that can
* override the behavior.
*
* In addition, entries in the queue can be removed (even in the
* middle). This is handy for items in the queue that are no
* longer participating in the priority.
*
* Finally, the queue supports a basic override to the order,
* allowing a "high priority" DataT object to be pushed to the
* front, even if that object doesn't conform to the ordering
* rules.
*
* If the template parameter bounded_cnt is non-zero, the
* PriorityQueue will be bounded to an upper limit of
* bounded_cnt. This also improves the performance of the
* PriorityQueue (uses sparta::utils::FastList).
*
*/
template <class DataT,
class SortingAlgorithmT = std::less<DataT>,
size_t bounded_cnt=0>
class PriorityQueue
{
private:
using PQueueType =
typename std::conditional<bounded_cnt == 0,
std::list<DataT>,
utils::FastList<DataT>>::type;

public:

// For collection
using size_type = size_t;
using iterator = typename PQueueType::iterator;
using const_iterator = typename PQueueType::const_iterator;

/**
* \brief Create a priority queue with a default instance of the
* sorting algorithm
*/
PriorityQueue() :
priority_items_(bounded_cnt)
{}

/**
* \brief Create a priority queue with a specific instance of the
* sorting algorithm
* \param sort_alg Reference to the sorting algorithm instance
*/
PriorityQueue(const SortingAlgorithmT & sort_alg) :
priority_items_(bounded_cnt),
sort_alg_(sort_alg)
{}

/**
* \brief Inserts the data item into the list using the
* sorting alg. Stops at the first insertion.
* \param data The data to insert
*/
void insert(const DataT & data)
{
const auto eit = priority_items_.end();
for(auto it = priority_items_.begin(); it != eit; ++it)
{
if(sort_alg_(data, *it)) {
priority_items_.insert(it, data);
return;
}
}
priority_items_.emplace_back(data);
}

//! Get the number of items in the queue
size_t size() const {
return priority_items_.size();
}

//! Is the queue empty?
bool empty() const {
return priority_items_.empty();
}

//! Get the first element in the queue
const DataT & top() const {
sparta_assert(false == empty(), "Grabbing top from an empty queue");
return priority_items_.front();
}

//! Get the last element (lowest priority) in the queue
const DataT & back() const {
sparta_assert(false == empty(), "Grabbing back from an empty queue");
return priority_items_.back();
}

//! Pop the front of the queue (highest priority)
void pop() {
sparta_assert(false == empty(), "Popping on an empty priority queue");
priority_items_.pop_front();
}

//! Clear the entire queue
void clear() {
priority_items_.clear();
}

//! Remove the item from the queue
void remove(const DataT & data) {
priority_items_.remove(data);
}

//! Erase the item from the queue (const_iterator/iterator)
void erase(const const_iterator & it) {
priority_items_.erase(it);
}

/**
* \brief Force a data entry to the front of the queue
* \param data Reference to the data object forced to the
* front of the queue
*
* Push the data item to the front of the queue, bypassing the
* internal sorting algorithm. This is handy if multiple
* items from multiple directions should be prioritized, but a
* last-minute item, which normally is a low-priority item,
* _must be handled_ immediately.
*/
void forceFront(const DataT & data) {
priority_items_.emplace_front(data);
}

/*! \defgroup iteration Iteration Support */
/**@{*/
//! Iterator to beginning of the queue -- highest priority
iterator begin() { return priority_items_.begin(); }

//! Const Iterator to beginning of the queue -- highest priority
const_iterator begin() const { return priority_items_.begin(); }

//! Iterator to end of the queue -- end priority
iterator end() { return priority_items_.end(); }

//! Const Iterator to end of the queue -- end priority
const_iterator end() const { return priority_items_.end(); }
/**@}*/

private:

//! The internal queue
PQueueType priority_items_;

//! Copy of the sorting algorithm
SortingAlgorithmT sort_alg_;
};
}
20 changes: 14 additions & 6 deletions sparta/sparta/resources/Scoreboard.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
// <Scoreboard.hpp> -*- C++ -*-

/**
* \file Scoreboard.hpp
* \brief Class used to track operand dependencies (timed) between units
*/

#pragma once

#include <vector>
Expand All @@ -17,17 +24,18 @@ namespace sparta

/**
* \class Scoreboard
* \brief Class used to track operand dependencies (timed) between units
*
* The Scoreboard of the model simply keeps track of the readiness
* of phyiscal registers in the OOO core. There are two parts to the SB:
*
* # The Scoreboard or "master" for each register file type (GPU,
* FPR, Vector, etc). Typically a Rename block is responsible
* for setting/clearing the SB readiness.
* -# The Scoreboard or "master" for each register file type (GPU,
* FPR, Vector, etc). Typically a Rename block is responsible
* for setting/clearing the SB readiness.
*
* # The ScoreboardView is created by a Scheduling/Execution block
* and is used to determine if an instruction is ready for
* execution (all operands ready)
* -# The ScoreboardView is created by a Scheduling/Execution block
* and is used to determine if an instruction is ready for
* execution (all operands ready)
*
*/
class Scoreboard : public sparta::Unit
Expand Down
38 changes: 27 additions & 11 deletions sparta/sparta/utils/FastList.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#include <iterator>
#include <cinttypes>
#include <cassert>
#include <type_traits>

#include "sparta/utils/IteratorTraits.hpp"
#include "sparta/utils/SpartaAssert.hpp"

namespace sparta::utils
Expand All @@ -40,7 +42,7 @@ namespace sparta::utils
* - The API isn't as complete as typical STL container types
*
*/
template <class T>
template <class DataT>
class FastList
{
struct Node
Expand All @@ -60,7 +62,7 @@ namespace sparta::utils
// Stores the memory for an instance of 'T'.
// Use placement new to construct the object and
// manually invoke its dtor as necessary.
std::aligned_storage_t<sizeof(T), alignof(T)> type_storage;
std::aligned_storage_t<sizeof(DataT), alignof(DataT)> type_storage;

Node(NodeIdx _index) :
index(_index)
Expand All @@ -81,15 +83,15 @@ namespace sparta::utils
}

public:
using value_type = T; //!< Handy using
using value_type = DataT; //!< Handy using

/**
* \class NodeIterator
* \brief The internal iterator type of FastList. Use FastList<T>::[const_]iterator instead
*
*/
template<bool is_const = true>
class NodeIterator // : public std::iterator<std::intput_iterator_tag, Node>
class NodeIterator : public sparta::utils::IteratorTraits<std::forward_iterator_tag, value_type>
{
typedef std::conditional_t<is_const, const value_type &, value_type &> RefIteratorType;
typedef std::conditional_t<is_const, const value_type *, value_type *> PtrIteratorType;
Expand Down Expand Up @@ -170,7 +172,7 @@ namespace sparta::utils
NodeIterator& operator=( NodeIterator &&rhs) = default;

private:
friend class FastList<T>;
friend class FastList<DataT>;

NodeIterator(FastListPtrType flist, typename Node::NodeIdx node_idx) :
flist_(flist),
Expand Down Expand Up @@ -217,9 +219,16 @@ namespace sparta::utils

//! Obtain an end iterator
iterator end() { return iterator(this, -1); }

//! Obtain an end const_iterator
const_iterator end() const { return const_iterator(this, -1); }

//! Get the front of the fast list non-const
DataT & front() { return *begin(); }

//! Get the front of the fast list, const
const DataT & front() const { return *begin(); }

//! \return Is this container empty?
bool empty() const { return size_ == 0; }

Expand All @@ -246,7 +255,7 @@ namespace sparta::utils
{
const auto node_idx = entry.getIndex();
auto & node_to_erase = nodes_[node_idx];
reinterpret_cast<T*>(&node_to_erase.type_storage)->~T();
reinterpret_cast<DataT*>(&node_to_erase.type_storage)->~DataT();
int next_elem = -1;

if(first_node_ == node_idx) {
Expand Down Expand Up @@ -295,7 +304,7 @@ namespace sparta::utils

auto & new_node = nodes_[free_head_];
free_head_ = new_node.next;
new (&new_node.type_storage) T(args...);
new (&new_node.type_storage) DataT(args...);
// Update pointers. Start with a clean slate
new_node.next = -1;
new_node.prev = -1;
Expand Down Expand Up @@ -332,7 +341,7 @@ namespace sparta::utils

auto & new_node = nodes_[free_head_];
free_head_ = new_node.next;
new (&new_node.type_storage) T(args...);
new (&new_node.type_storage) DataT(args...);

// Update pointers. Start with a clean slate
new_node.next = -1;
Expand Down Expand Up @@ -364,7 +373,7 @@ namespace sparta::utils

auto & new_node = nodes_[free_head_];
free_head_ = new_node.next;
new (&new_node.type_storage) T(args...);
new (&new_node.type_storage) DataT(args...);

// Update pointers. Start with a clean slate
new_node.next = -1;
Expand All @@ -384,6 +393,13 @@ namespace sparta::utils
return iterator(this, new_node.index);
}

//! Insert an element at a specific place in the list. Really
//! just an alias for emplace
template<class ...ArgsT>
iterator insert(const const_iterator & pos, ArgsT&&...args) {
return emplace(pos, args...);
}

//! Pop the last element off of the list
void pop_back() {
sparta_assert(last_node_ != -1,
Expand All @@ -401,7 +417,7 @@ namespace sparta::utils
private:

// Friendly printer
friend std::ostream & operator<<(std::ostream & os, const FastList<T> & fl)
friend std::ostream & operator<<(std::ostream & os, const FastList<DataT> & fl)
{
int next_node = fl.first_node_;
if(next_node == -1) {
Expand All @@ -412,7 +428,7 @@ namespace sparta::utils
do
{
const auto & n = fl.nodes_[next_node];
os << index << " elem=" << *reinterpret_cast<const T*>(&n.type_storage)
os << index << " elem=" << *reinterpret_cast<const DataT*>(&n.type_storage)
<< " n.next=" << n.next
<< " n.prev=" << n.prev << std::endl;
next_node = n.next;
Expand Down
Loading

0 comments on commit 0fc8a9b

Please sign in to comment.