Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions tasks/denisov_a_ring/common/include/common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <string>
#include <tuple>
#include <vector>

#include "task/include/task.hpp"

namespace denisov_a_ring {

struct RingMessage {
int source = 0;
int destination = 0;
std::vector<int> data;
};

using InType = RingMessage;
using OutType = std::vector<int>;
using TestType = std::tuple<int, std::string>;
using BaseTask = ppc::task::Task<InType, OutType>;

} // namespace denisov_a_ring
9 changes: 9 additions & 0 deletions tasks/denisov_a_ring/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "Артём",
"group_number": "3823Б1ПР4",
"last_name": "Денисов",
"middle_name": "Андреевич",
"task_number": "2"
}
}
29 changes: 29 additions & 0 deletions tasks/denisov_a_ring/mpi/include/ops_mpi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <vector>

#include "denisov_a_ring/common/include/common.hpp"
#include "task/include/task.hpp"

namespace denisov_a_ring {

class RingTopologyMPI : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kMPI;
}

explicit RingTopologyMPI(const InType &in);

private:
bool ValidationImpl() override;
bool PreProcessingImpl() override;
bool RunImpl() override;
bool PostProcessingImpl() override;

void static SendVector(const std::vector<int> &data, int to_rank);
void static ReceiveVector(std::vector<int> &data, int from_rank);
void static BroadcastResult(std::vector<int> &output, int rank, int root);
};

} // namespace denisov_a_ring
118 changes: 118 additions & 0 deletions tasks/denisov_a_ring/mpi/src/ops_mpi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#include "denisov_a_ring/mpi/include/ops_mpi.hpp"

#include <mpi.h>

#include <vector>

#include "denisov_a_ring/common/include/common.hpp"

namespace denisov_a_ring {

RingTopologyMPI::RingTopologyMPI(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput().clear();
}

bool RingTopologyMPI::ValidationImpl() {
int world_size = 0;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);

const auto &in = GetInput();
if (in.source < 0 || in.source >= world_size) {
return false;
}

if (in.destination < 0 || in.destination >= world_size) {
return false;
}

return true;
}

bool RingTopologyMPI::PreProcessingImpl() {
GetOutput().clear();
return true;
}

bool RingTopologyMPI::RunImpl() {
int rank = 0;
int world_size = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);

const auto &in = GetInput();
int start_node = in.source;
int target_node = in.destination;

if (start_node == target_node) {
if (rank == start_node) {
GetOutput() = in.data;
}
BroadcastResult(GetOutput(), rank, start_node);
return true;
}

int next = (rank + 1) % world_size;
int prev = (rank - 1 + world_size) % world_size;

int total_steps = (target_node - start_node + world_size) % world_size;
int local_step = (rank - start_node + world_size) % world_size;

std::vector<int> local_buf;

if (local_step == 0) {
local_buf = in.data;
SendVector(local_buf, next);
} else if (local_step < total_steps) {
ReceiveVector(local_buf, prev);
SendVector(local_buf, next);
} else if (local_step == total_steps) {
ReceiveVector(local_buf, prev);
}

if (rank == target_node) {
GetOutput() = local_buf;
}

BroadcastResult(GetOutput(), rank, target_node);
return true;
}

bool RingTopologyMPI::PostProcessingImpl() {
return true;
}

void RingTopologyMPI::SendVector(const std::vector<int> &data, int to_rank) {
int count = static_cast<int>(data.size());
MPI_Send(&count, 1, MPI_INT, to_rank, 0, MPI_COMM_WORLD);

if (count > 0) {
MPI_Send(data.data(), count, MPI_INT, to_rank, 1, MPI_COMM_WORLD);
}
}

void RingTopologyMPI::ReceiveVector(std::vector<int> &data, int from_rank) {
int count = 0;
MPI_Recv(&count, 1, MPI_INT, from_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

data.resize(count);
if (count > 0) {
MPI_Recv(data.data(), count, MPI_INT, from_rank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
}

void RingTopologyMPI::BroadcastResult(std::vector<int> &out, int rank, int root) {
int size = (rank == root) ? static_cast<int>(out.size()) : 0;
MPI_Bcast(&size, 1, MPI_INT, root, MPI_COMM_WORLD);

if (rank != root) {
out.resize(size);
}

if (size > 0) {
MPI_Bcast(out.data(), size, MPI_INT, root, MPI_COMM_WORLD);
}
}

} // namespace denisov_a_ring
Loading
Loading