Parcourir la source

version avec l'API C de MPI

Julien Dehos il y a 7 ans
Parent
commit
196c549e9d
6 fichiers modifiés avec 180 ajouts et 114 suppressions
  1. 3 2
      Makefile
  2. 17 17
      image.hpp
  3. 0 94
      laplacien_mpi.cpp
  4. 71 0
      laplacien_mpi_1.cpp
  5. 88 0
      laplacien_mpi_2.cpp
  6. 1 1
      run.sh

+ 3 - 2
Makefile

@@ -1,5 +1,6 @@
 all:
-	mpic++ -std=c++11 -Wall -Wextra -lboost_mpi -lboost_serialization -o laplacien_mpi.out laplacien_mpi.cpp 
+	mpic++ -std=c++11 -Wall -Wextra -o laplacien_mpi_1.out laplacien_mpi_1.cpp 
+	mpic++ -std=c++11 -Wall -Wextra -o laplacien_mpi_2.out laplacien_mpi_2.cpp 
 
 clean:
-	rm -f laplacien_mpi.out output.pgm OAR.*
+	rm -f laplacien_mpi_?.out output_?.pgm OAR.*

+ 17 - 17
image.hpp

@@ -1,4 +1,3 @@
-
 #ifndef _IMAGE_HPP_
 #define _IMAGE_HPP_
 
@@ -9,14 +8,12 @@
 #include <string>
 #include <vector>
 
-typedef unsigned char pixel_t;
-typedef std::vector<pixel_t> image_t;
+using pixel_t = unsigned char;
+using image_t = std::vector<pixel_t>;
 
 // write image
-std::string writePgm(const std::string &filename, 
-                     int width, 
-                     int height, 
-                     const image_t & data) 
+std::string writePgm(const std::string &filename, int width, int height, 
+        const image_t & data) 
 {
     std::ofstream os(filename);
     if (not os)
@@ -34,10 +31,8 @@ std::string writePgm(const std::string &filename,
 }
 
 // read image
-std::string readPgm(const std::string &filename, 
-                    int & width, 
-                    int & height, 
-                    image_t & data) 
+std::string readPgm(const std::string &filename, int & width, int & height, 
+        image_t & data) 
 {
     std::ifstream is(filename);
     if (not is)
@@ -67,11 +62,13 @@ std::string readPgm(const std::string &filename,
     return "";
 }
 
-// Returns a blurred subimage of data1 (using the specified radius for the convolution kernel).
+// Returns a blurred subimage of data1 
+// (using the specified radius for the convolution kernel).
 // The size of data1 is width*height.
 // The blurred region is, in data1, (x0, y0, x1, y1).
 // Therefore the size of the subimage is (x1-x0)*(y1-y0)
-image_t blur(const image_t & data1, int width, int height, int radius, int x0, int y0, int x1, int y1)
+image_t blur(const image_t & data1, int width, int height, int radius, int x0, 
+        int y0, int x1, int y1)
 {
     int width2 = x1-x0;
     int height2 = y1-y0;
@@ -99,18 +96,20 @@ image_t blur(const image_t & data1, int width, int height, int radius, int x0, i
                 }
             }
             int pixel = n>0 ? s/n : data1[y*width + x];
-            if (x==x0 or y==y0 or x==x1-1 or y==y1-1) pixel = 0;    // draw border
+            if (x==x0 or y==y0 or x==x1-1 or y==y1-1) pixel = 0; // draw border
             data2[(y-y0)*width2 + (x-x0)] = pixel;
         }
     }
     return data2;
 }
 
-image_t computeLaplacian(const image_t & data1, int width, int height, double scaling)
+image_t computeLaplacian(const image_t & data1, int width, int height, 
+        double scaling)
 {
     assert(data1.size() >= unsigned(width*height));
     // return the pixel value of (x,y) in [0,1]
-    auto ind = [&data1,width](int x, int y) {return double(data1[y*width + x])/255.0;};
+    auto ind = [&data1,width](int x, int y) 
+    {return double(data1[y*width + x])/255.0;};
     // compute laplacian image
     image_t data2(width*height);
     for (int x=1; x<width-1; x++)
@@ -118,7 +117,8 @@ image_t computeLaplacian(const image_t & data1, int width, int height, double sc
         for (int y=1; y<height-1; y++)
         {
             // compute laplacian value in [-4,4]
-            double v = -4.0*ind(x,y) + ind(x,y-1) + ind(x,y+1) + ind(x-1,y) + ind(x+1,y);
+            double v = -4.0*ind(x,y) 
+                + ind(x,y-1) + ind(x,y+1) + ind(x-1,y) + ind(x+1,y);
             // scale the value in [0,255]
             // and write this value in output image
             int i255 = 255.0 * (scaling*v+4.0)/8.0;

+ 0 - 94
laplacien_mpi.cpp

@@ -1,94 +0,0 @@
-// mpic++ -std=c++11 -Wall -Wextra -lboost_mpi -lboost_serialization -o laplacien_mpi.out laplacien_mpi.cpp 
-// mpirun -n 50 --hostfile mpi_file ./laplacien_mpi.out
-
-#include "image.hpp"
-
-#include <boost/mpi.hpp>
-namespace mpi = boost::mpi;
-
-#include <algorithm>
-
-int main(int argc, char ** argv)
-{
-    mpi::environment env(argc, argv);
-    mpi::communicator world;
-
-    int rank = world.rank();
-    int size = world.size();
-    int Nj = size;
-
-    if (rank == 0)  // master node
-    {
-        // read image
-        image_t data0;
-        int width, height;
-        std::string readError = readPgm("backloop.pgm", width, height, data0);
-        if (readError != "")
-        {
-            std::cout << readError << std::endl;
-            exit(-1);
-        }
-        int heightN = (height+Nj-1) / Nj;
-        int height2 = heightN * Nj;
-        int sizeN = heightN * width;
-
-        // copy data0 in data1 
-        // ensure the height of data1 is a multiple of Nj
-        image_t data1(width*height2);
-        std::copy_n(data0.begin(), width*height,
-                std::inserter(data1, data1.begin()));
-
-        // some data for MPI transfers
-        image_t data(sizeN);
-        std::vector<image_t> allData(Nj, data);
-        std::vector<image_t> allResults(Nj, data);
-
-        // decompose image 
-        for (int j=0; j<Nj; j++)
-            std::copy_n(data1.begin()+(j*sizeN), sizeN,
-                    std::inserter(allData[j], allData[j].begin()));
-
-        // send subimage sizes to slave nodes
-        mpi::broadcast(world, width, 0);
-        mpi::broadcast(world, heightN, 0);
-
-        // send data to slave nodes
-        image_t nodeData;
-        mpi::scatter(world, allData, nodeData, 0);
-
-        // compute master data
-        image_t nodeResult = computeLaplacian(nodeData, width, heightN, 10.0);
-
-        // receive results from slave nodes
-        mpi::gather(world, nodeResult, allResults, 0);
-
-        // recompose image
-        image_t data2(width*height2);
-        for (int j=0; j<Nj; j++)
-            std::copy_n(allResults[j].begin(), sizeN,
-                    std::inserter(data2, data2.begin()+(j*sizeN)));
-
-        // write output image
-        writePgm("output.pgm", width, height, data2);
-    }
-    else  // slave nodes
-    {
-        // receive subimage sizes
-        int width;
-        mpi::broadcast(world, width, 0);
-        int heightN;
-        mpi::broadcast(world, heightN, 0);
-
-        // receive data from master node
-        image_t nodeData(width,heightN);
-        mpi::scatter(world, nodeData, 0);
-
-        // compute node data
-        image_t nodeResult = computeLaplacian(nodeData, width, heightN, 10.0);
-
-        // send results to master node
-        mpi::gather(world, nodeResult, 0);
-    }
-
-    return 0;
-}

+ 71 - 0
laplacien_mpi_1.cpp

@@ -0,0 +1,71 @@
+// mpic++ -std=c++11 -Wall -Wextra -o laplacien_mpi_1.out laplacien_mpi_1.cpp 
+// mpirun -n 4 ./laplacien_mpi_1.out
+
+#include "image.hpp"
+#include <algorithm>
+#include <mpi.h>
+
+int main(int argc, char ** argv)
+{
+    // init MPI
+    MPI_Init(&argc, &argv);
+    int nbNodes;
+    MPI_Comm_size(MPI_COMM_WORLD, &nbNodes);
+    int iNode;
+    MPI_Comm_rank(MPI_COMM_WORLD, &iNode);
+
+    // read image (master node)
+    image_t data0;
+    int width, height;
+    if (iNode == 0)  
+    {
+        std::string readError = readPgm("backloop.pgm", width, height, data0);
+        if (readError != "")
+        {
+            std::cout << readError << std::endl;
+            exit(-1);
+        }
+    }
+
+    // broadcast image sizes
+    MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
+    MPI_Bcast(&height, 1, MPI_INT, 0, MPI_COMM_WORLD);
+
+    int heightN = (height+nbNodes-1) / nbNodes;
+    int sizeN = heightN * width;
+    int height2 = heightN * nbNodes;
+    int size2 = height2 * width;
+
+    // ensure height of data is a multiple of nbNodes (master node)
+    image_t data1(size2);
+    if (iNode == 0)
+    {
+        std::copy_n(data0.begin(), width*height, data1.begin());
+    }
+
+    // send data to nodes
+    image_t nodeData(sizeN);
+    MPI_Scatter(data1.data(), sizeN, MPI_UNSIGNED_CHAR, 
+            nodeData.data(), sizeN, MPI_UNSIGNED_CHAR, 
+            0, MPI_COMM_WORLD);
+
+    // compute on each node
+    image_t nodeResult = computeLaplacian(nodeData, width, heightN, 10.0);
+
+    // receive results from nodes
+    image_t data2(size2);
+    MPI_Gather(nodeResult.data(), sizeN, MPI_UNSIGNED_CHAR, 
+            data2.data(), sizeN, MPI_UNSIGNED_CHAR, 
+            0, MPI_COMM_WORLD);
+
+    // write output image (master node)
+    if (iNode == 0)
+    {
+        writePgm("output_1.pgm", width, height, data2);
+        std::cout << "walltime = " << MPI_Wtime() << std::endl;
+    }
+
+    MPI_Finalize();
+    return 0;
+}
+

+ 88 - 0
laplacien_mpi_2.cpp

@@ -0,0 +1,88 @@
+// mpic++ -std=c++11 -Wall -Wextra -o laplacien_mpi_2.out laplacien_mpi_2.cpp 
+// mpirun -n 4 ./laplacien_mpi_2.out
+
+#include "image.hpp"
+#include <algorithm>
+#include <mpi.h>
+
+int main(int argc, char ** argv)
+{
+    // init MPI
+    MPI_Init(&argc, &argv);
+    int nbNodes;
+    MPI_Comm_size(MPI_COMM_WORLD, &nbNodes);
+    int iNode;
+    MPI_Comm_rank(MPI_COMM_WORLD, &iNode);
+
+    if (iNode == 0)  // master node
+    {
+        // read image
+        image_t data0;
+        int width, height;
+        std::string readError = readPgm("backloop.pgm", width, height, data0);
+        if (readError != "")
+        {
+            std::cout << readError << std::endl;
+            exit(-1);
+        }
+        int heightN = (height+nbNodes-1) / nbNodes;
+        int sizeN = heightN * width;
+        int height2 = heightN * nbNodes;
+        int size2 = height2 * width;
+
+        // copy data0 in data1 
+        // ensure the height of data1 is a multiple of nbNodes
+        image_t data1(size2);
+        std::copy_n(data0.begin(), width*height, data1.begin());
+
+        // send subimage sizes to slave nodes
+        MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
+        MPI_Bcast(&heightN, 1, MPI_INT, 0, MPI_COMM_WORLD);
+
+        // send data to slave nodes
+        image_t nodeData(sizeN);
+        MPI_Scatter(data1.data(), sizeN, MPI_UNSIGNED_CHAR, 
+                nodeData.data(), sizeN, MPI_UNSIGNED_CHAR, 
+                0, MPI_COMM_WORLD);
+
+        // compute master data
+        image_t nodeResult = computeLaplacian(nodeData, width, heightN, 10.0);
+
+        // receive results from slave nodes
+        image_t data2(size2, 0);
+        MPI_Gather(nodeResult.data(), sizeN, MPI_UNSIGNED_CHAR, 
+                data2.data(), sizeN, MPI_UNSIGNED_CHAR, 
+                0, MPI_COMM_WORLD);
+
+        // write output image
+        writePgm("output_2.pgm", width, height, data2);
+        std::cout << "walltime = " << MPI_Wtime() << std::endl;
+    }
+    else  // slave nodes
+    {
+        // receive subimage sizes
+        int width;
+        MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
+        int heightN;
+        MPI_Bcast(&heightN, 1, MPI_INT, 0, MPI_COMM_WORLD);
+        int sizeN = heightN * width;
+
+        // receive data from master node
+        image_t nodeData(sizeN);
+        MPI_Scatter(nullptr, sizeN, MPI_UNSIGNED_CHAR, 
+                nodeData.data(), sizeN, MPI_UNSIGNED_CHAR, 
+                0, MPI_COMM_WORLD);
+
+        // compute node data
+        image_t nodeResult = computeLaplacian(nodeData, width, heightN, 10.0);
+
+        // send results to master node
+        MPI_Gather(nodeResult.data(), sizeN, MPI_UNSIGNED_CHAR, 
+                nullptr, sizeN, MPI_UNSIGNED_CHAR, 
+                0, MPI_COMM_WORLD);
+    }
+
+    MPI_Finalize();
+    return 0;
+}
+

+ 1 - 1
run.sh

@@ -6,6 +6,6 @@
 ulimit -s unlimited
 NSLOTS=$(cat $OAR_NODEFILE | wc -l)
 PREF=$(dirname `which mpirun` | awk -F'/[^/]*$' '{print $1}')
-mpirun --prefix $PREF -np $NSLOTS -machinefile $OAR_NODEFILE -mca orte_rsh_agent "oarsh" ./laplacien_mpi.out
+mpirun --prefix $PREF -np $NSLOTS -machinefile $OAR_NODEFILE -mca orte_rsh_agent "oarsh" ./laplacien_mpi_1.out
 exit $?