HW2: A validator added and small changes
This commit is contained in:
@@ -24,6 +24,9 @@
|
||||
#define CODE_VERSION BITONIC
|
||||
#endif
|
||||
|
||||
// Default Data size (in case -q <N> is not present)
|
||||
#define DEFAULT_DATA_SIZE (1 << 16)
|
||||
|
||||
/*!
|
||||
* Value type selection
|
||||
*
|
||||
@@ -42,10 +45,11 @@ using distValue_t = uint32_t;
|
||||
* Session option for each invocation of the executable
|
||||
*/
|
||||
struct session_t {
|
||||
size_t arraySize{0};
|
||||
bool ndebug{false};
|
||||
bool timing{false};
|
||||
bool verbose{false}; //!< Flag to enable verbose output to stdout
|
||||
size_t arraySize{DEFAULT_DATA_SIZE}; //!<
|
||||
bool validation{false}; //!< Request a full validation at the end, performed by process rank 0
|
||||
bool ndebug{false}; //!< Skips debug trap on DEBUG builds
|
||||
bool timing{false}; //!< Enable timing measurements and prints
|
||||
bool verbose{false}; //!< Flag to enable verbose output to stdout
|
||||
};
|
||||
|
||||
extern session_t session;
|
||||
|
||||
@@ -177,15 +177,15 @@ void fullSort(RangeT& data, bool ascending) noexcept {
|
||||
* @note
|
||||
* This is the core functionality. Use the elbowSort() function instead
|
||||
*
|
||||
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||
* @tparam CompT A Comparison type for binary operation comparisons
|
||||
* @tparam ShadowedDataT A Shadowed buffer type with random access iterator.
|
||||
* @tparam CompT A Comparison type for binary operation comparisons
|
||||
*
|
||||
* @param data [ShadowedT] The data to sort
|
||||
* @param ascending [bool] Flag to indicate the sorting order
|
||||
* @param comp [CompT] The binary operator object
|
||||
* @param data [ShadowedDataT] The data to sort
|
||||
* @param ascending [bool] Flag to indicate the sorting order
|
||||
* @param comp [CompT] The binary operator object
|
||||
*/
|
||||
template<typename ShadowedT, typename CompT>
|
||||
void elbowSortCore(ShadowedT& data, bool ascending, CompT comp) noexcept {
|
||||
template<typename ShadowedDataT, typename CompT>
|
||||
void elbowSortCore(ShadowedDataT& data, bool ascending, CompT comp) noexcept {
|
||||
auto& active = data.getActive(); // Get the source vector (the data to sort)
|
||||
auto& shadow = data.getShadow(); // Get the target vector (the sorted data)
|
||||
|
||||
@@ -215,13 +215,13 @@ void elbowSortCore(ShadowedT& data, bool ascending, CompT comp) noexcept {
|
||||
/*!
|
||||
* Sort a shadowed buffer using the "elbow sort" algorithm.
|
||||
*
|
||||
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||
* @tparam ShadowedDataT A Shadowed buffer type with random access iterator.
|
||||
*
|
||||
* @param data [ShadowedT] The data to sort
|
||||
* @param ascending [bool] Flag to indicate the sorting order
|
||||
* @param data [ShadowedDataT] The data to sort
|
||||
* @param ascending [bool] Flag to indicate the sorting order
|
||||
*/
|
||||
template<typename ShadowedT>
|
||||
void elbowSort(ShadowedT& data, bool ascending) noexcept {
|
||||
template<typename ShadowedDataT>
|
||||
void elbowSort(ShadowedDataT& data, bool ascending) noexcept {
|
||||
if (ascending)
|
||||
elbowSortCore(data, ascending, std::less<>());
|
||||
else
|
||||
@@ -261,13 +261,14 @@ void minmax(RangeT& local, const RangeT& remote, bool keepSmall) noexcept {
|
||||
* @note
|
||||
* Each MPI process should run an instance of this function.
|
||||
*
|
||||
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||
* @tparam ShadowedDataT A Shadowed buffer type with random access iterator.
|
||||
*
|
||||
* @param data [ShadowedT] The local to MPI process data to sort
|
||||
* @param Processes [mpi_id_t] The total number of MPI processes
|
||||
* @param data [ShadowedDataT] The local to MPI process data to sort
|
||||
* @param Processes [mpi_id_t] The total number of MPI processes
|
||||
* @param rank [mpi_id_t] The current process id
|
||||
*/
|
||||
template<typename ShadowedT>
|
||||
void distBubbletonic(ShadowedT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
template<typename ShadowedDataT>
|
||||
void distBubbletonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
// Initially sort to create a half part of a bitonic sequence
|
||||
fullSort(data, ascending<SortMode::Bubbletonic>(rank, 0));
|
||||
|
||||
@@ -279,7 +280,7 @@ void distBubbletonic(ShadowedT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
if ( isActive(rank, Processes) &&
|
||||
isActive(part, Processes) ) {
|
||||
// Exchange with partner, keep nim-or-max and sort - O(N)
|
||||
mpi.exchange(part, data.getActive(), data.getShadow(), step);
|
||||
mpi.exchange(data.getActive(), data.getShadow(), part, step);
|
||||
minmax(data.getActive(), data.getShadow(), ks);
|
||||
elbowSort(data, ascending<SortMode::Bubbletonic>(rank, Processes));
|
||||
}
|
||||
@@ -298,13 +299,14 @@ void distBubbletonic(ShadowedT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
* @note
|
||||
* Each MPI process should run an instance of this function.
|
||||
*
|
||||
* @tparam ShadowedT A Shadowed buffer type with random access iterator.
|
||||
* @tparam ShadowedDataT A Shadowed buffer type with random access iterator.
|
||||
*
|
||||
* @param data [ShadowedT] The local to MPI process data to sort
|
||||
* @param Processes [mpi_id_t] The total number of MPI processes
|
||||
* @param data [ShadowedDataT] The local to MPI process data to sort
|
||||
* @param Processes [mpi_id_t] The total number of MPI processes
|
||||
* @param rank [mpi_id_t] The current process id
|
||||
*/
|
||||
template<typename ShadowedT>
|
||||
void distBitonic(ShadowedT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
template<typename ShadowedDataT>
|
||||
void distBitonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
// Initially sort to create a half part of a bitonic sequence
|
||||
fullSort(data, ascending<SortMode::Bitonic>(rank, 0));
|
||||
|
||||
@@ -317,7 +319,7 @@ void distBitonic(ShadowedT& data, mpi_id_t Processes, mpi_id_t rank) {
|
||||
auto part = partner<SortMode::Bitonic>(rank, step);
|
||||
auto ks = keepSmall<SortMode::Bitonic>(rank, part, depth);
|
||||
// Exchange with partner, keep nim-or-max
|
||||
mpi.exchange(part, data.getActive(), data.getShadow(), (depth << 8) | step);
|
||||
mpi.exchange(data.getActive(), data.getShadow(), part, (depth << 8) | step);
|
||||
minmax(data.getActive(), data.getShadow(), ks);
|
||||
}
|
||||
// sort - O(N)
|
||||
|
||||
@@ -49,9 +49,9 @@ struct MPI_t {
|
||||
* Initializes the MPI environment, must called from each process
|
||||
*
|
||||
* @param argc [int*] POINTER to main's argc argument
|
||||
* @param argv [car***] POINTER to main's argv argument
|
||||
* @param argv [char***] POINTER to main's argv argument
|
||||
*/
|
||||
void init(int *argc, char ***argv) {
|
||||
void init(int* argc, char*** argv) {
|
||||
// Initialize the MPI environment
|
||||
int err;
|
||||
if ((err = MPI_Init(argc, argv)) != MPI_SUCCESS)
|
||||
@@ -84,13 +84,13 @@ struct MPI_t {
|
||||
*
|
||||
* @tparam T The inner valur type used in buffer
|
||||
*
|
||||
* @param partner [mpi_id_t] The partner for the exchange
|
||||
* @param send_data [std::vector<T>] Reference to local data to send
|
||||
* @param recv_data [std::vector<T>] Reference to buffer to receive data from partner
|
||||
* @param partner [mpi_id_t] The partner for the exchange
|
||||
* @param tag [int] The tag to use for the MPI communication
|
||||
*/
|
||||
template<typename T>
|
||||
void exchange(ID_t partner, const std::vector<T>& send_data, std::vector<T>& recv_data, int tag) {
|
||||
void exchange(const std::vector<T>& send_data, std::vector<T>& recv_data, ID_t partner, int tag) {
|
||||
using namespace std::string_literals;
|
||||
|
||||
MPI_Datatype datatype = MPI_TypeMapper<T>::getType();
|
||||
@@ -110,6 +110,11 @@ struct MPI_t {
|
||||
[[nodiscard]] ID_t size() const noexcept { return size_; }
|
||||
[[nodiscard]] const std::string& name() const noexcept { return name_; }
|
||||
|
||||
// Mutators
|
||||
ID_t rank(ID_t rank) noexcept { return rank_ = rank; }
|
||||
ID_t size(ID_t size) noexcept { return size_ = size; }
|
||||
std::string& name(const std::string& name) noexcept { return name_ = name; }
|
||||
|
||||
/*!
|
||||
* Finalized the MPI
|
||||
*/
|
||||
@@ -130,7 +135,7 @@ struct MPI_t {
|
||||
// Local functionality
|
||||
private:
|
||||
/*!
|
||||
* Throw exception helper. It bundles the prefix with the MPI error string retrieved by
|
||||
* Throw exception helper. It bundles the prefix msg with the MPI error string retrieved by
|
||||
* MPI API.
|
||||
*
|
||||
* @param err The MPI error code
|
||||
@@ -143,11 +148,7 @@ private:
|
||||
throw std::runtime_error(prefixMsg + std::string (err_msg) + '\n');
|
||||
}
|
||||
|
||||
#if !defined TESTING
|
||||
private:
|
||||
#else
|
||||
public:
|
||||
#endif
|
||||
ID_t rank_{}; //!< MPI rank of the process
|
||||
ID_t size_{}; //!< MPI total size of the execution
|
||||
std::string name_{}; //!< The name of the local machine
|
||||
@@ -172,10 +173,10 @@ using mpi_id_t = MPI_t<>::ID_t;
|
||||
template <typename Value_t>
|
||||
struct ShadowedVec_t {
|
||||
// STL requirements
|
||||
using value_type = Value_t;
|
||||
using iterator = typename std::vector<Value_t>::iterator;
|
||||
using value_type = Value_t;
|
||||
using iterator = typename std::vector<Value_t>::iterator;
|
||||
using const_iterator = typename std::vector<Value_t>::const_iterator;
|
||||
using size_type = typename std::vector<Value_t>::size_type;
|
||||
using size_type = typename std::vector<Value_t>::size_type;
|
||||
|
||||
// Default constructor
|
||||
ShadowedVec_t() = default;
|
||||
@@ -214,17 +215,15 @@ struct ShadowedVec_t {
|
||||
}
|
||||
|
||||
// Type accessors
|
||||
const std::vector<Value_t>& getNorth() const { return North; }
|
||||
const std::vector<Value_t>& getSouth() const { return South; }
|
||||
std::vector<Value_t>& getActive() { return (active == north) ? North : South; }
|
||||
std::vector<Value_t>& getShadow() { return (active == north) ? South : North; }
|
||||
const std::vector<Value_t>& getActive() const { return (active == north) ? North : South; }
|
||||
const std::vector<Value_t>& getShadow() const { return (active == north) ? South : North; }
|
||||
|
||||
// Switching vectors
|
||||
// Swap vectors
|
||||
void switch_active() { active = (active == north) ? south : north; }
|
||||
|
||||
// Dispatch to active vector functionality
|
||||
// Dispatch vector functionality to active vector
|
||||
Value_t& operator[](size_type index) { return getActive()[index]; }
|
||||
const Value_t& operator[](size_type index) const { return getActive()[index]; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user