diff --git a/lab10/jacobi/comp.py b/lab10/jacobi/comp.py new file mode 100644 index 0000000..133471a --- /dev/null +++ b/lab10/jacobi/comp.py @@ -0,0 +1,28 @@ +import csv +import math + +def compare_csv(file1, file2): + with open(file1, newline='') as f1, open(file2, newline='') as f2: + reader1 = list(csv.reader(f1)) + reader2 = list(csv.reader(f2)) + + if len(reader1) != len(reader2): + print(f"Unterschiedliche Zeilenzahl: {len(reader1)} vs {len(reader2)}") + return + + for row_idx, (row1, row2) in enumerate(zip(reader1, reader2), start=1): + if len(row1) != len(row2): + print(f"Zeile {row_idx}: unterschiedliche Spaltenanzahl") + continue + for col_idx, (cell1, cell2) in enumerate(zip(row1, row2), start=1): + try: + if not math.isclose(float(cell1), float(cell2), abs_tol=1e-7): + print(f"Unterschied in Zeile {row_idx}, Spalte {col_idx}: {cell1} ≠ {cell2} diff: {abs(float(cell1) - float(cell2))}") + except ValueError: + # print(f"{cell1}: {cell2}") + pass + + +if __name__ == "__main__": + compare_csv("result_parallel.asc", "result_serial.asc") + diff --git a/lab10/jacobi/creator.py b/lab10/jacobi/creator.py new file mode 100644 index 0000000..c8fe151 --- /dev/null +++ b/lab10/jacobi/creator.py @@ -0,0 +1,32 @@ +import math +import subprocess + +core_counts = [1, 2, 4, 6, 8, 12, 16, 18, 24, 32, 36, 48] +cores_per_node = 12 +max_nodes = 4 + +for y in core_counts: + x = math.ceil(y / cores_per_node) + if x > max_nodes: + print(f"Skipping {y} cores: requires more than {max_nodes} nodes.") + continue + + filename = f"slurm_{y}.sh" + script = f"""#!/bin/bash +#SBATCH --job-name=mpi_g5_{y} +#SBATCH --output=jacobi_{y}.txt +#SBATCH --nodes={x} +#SBATCH --ntasks={y} + +srun --mpi=pmix ./jacobi +""" + + with open(filename, "w") as f: + f.write(script) + + # Submit the job + result = subprocess.run(["sbatch", filename], capture_output=True, text=True) + if result.returncode == 0: + print(f"Submitted {filename}: {result.stdout.strip()}") + else: + print(f"Failed to submit {filename}: {result.stderr.strip()}") diff --git a/lab10/jacobi/do_all.sh b/lab10/jacobi/do_all.sh new file mode 100755 index 0000000..633ade9 --- /dev/null +++ b/lab10/jacobi/do_all.sh @@ -0,0 +1,6 @@ +#!/bin/bash +git pull +make +python3 creator.py +sleep 0.5 +squeue diff --git a/lab10/jacobi/efficiency_plot.png b/lab10/jacobi/efficiency_plot.png new file mode 100644 index 0000000..d4c6bae Binary files /dev/null and b/lab10/jacobi/efficiency_plot.png differ diff --git a/lab10/jacobi/jacobi_main.cpp b/lab10/jacobi/jacobi_main.cpp index 3986786..718eff9 100644 --- a/lab10/jacobi/jacobi_main.cpp +++ b/lab10/jacobi/jacobi_main.cpp @@ -41,7 +41,7 @@ Matrix getCompleteInitialCondition(int n) { return getInitialCondition(n, 0, 1); } -Matrix run(Jacobi& jacobi, const Matrix& init, double eps, int maxNumIter) { +Matrix run(Jacobi &jacobi, const Matrix &init, double eps, int maxNumIter) { auto [m, dist, nIter] = jacobi.run(init, eps, maxNumIter); int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); @@ -52,9 +52,7 @@ Matrix run(Jacobi& jacobi, const Matrix& init, double eps, int maxNumIter) { return m; } -double benchmark(Jacobi& jacobi, - const Matrix& init, - double eps, +double benchmark(Jacobi &jacobi, const Matrix &init, double eps, int maxNumIter) { auto start = std::chrono::system_clock::now(); jacobi.run(init, eps, maxNumIter); @@ -142,7 +140,7 @@ void runParallel(int n, double eps, int maxNumIter) { } } -int main(int argc, char* argv[]) { +int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); int rank, numProc; @@ -158,26 +156,24 @@ int main(int argc, char* argv[]) { // Result is saved to file. // Use this to graphically verify the correctness of the parallel // implementation. - //runSerial(n, eps, maxNumIter); + runSerial(n, eps, maxNumIter); runParallel(n, eps, maxNumIter); - // Run the benchmark - //double serialTime = 0; + double serialTime = 0; double parallelTime = 0; - //serialTime = serialBenchmark(n, eps, maxNumIter); + serialTime = serialBenchmark(n, eps, maxNumIter); parallelTime = parallelBenchmark(n, eps, maxNumIter); if (rank == 0) { - //std::cout << "Serial time: " << serialTime << "ms" << std::endl; - std::cout << "Serial time: ms" << std::endl; + std::cout << "Serial time: " << serialTime << "ms" << std::endl; std::cout << "Parallel time: " << parallelTime << "ms" << std::endl; - //std::cout << "Speedup: " << serialTime / parallelTime << std::endl; + std::cout << "Speedup: " << serialTime / parallelTime << std::endl; std::ofstream fout("benchmark.txt", std::ios::app); fout << numProc << "\t" << parallelTime << "\n"; } MPI_Finalize(); -} \ No newline at end of file +} diff --git a/lab10/jacobi/jacobi_mpi.cpp b/lab10/jacobi/jacobi_mpi.cpp index 4ad80e2..9b4c4f4 100644 --- a/lab10/jacobi/jacobi_mpi.cpp +++ b/lab10/jacobi/jacobi_mpi.cpp @@ -1,38 +1,27 @@ #include "jacobi.h" #include "jacobi_main.h" +#include +#include +#include -std::vector getFilledBuffer(const Matrix &matrix, int row) -{ +std::vector getFilledBuffer(const Matrix &matrix, int row) { int numCols = matrix.cols(); std::vector rowBuffer(numCols); // Extract the row (matrix is column-major) - for (int j = 0; j < numCols; ++j) - { + for (int j = 0; j < numCols; ++j) { rowBuffer[j] = matrix(row, j); } return rowBuffer; } -/** - * Takes a matrix and an index indexRowLocal which defines which row of the local matrix has to be sent. - * - * Sends data of that row via MPI_Send to process with rank receiverRank. - * - * indexRowGlobal identifies row in the view of the whole matrix, used from receiving process - * to identify if lower or upper halo by comparing against rowHaloUpperIndex and rowHaloLowerIndex. - */ -void sendLocalRow(MPI_Request &request, std::vector &row, const Matrix &matrix, const int indexRowLocal, const int receiverRank, const int indexRowGlobal) -{ - row = getFilledBuffer(matrix, indexRowLocal); - MPI_Isend(row.data(), row.size(), MPI_DOUBLE, receiverRank, indexRowGlobal, MPI_COMM_WORLD, &request); -} - -Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, int maxNumIter) -{ +Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, + int maxNumIter) { int rank, numProc; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &numProc); + // std::cout << "rank: " << rank << std::endl; + // std::cout << "numProc: " << numProc << std::endl; std::vector phi(2, init); @@ -42,6 +31,8 @@ Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, int maxNumIter const int neighborUpper = rank - 1; const int neighborLower = rank + 1; + // std::cout << neighborUpper << ":" << neighborLower << std::endl; + const int indexRowGlobalStart = (rank * numRows); const int indexRowGlobalEnd = (rank * numRows) + (numRows - 1); @@ -56,28 +47,27 @@ Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, int maxNumIter int t0 = 0; // array index of current timestep int t1 = 1; // array index of next timestep - while (dist > epsilon && nIter < maxNumIter) - { + while (dist > epsilon && nIter < maxNumIter) { dist = 0; - if (rank == 0) - { - std::vector row; - MPI_Request request; - sendLocalRow(request, row, phi[t0], numRows - 1, neighborLower, indexRowGlobalEnd); - MPI_Wait(&request, MPI_STATUS_IGNORE); + if (rank == 0) { + MPI_Request send_lower; + std::vector send_vec_low = phi[t0].get_row(numRows - 1); + MPI_Isend(send_vec_low.data(), numCols, MPI_DOUBLE, neighborLower, + indexRowGlobalEnd, MPI_COMM_WORLD, &send_lower); MPI_Request requestLower; - MPI_Irecv(haloLower.data(), haloLower.size(), MPI_DOUBLE, - neighborLower, rowHaloLowerIndex, MPI_COMM_WORLD, &requestLower); + MPI_Irecv(haloLower.data(), numCols, MPI_DOUBLE, neighborLower, + rowHaloLowerIndex, MPI_COMM_WORLD, &requestLower); + + MPI_Wait(&send_lower, MPI_STATUS_IGNORE); MPI_Wait(&requestLower, MPI_STATUS_IGNORE); - for (int i = 1; i < numRows; ++i) - { - for (int j = 1; j < numCols - 1; ++j) - { + for (int i = 1; i < numRows; ++i) { + for (int j = 1; j < numCols - 1; ++j) { double valueBottom; - (i == numRows - 1) ? valueBottom = haloLower[j] : valueBottom = phi[t0](i + 1, j); + (i == numRows - 1) ? valueBottom = haloLower[j] + : valueBottom = phi[t0](i + 1, j); phi[t1](i, j) = .25 * (valueBottom + phi[t0](i - 1, j) + phi[t0](i, j + 1) + phi[t0](i, j - 1)); const double diff = phi[t1](i, j) - phi[t0](i, j); @@ -86,23 +76,21 @@ Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, int maxNumIter } } - else if (rank == (numProc - 1)) - { - std::vector row; + else if (rank == (numProc - 1)) { + MPI_Request send_upper; + std::vector send_vec_up = phi[t0].get_row(0); + MPI_Isend(send_vec_up.data(), numCols, MPI_DOUBLE, neighborUpper, + indexRowGlobalStart, MPI_COMM_WORLD, &send_upper); - MPI_Request request; - sendLocalRow(request, row, phi[t0], 0, neighborUpper, indexRowGlobalStart); - MPI_Wait(&request, MPI_STATUS_IGNORE); + MPI_Request request_upper; + MPI_Irecv(haloUpper.data(), numCols, MPI_DOUBLE, neighborUpper, + rowHaloUpperIndex, MPI_COMM_WORLD, &request_upper); - MPI_Request requestUpper; - MPI_Irecv(haloUpper.data(), haloUpper.size(), MPI_DOUBLE, - neighborUpper, rowHaloUpperIndex, MPI_COMM_WORLD, &requestUpper); - MPI_Wait(&requestUpper, MPI_STATUS_IGNORE); + MPI_Wait(&send_upper, MPI_STATUS_IGNORE); + MPI_Wait(&request_upper, MPI_STATUS_IGNORE); - for (int i = 0; i < numRows - 1; ++i) - { - for (int j = 1; j < numCols - 1; ++j) - { + for (int i = 0; i < numRows - 1; ++i) { + for (int j = 1; j < numCols - 1; ++j) { double valueTop; (i == 0) ? valueTop = haloUpper[j] : valueTop = phi[t0](i - 1, j); phi[t1](i, j) = .25 * (phi[t0](i + 1, j) + valueTop + @@ -113,51 +101,45 @@ Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, int maxNumIter } } - else - { - std::vector rowUpper; - std::vector rowLower; + else { + MPI_Request send_upper; + MPI_Request send_lower; - MPI_Request requestSendUpper; - MPI_Request requestSendLower; - sendLocalRow(requestSendUpper, rowUpper, phi[t0], 0, neighborUpper, indexRowGlobalStart); - sendLocalRow(requestSendLower, rowLower, phi[t0], numRows - 1, neighborLower, indexRowGlobalEnd); + std::vector send_vec_up = phi[t0].get_row(0); + MPI_Isend(send_vec_up.data(), numCols, MPI_DOUBLE, neighborUpper, + indexRowGlobalStart, MPI_COMM_WORLD, &send_upper); - MPI_Request sendRequests[2] = {requestSendUpper, requestSendLower}; - MPI_Waitall(2, sendRequests, MPI_STATUSES_IGNORE); + std::vector send_vec_low = phi[t0].get_row(numRows - 1); + MPI_Isend(send_vec_low.data(), numCols, MPI_DOUBLE, neighborLower, + indexRowGlobalEnd, MPI_COMM_WORLD, &send_lower); - MPI_Request requestUpper; - MPI_Irecv(haloUpper.data(), haloUpper.size(), MPI_DOUBLE, - neighborUpper, rowHaloUpperIndex, MPI_COMM_WORLD, &requestUpper); - MPI_Request requestLower; - MPI_Irecv(haloLower.data(), haloLower.size(), MPI_DOUBLE, - neighborLower, rowHaloLowerIndex, MPI_COMM_WORLD, &requestLower); + MPI_Request request_upper; + MPI_Request request_lower; + MPI_Irecv(haloUpper.data(), numCols, MPI_DOUBLE, neighborUpper, + rowHaloUpperIndex, MPI_COMM_WORLD, &request_upper); + MPI_Irecv(haloLower.data(), numCols, MPI_DOUBLE, neighborLower, + rowHaloLowerIndex, MPI_COMM_WORLD, &request_lower); - MPI_Request requests[2] = {requestUpper, requestLower}; - MPI_Waitall(2, requests, MPI_STATUSES_IGNORE); + MPI_Wait(&send_upper, MPI_STATUS_IGNORE); + MPI_Wait(&send_lower, MPI_STATUS_IGNORE); + MPI_Wait(&request_upper, MPI_STATUS_IGNORE); + MPI_Wait(&request_lower, MPI_STATUS_IGNORE); - for (int i = 0; i < numRows; ++i) - { - for (int j = 1; j < numCols - 1; ++j) - { - if (i == 0) - { + for (int i = 0; i < numRows; ++i) { + for (int j = 1; j < numCols - 1; ++j) { + if (i == 0) { double valueTop = haloUpper[j]; phi[t1](i, j) = .25 * (phi[t0](i + 1, j) + valueTop + phi[t0](i, j + 1) + phi[t0](i, j - 1)); const double diff = phi[t1](i, j) - phi[t0](i, j); dist = std::max(dist, std::abs(diff)); - } - else if (i == numRows - 1) - { + } else if (i == numRows - 1) { double valueBottom = haloLower[j]; phi[t1](i, j) = .25 * (valueBottom + phi[t0](i - 1, j) + phi[t0](i, j + 1) + phi[t0](i, j - 1)); const double diff = phi[t1](i, j) - phi[t0](i, j); dist = std::max(dist, std::abs(diff)); - } - else - { + } else { phi[t1](i, j) = .25 * (phi[t0](i + 1, j) + phi[t0](i - 1, j) + phi[t0](i, j + 1) + phi[t0](i, j - 1)); const double diff = phi[t1](i, j) - phi[t0](i, j); @@ -167,16 +149,17 @@ Jacobi::Result JacobiMPI::run(const Matrix &init, double epsilon, int maxNumIter } } - // if (nIter % 1000 == 0) { - // std::cout << "Iteration " << nIter << ", dist=" << dist << "\n"; - // } - double globalDist; + double globalDist = 0; MPI_Allreduce(&dist, &globalDist, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); dist = globalDist; nIter++; std::swap(t0, t1); + // if (nIter == 100) { + // std::cout << phi[t1] << std::endl; + // } } + // std::cout << phi[t1] << std::endl; return Jacobi::Result{phi[t0], dist, nIter}; } diff --git a/lab10/jacobi/matrix.h b/lab10/jacobi/matrix.h index fd3df1d..7a78fd7 100644 --- a/lab10/jacobi/matrix.h +++ b/lab10/jacobi/matrix.h @@ -16,14 +16,13 @@ * limitations under the License. */ - #ifndef MATRIX_H #define MATRIX_H -#include -#include -#include #include +#include +#include +#include /** * Matrix class @@ -40,7 +39,7 @@ * */ class Matrix { - public: +public: /** * Create a matrix of size m x n and initialize all entries to zero. * @param rows number of rows @@ -79,19 +78,19 @@ class Matrix { */ static Matrix uninit(std::pair dim); - Matrix(const Matrix& other); - Matrix(Matrix&& other); + Matrix(const Matrix &other); + Matrix(Matrix &&other); ~Matrix(); - Matrix& operator=(const Matrix& other); - Matrix& operator=(Matrix&& other); + Matrix &operator=(const Matrix &other); + Matrix &operator=(Matrix &&other); // Access element a_ij of the matrix - double& operator()(int i, int j); - const double& operator()(int i, int j) const; + double &operator()(int i, int j); + const double &operator()(int i, int j) const; // Obtain a pointer to the underlying data - double* data(); - const double* data() const; + double *data(); + const double *data() const; // Getter functions for the dimensions std::pair dim() const; @@ -100,44 +99,55 @@ class Matrix { int numEntries() const; // Comparison operators - bool operator==(const Matrix& b); - bool operator!=(const Matrix& b); + bool operator==(const Matrix &b); + bool operator!=(const Matrix &b); // addition - Matrix& operator+=(const Matrix& b); + Matrix &operator+=(const Matrix &b); // subtraction - Matrix& operator-=(const Matrix& b); + Matrix &operator-=(const Matrix &b); // scalar multiplication - Matrix& operator*=(double x); + Matrix &operator*=(double x); // scalar division - Matrix& operator/=(double x); + Matrix &operator/=(double x); - private: + std::vector get_row(int i) { + std::vector row(0); + int start = this->cols() * i; + int end = this->cols() * i + cols(); + + for (int j = start; j < end; j++) { + row.push_back(this->data()[j]); + } + return row; + } + +private: // Constructor is private to prevent creating an uninitialized matrix // accidentally. Use Matrix::zeros() or Matrix::uninit() instead Matrix(int m, int n); - int numRows_; // number of rows - int numCols_; // number of columns - double* data_; // the matrix' entries + int numRows_; // number of rows + int numCols_; // number of columns + double *data_; // the matrix' entries }; /** * Vector class - * + * * This class implements a vector of size n. The vector is stored in a * Matrix of size n x 1. - * + * * Constructors are provided to create a vector of zeros or an uninitialized * vector. The uninitialized vector is not initialized, i.e. the entries are * not set to zero. This is useful for performance reasons, e.g. to control * the placement of vector entries in locality-domain memory. */ class Vector { - public: +public: static Vector zeros(int n) { Vector vec; vec.data_ = Matrix::zeros(n, 1); @@ -150,19 +160,19 @@ class Vector { return vec; } - bool operator==(const Vector& b) { return data_ == b.data_; } - bool operator!=(const Vector& b) { return !operator==(b); } - double& operator()(int i) { return data_(i, 0); } - const double& operator()(int i) const { return data_(i, 0); } - double* data() { return data_.data(); } - const double* data() const { return data_.data(); } + bool operator==(const Vector &b) { return data_ == b.data_; } + bool operator!=(const Vector &b) { return !operator==(b); } + double &operator()(int i) { return data_(i, 0); } + const double &operator()(int i) const { return data_(i, 0); } + double *data() { return data_.data(); } + const double *data() const { return data_.data(); } - Vector operator+=(const Vector& b) { + Vector operator+=(const Vector &b) { data_ += b.data_; return *this; } - Vector operator-=(const Vector& b) { + Vector operator-=(const Vector &b) { data_ -= b.data_; return *this; } @@ -177,7 +187,7 @@ class Vector { int size() const { return data_.rows(); } - private: +private: Matrix data_ = Matrix::zeros(0, 0); }; @@ -193,27 +203,21 @@ inline Matrix Matrix::zeros(int m, int n) { return mat; } -inline Matrix Matrix::zeros(int n) { - return zeros(n, n); -} +inline Matrix Matrix::zeros(int n) { return zeros(n, n); } inline Matrix Matrix::zeros(std::pair dim) { return zeros(dim.first, dim.second); } -inline Matrix Matrix::uninit(int m, int n) { - return Matrix(m, n); -} +inline Matrix Matrix::uninit(int m, int n) { return Matrix(m, n); } -inline Matrix Matrix::uninit(int n) { - return uninit(n, n); -} +inline Matrix Matrix::uninit(int n) { return uninit(n, n); } inline Matrix Matrix::uninit(std::pair dim) { return uninit(dim.first, dim.second); } -inline Matrix::Matrix(const Matrix& other) { +inline Matrix::Matrix(const Matrix &other) { numRows_ = other.numRows_; numCols_ = other.numCols_; if (numRows_ == 0 || numCols_ == 0) { @@ -228,7 +232,7 @@ inline Matrix::Matrix(const Matrix& other) { } } -inline Matrix::Matrix(Matrix&& other) { +inline Matrix::Matrix(Matrix &&other) { numRows_ = other.numRows_; numCols_ = other.numCols_; data_ = other.data_; @@ -244,7 +248,7 @@ inline Matrix::~Matrix() { } } -inline Matrix& Matrix::operator=(const Matrix& other) { +inline Matrix &Matrix::operator=(const Matrix &other) { if (this != &other) { if (data_ != nullptr) { delete[] data_; @@ -261,7 +265,7 @@ inline Matrix& Matrix::operator=(const Matrix& other) { return *this; } -inline Matrix& Matrix::operator=(Matrix&& other) { +inline Matrix &Matrix::operator=(Matrix &&other) { if (this != &other) { if (data_ != nullptr) { delete[] data_; @@ -276,39 +280,29 @@ inline Matrix& Matrix::operator=(Matrix&& other) { return *this; } -inline double& Matrix::operator()(int i, int j) { +inline double &Matrix::operator()(int i, int j) { return data_[i * numCols_ + j]; } -inline const double& Matrix::operator()(int i, int j) const { +inline const double &Matrix::operator()(int i, int j) const { return data_[i * numCols_ + j]; } -inline double* Matrix::data() { - return data_; -} +inline double *Matrix::data() { return data_; } -inline const double* Matrix::data() const { - return data_; -} +inline const double *Matrix::data() const { return data_; } inline std::pair Matrix::dim() const { return std::pair(numRows_, numCols_); } -inline int Matrix::rows() const { - return numRows_; -} +inline int Matrix::rows() const { return numRows_; } -inline int Matrix::cols() const { - return numCols_; -} +inline int Matrix::cols() const { return numCols_; } -inline int Matrix::numEntries() const { - return numRows_ * numCols_; -} +inline int Matrix::numEntries() const { return numRows_ * numCols_; } -inline bool Matrix::operator==(const Matrix& b) { +inline bool Matrix::operator==(const Matrix &b) { const double eps = 1e-12; if (numRows_ != b.numRows_ || numCols_ != b.numCols_) { return false; @@ -323,11 +317,9 @@ inline bool Matrix::operator==(const Matrix& b) { return true; } -inline bool Matrix::operator!=(const Matrix& b) { - return !operator==(b); -} +inline bool Matrix::operator!=(const Matrix &b) { return !operator==(b); } -inline Matrix& Matrix::operator+=(const Matrix& b) { +inline Matrix &Matrix::operator+=(const Matrix &b) { for (int i = 0; i < numRows_; ++i) { for (int j = 0; j < numCols_; ++j) { operator()(i, j) += b(i, j); @@ -336,7 +328,7 @@ inline Matrix& Matrix::operator+=(const Matrix& b) { return *this; } -inline Matrix& Matrix::operator-=(const Matrix& b) { +inline Matrix &Matrix::operator-=(const Matrix &b) { for (int i = 0; i < numRows_; ++i) { for (int j = 0; j < numCols_; ++j) { operator()(i, j) -= b(i, j); @@ -345,7 +337,7 @@ inline Matrix& Matrix::operator-=(const Matrix& b) { return *this; } -inline Matrix& Matrix::operator*=(double x) { +inline Matrix &Matrix::operator*=(double x) { for (int i = 0; i < numRows_; ++i) { for (int j = 0; j < numCols_; ++j) { operator()(i, j) *= x; @@ -354,7 +346,7 @@ inline Matrix& Matrix::operator*=(double x) { return *this; } -inline Matrix& Matrix::operator/=(double x) { +inline Matrix &Matrix::operator/=(double x) { for (int i = 0; i < numRows_; ++i) { for (int j = 0; j < numCols_; ++j) { operator()(i, j) /= x; @@ -370,7 +362,7 @@ inline Matrix::Matrix(int m, int n) : numRows_(m), numCols_(n) { } } -inline std::ostream& operator<<(std::ostream& os, const Matrix& a) { +inline std::ostream &operator<<(std::ostream &os, const Matrix &a) { const int width = 10; const int precision = 4; @@ -389,8 +381,7 @@ inline std::ostream& operator<<(std::ostream& os, const Matrix& a) { return os; } -inline bool equalWithinRange(const Matrix& a, - const Matrix& b, +inline bool equalWithinRange(const Matrix &a, const Matrix &b, double eps = 1e-12) { if (a.rows() != b.rows() || a.cols() != b.cols()) return false; @@ -408,4 +399,4 @@ inline bool equalWithinRange(const Matrix& a, return true; } -#endif // MATRIX_H \ No newline at end of file +#endif // MATRIX_H diff --git a/lab10/jacobi/matrix_io.cpp b/lab10/jacobi/matrix_io.cpp index b5d9708..2721701 100644 --- a/lab10/jacobi/matrix_io.cpp +++ b/lab10/jacobi/matrix_io.cpp @@ -1,16 +1,16 @@ +#include "matrix_io.h" +#include "matrix.h" +#include #include #include -#include -#include "matrix.h" -#include "matrix_io.h" MatrixIO::MatrixIO() { MPI_Comm_rank(MPI_COMM_WORLD, &rank_); MPI_Comm_size(MPI_COMM_WORLD, &numProc_); } -void MatrixIO::saveDistributed(const Matrix& distributedMatrix, - const std::string& filename) { +void MatrixIO::saveDistributed(const Matrix &distributedMatrix, + const std::string &filename) { Matrix mat = gatherMatrixOnRoot(distributedMatrix); if (rank_ == 0) { @@ -18,7 +18,7 @@ void MatrixIO::saveDistributed(const Matrix& distributedMatrix, } } -void MatrixIO::saveSerial(const Matrix& m, const std::string& filename) { +void MatrixIO::saveSerial(const Matrix &m, const std::string &filename) { std::ofstream fout(filename); const int numRows = m.rows(); const int numCols = m.cols(); @@ -31,7 +31,7 @@ void MatrixIO::saveSerial(const Matrix& m, const std::string& filename) { } } -Matrix MatrixIO::loadDistributed(const std::string& filename) { +Matrix MatrixIO::loadDistributed(const std::string &filename) { Matrix matrixOnRoot = Matrix::zeros(0, 0); if (rank_ == 0) { matrixOnRoot = loadSerial(filename); @@ -41,7 +41,7 @@ Matrix MatrixIO::loadDistributed(const std::string& filename) { return distributedMatrix; } -Matrix MatrixIO::loadSerial(const std::string& filename) { +Matrix MatrixIO::loadSerial(const std::string &filename) { std::ifstream fin(filename); // Check first character (has to be #) @@ -66,7 +66,7 @@ Matrix MatrixIO::loadSerial(const std::string& filename) { return mat; } -Matrix MatrixIO::gatherMatrixOnRoot(const Matrix& distributedMatrix) { +Matrix MatrixIO::gatherMatrixOnRoot(const Matrix &distributedMatrix) { const int numRowsLocal = distributedMatrix.rows(); const int numCols = distributedMatrix.cols(); const int numRowsTotal = numRowsLocal * numProc_; @@ -84,7 +84,7 @@ Matrix MatrixIO::gatherMatrixOnRoot(const Matrix& distributedMatrix) { return matrixOnRoot; } -Matrix MatrixIO::scatterMatrixFromRoot(const Matrix& matrixOnRoot) { +Matrix MatrixIO::scatterMatrixFromRoot(const Matrix &matrixOnRoot) { int numRowsTotal = matrixOnRoot.rows(); int numCols = matrixOnRoot.cols(); diff --git a/lab10/jacobi/performance_plot.png b/lab10/jacobi/performance_plot.png new file mode 100644 index 0000000..d1d5b80 Binary files /dev/null and b/lab10/jacobi/performance_plot.png differ diff --git a/lab10/jacobi/plot_res.py b/lab10/jacobi/plot_res.py new file mode 100644 index 0000000..001f7f4 --- /dev/null +++ b/lab10/jacobi/plot_res.py @@ -0,0 +1,55 @@ +import matplotlib.pyplot as plt + +# Pfad zum Verzeichnis mit den Dateien +data_dir = "resluts/" # ggf. anpassen + +threads = [1, 2, 4, 6, 8, 12, 16, 18, 24, 32, 36, 48] +times = [ + 175246, + 89030.8, + 45182.7, + 30198.1, + 22710.1, + 15256.1, + 13512.1, + 13073.2, + 10036.8, + 9845.38, + 8423.65, + 7676.71, +] +speedups = [ + 1, + 1.96838, + 3.90997, + 5.8091, + 7.73292, + 11.4934, + 13.0374, + 13.4461, + 17.4421, + 17.9058, + 20.8097, + 22.8728, +] + +efficiency = [speedup / thread for speedup, thread in zip(speedups, threads)] + +# plt.figure(figsize=(10, 5)) +plt.plot(threads, efficiency, marker="o", label="Speedup") +plt.title("Efficiency") +plt.xlabel("Threads") +plt.ylabel("Efficiency") +plt.grid(True) +# plt.legend() +# plt.tight_layout() +plt.savefig("efficiency_plot.png") + +plt.clf() +# --- Plot 2: Performance --- +plt.plot(threads, times, marker="o") +plt.title("Performance") +plt.xlabel("Threads") +plt.ylabel("Performance (ms)") +plt.grid(True) +plt.savefig("performance_plot.png") diff --git a/lab10/jacobi/results/jacobi_12.txt b/lab10/jacobi/results/jacobi_12.txt new file mode 100644 index 0000000..9780592 --- /dev/null +++ b/lab10/jacobi/results/jacobi_12.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175344ms +Parallel benchmark finished, time=15256.1ms +Serial time: 175344ms +Parallel time: 15256.1ms +Speedup: 11.4934 diff --git a/lab10/jacobi/results/jacobi_16.txt b/lab10/jacobi/results/jacobi_16.txt new file mode 100644 index 0000000..3255197 --- /dev/null +++ b/lab10/jacobi/results/jacobi_16.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=176163ms +Parallel benchmark finished, time=13512.1ms +Serial time: 176163ms +Parallel time: 13512.1ms +Speedup: 13.0374 diff --git a/lab10/jacobi/results/jacobi_18.txt b/lab10/jacobi/results/jacobi_18.txt new file mode 100644 index 0000000..4cd8e8b --- /dev/null +++ b/lab10/jacobi/results/jacobi_18.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175784ms +Parallel benchmark finished, time=13073.2ms +Serial time: 175784ms +Parallel time: 13073.2ms +Speedup: 13.4461 diff --git a/lab10/jacobi/results/jacobi_2.txt b/lab10/jacobi/results/jacobi_2.txt new file mode 100644 index 0000000..7dc08fb --- /dev/null +++ b/lab10/jacobi/results/jacobi_2.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175246ms +Parallel benchmark finished, time=89030.8ms +Serial time: 175246ms +Parallel time: 89030.8ms +Speedup: 1.96838 diff --git a/lab10/jacobi/results/jacobi_24.txt b/lab10/jacobi/results/jacobi_24.txt new file mode 100644 index 0000000..3bcb7b6 --- /dev/null +++ b/lab10/jacobi/results/jacobi_24.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175063ms +Parallel benchmark finished, time=10036.8ms +Serial time: 175063ms +Parallel time: 10036.8ms +Speedup: 17.4421 diff --git a/lab10/jacobi/results/jacobi_32.txt b/lab10/jacobi/results/jacobi_32.txt new file mode 100644 index 0000000..67a3f11 --- /dev/null +++ b/lab10/jacobi/results/jacobi_32.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=176290ms +Parallel benchmark finished, time=9845.38ms +Serial time: 176290ms +Parallel time: 9845.38ms +Speedup: 17.9058 diff --git a/lab10/jacobi/results/jacobi_36.txt b/lab10/jacobi/results/jacobi_36.txt new file mode 100644 index 0000000..2c9a976 --- /dev/null +++ b/lab10/jacobi/results/jacobi_36.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175294ms +Parallel benchmark finished, time=8423.65ms +Serial time: 175294ms +Parallel time: 8423.65ms +Speedup: 20.8097 diff --git a/lab10/jacobi/results/jacobi_4.txt b/lab10/jacobi/results/jacobi_4.txt new file mode 100644 index 0000000..32a1d40 --- /dev/null +++ b/lab10/jacobi/results/jacobi_4.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=176663ms +Parallel benchmark finished, time=45182.7ms +Serial time: 176663ms +Parallel time: 45182.7ms +Speedup: 3.90997 diff --git a/lab10/jacobi/results/jacobi_48.txt b/lab10/jacobi/results/jacobi_48.txt new file mode 100644 index 0000000..77a6ee9 --- /dev/null +++ b/lab10/jacobi/results/jacobi_48.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175588ms +Parallel benchmark finished, time=7676.71ms +Serial time: 175588ms +Parallel time: 7676.71ms +Speedup: 22.8728 diff --git a/lab10/jacobi/results/jacobi_6.txt b/lab10/jacobi/results/jacobi_6.txt new file mode 100644 index 0000000..0216106 --- /dev/null +++ b/lab10/jacobi/results/jacobi_6.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175424ms +Parallel benchmark finished, time=30198.1ms +Serial time: 175424ms +Parallel time: 30198.1ms +Speedup: 5.8091 diff --git a/lab10/jacobi/results/jacobi_8.txt b/lab10/jacobi/results/jacobi_8.txt new file mode 100644 index 0000000..5b055a0 --- /dev/null +++ b/lab10/jacobi/results/jacobi_8.txt @@ -0,0 +1,6 @@ +Starting serial benchmark +Serial benchmark finished, time=175615ms +Parallel benchmark finished, time=22710.1ms +Serial time: 175615ms +Parallel time: 22710.1ms +Speedup: 7.73292