{"id":5025,"date":"2022-05-30T10:54:19","date_gmt":"2022-05-30T09:54:19","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=5025"},"modified":"2022-05-30T10:54:19","modified_gmt":"2022-05-30T09:54:19","slug":"c-guns-mpi-dataype-send-struct","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=5025","title":{"rendered":"C++ Guns: MPI Dataype; send struct"},"content":{"rendered":"<p>Das Beispiel habe ich von https:\/\/www.mpi-forum.org\/docs\/mpi-3.1\/mpi31-report\/node425.htm<br \/>\nJeder Thread erstellt einen MPI Datentyp welcher die Offsett Addressen der struct Member Variablen hat.<br \/>\nThread 1 sendet Daten zu Thread 0<br \/>\nThread 0 empfaenge Daten von Thread1 und seine eigenen Daten, so dass alle in einem Array dann liegen.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/ This example is based on https:\/\/www.mpi-forum.org\/docs\/mpi-3.1\/mpi31-report\/node425.htm\r\n\/\/ Jeder Thread erstellt einen MPI Datentyp welcher die Offsett Addressen der struct Member Variablen hat.\r\n\/\/ Thread 1 sendet Daten zu Thread 0\r\n\/\/ Thread 0 empfaenge Daten von Thread1 und seine eigenen Daten, so dass alle in einem Array dann liegen.\r\n\r\n#include &lt;iostream&gt;\r\n#include &lt;array&gt;\r\n\r\n#include &lt;mpi.h&gt;\r\n\r\nint my_rank;\r\nint nThreads;\r\n\r\nstruct basetype_t {\r\n  double volstep = 0;\r\n  double volTot = 0;\r\n};\r\n\r\n\/\/ Vererbung ist nicht erlaubt\r\nstruct type_t  {\r\n  char ID&#x5B;50];\r\n  int i = 0;\r\n  float x = 0;\r\n  \/\/ Ein Container wie std::vector zwischen den Datentypen scheint wohl zu funktionieren, ist in Fortran aber explizit nicht erlaubt.\r\n\/\/   std::vector&lt;int&gt; unused;\r\n  bool l = false;\r\n  double d = 0;\r\n  basetype_t base;\r\n};\r\n\r\n\/\/ Check MPI Error code\r\nvoid check(int ierr) {\r\n  if (ierr != MPI_SUCCESS) {\r\n    char err_recvbuffer&#x5B;MPI_MAX_ERROR_STRING];\r\n    int resultlen;\r\n    MPI_Error_string(ierr, err_recvbuffer, &amp;resultlen);\r\n    std::cerr &lt;&lt; err_recvbuffer &lt;&lt; &quot;\\n&quot;;\r\n    MPI_Finalize();\r\n  }\r\n}\r\n\r\n\/\/ create new MPI datatype based on the addresses of the member variables of the type we want to send\r\nMPI_Datatype createMPItyp() {\r\n  type_t foo;\r\n  MPI_Aint base;\r\n  check(MPI_Get_address(&amp;foo, &amp;base));\r\n\r\n  \/\/ Fuer jede member Variable die gesendet werden soll, Typ und Addresse bestimmen\r\n  const int nMembervarsToSend = 7;\r\n  std::array&lt;MPI_Datatype, nMembervarsToSend&gt; types;\r\n  std::array&lt;int,nMembervarsToSend&gt; blocklen;\r\n  std::array&lt;MPI_Aint, nMembervarsToSend&gt; disp;\r\n\r\n  types&#x5B;0] = MPI_INT;\r\n  blocklen&#x5B;0] = 1;\r\n  check(MPI_Get_address(&amp;foo.i, &amp;disp&#x5B;0]));\r\n\r\n  types&#x5B;1] = MPI_FLOAT;\r\n  blocklen&#x5B;1] = 1;\r\n  check(MPI_Get_address(&amp;foo.x, &amp;disp&#x5B;1]));\r\n\r\n  types&#x5B;2] = MPI_LOGICAL;\r\n  blocklen&#x5B;2] = 1;\r\n  check(MPI_Get_address(&amp;foo.l, &amp;disp&#x5B;2]));\r\n\r\n  types&#x5B;3] = MPI_DOUBLE;\r\n  blocklen&#x5B;3] = 1;\r\n  check(MPI_Get_address(&amp;foo.d, &amp;disp&#x5B;3]));\r\n\r\n  types&#x5B;4] = MPI_CHAR;\r\n  blocklen&#x5B;4] = sizeof(foo.ID);\r\n  check(MPI_Get_address(&amp;foo.ID, &amp;disp&#x5B;4]));\r\n\r\n  types&#x5B;5] = MPI_DOUBLE;\r\n  blocklen&#x5B;5] = 1;\r\n  check(MPI_Get_address(&amp;foo.base.volstep, &amp;disp&#x5B;5]));\r\n\r\n  types&#x5B;6] = MPI_DOUBLE;\r\n  blocklen&#x5B;6] = 1;\r\n  check(MPI_Get_address(&amp;foo.base.volTot, &amp;disp&#x5B;6]));\r\n\r\n  if(my_rank == 0) {\r\n      std::cout &lt;&lt; &quot;Base Address &quot; &lt;&lt; std::hex &lt;&lt; base &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;Addresses   &quot;;\r\n      for(auto&amp; x : disp) {\r\n        std::cout &lt;&lt; &quot; &quot; &lt;&lt; std::hex &lt;&lt; x;\r\n      }\r\n      std::cout &lt;&lt; std::dec &lt;&lt; &quot;\\n&quot;;\r\n  }\r\n\r\n  \/\/ Addresse zu Offset umrechnen\r\n  for(auto&amp; x : disp) {\r\n    x -= base;\r\n  }\r\n\r\n  if(my_rank == 0) {\r\n    std::cout &lt;&lt; &quot;Displacement&quot;;\r\n    for(auto&amp; x : disp) {\r\n      std::cout &lt;&lt; &quot; &quot; &lt;&lt; x;\r\n    }\r\n    std::cout &lt;&lt; &quot;\\n&quot;;\r\n  }\r\n\r\n  MPI_Datatype newMPItype;\r\n  check(MPI_Type_create_struct(nMembervarsToSend, blocklen.data(), disp.data(), types.data(), &amp;newMPItype));\r\n  check(MPI_Type_commit(&amp;newMPItype));\r\n\r\n  return newMPItype;\r\n}\r\n\r\nvoid doRank0(MPI_Datatype newMPItype) {\r\n    type_t sendbuffer;\r\n    strcpy(sendbuffer.ID, &quot;Kreis100&quot;);\r\n    sendbuffer.i = 10;\r\n    sendbuffer.x = 1.2f;\r\n    sendbuffer.d = 1.23;\r\n    sendbuffer.l = true;\r\n    sendbuffer.base.volstep = 1.34;\r\n    sendbuffer.base.volTot = 1.56;\r\n\r\n    int  displacements&#x5B;nThreads], counts&#x5B;nThreads];\r\n\r\n    std::vector&lt;type_t&gt; recvbuffer(2);\r\n    std::cout &lt;&lt; my_rank &lt;&lt; &quot; Receiving...\\n&quot;;\r\n\r\n    int root_rank = 0;\r\n    displacements&#x5B;0] = 0;\r\n    displacements&#x5B;1] = 1;\r\n    counts&#x5B;0] = 1;\r\n    counts&#x5B;1] = 1;\r\n    \/\/ MPI_Gatherv(recvbuffer_send,count_send, datatype_send, recvbuffer_recv, counts_recv, displacements, datatype_recv, root,comm)\r\n    check(MPI_Gatherv(&amp;sendbuffer, 1, newMPItype, recvbuffer.data(), counts, displacements, newMPItype, root_rank, MPI_COMM_WORLD));\r\n    std::cout &lt;&lt; my_rank &lt;&lt; &quot; Done receiving\\n&quot;;\r\n\r\n    std::cout &lt;&lt; my_rank &lt;&lt; &quot; content of struct:\\n&quot;;\r\n    for(const type_t&amp; buf : recvbuffer) {\r\n      std::cout &lt;&lt; &quot;ID &quot;  &lt;&lt; buf.ID &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;i &quot;  &lt;&lt; buf.i &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;x &quot;  &lt;&lt; buf.x &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;d &quot;  &lt;&lt; buf.d &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;l &quot;  &lt;&lt; buf.l &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;volstep &quot;  &lt;&lt; buf.base.volstep &lt;&lt; &quot;\\n&quot;;\r\n      std::cout &lt;&lt; &quot;volTot &quot;  &lt;&lt; buf.base.volTot &lt;&lt; &quot;\\n\\n&quot;;\r\n    }\r\n}\r\n\r\nvoid doRank1(MPI_Datatype newMPItype) {\r\n    type_t sendbuffer;\r\n    int  displacements&#x5B;nThreads], counts&#x5B;nThreads];\r\n\r\n    strcpy(sendbuffer.ID, &quot;Kreis200&quot;);\r\n    sendbuffer.i = 20;\r\n    sendbuffer.x = 2.2;\r\n    sendbuffer.d = 2.23;\r\n    sendbuffer.l = true;\r\n    sendbuffer.base.volstep = 2.34;\r\n    sendbuffer.base.volTot = 2.56;\r\n\r\n    std::cout &lt;&lt; my_rank &lt;&lt; &quot; Sending...\\n&quot;;\r\n    \/\/ MPI_Gatherv(recvbuffer_send,count_send, datatype_send, recvbuffer_recv, counts_recv, displacements, datatype_recv, root,comm)\r\n    int root_rank = 0;\r\n    check(MPI_Gatherv(&amp;sendbuffer, 1, newMPItype, NULL, counts, displacements, newMPItype, root_rank, MPI_COMM_WORLD));\r\n    std::cout &lt;&lt; my_rank &lt;&lt; &quot; Done sending\\n&quot;;\r\n}\r\n\r\nint main(int argc, char* argv&#x5B;]) {\r\n    MPI_Init(&amp;argc, &amp;argv);\r\n\r\n    \/\/ Get number of processes and check only 2 processes are used\r\n    MPI_Comm_size(MPI_COMM_WORLD, &amp;nThreads);\r\n    if(nThreads != 2) {\r\n        std::cout &lt;&lt; &quot;Start with 2 threads.\\n&quot;;\r\n        MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);\r\n    }\r\n\r\n    MPI_Comm_rank(MPI_COMM_WORLD, &amp;my_rank);\r\n    MPI_Datatype newMPItype = createMPItyp();\r\n\r\n    switch(my_rank) {\r\n      case 0: doRank0(newMPItype); break;\r\n      case 1: doRank1(newMPItype); break;\r\n    };\r\n\r\n    MPI_Finalize();\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n\r\n<\/pre>\n<blockquote><p>$ mpic++ -g -ggdb -Wall test_MPI_struct.cpp <\/p>\n<p>$ mpiexec -n 2 .\/a.out<br \/>\n1 Sending...<br \/>\n1 Done sending<br \/>\nBase Address 7ffd83f7e180<br \/>\nAddresses    7ffd83f7e1b4 7ffd83f7e1b8 7ffd83f7e1bc 7ffd83f7e1c0 7ffd83f7e180 7ffd83f7e1c8 7ffd83f7e1d0<br \/>\nDisplacement 52 56 60 64 0 72 80<br \/>\n0 Receiving...<br \/>\n0 Done receiving<br \/>\n0 content of struct:<br \/>\nID Kreis100<br \/>\ni 10<br \/>\nx 1.2<br \/>\nd 1.23<br \/>\nl 1<br \/>\nvolstep 1.34<br \/>\nvolTot 1.56<\/p>\n<p>ID Kreis200<br \/>\ni 20<br \/>\nx 2.2<br \/>\nd 2.23<br \/>\nl 1<br \/>\nvolstep 2.34<br \/>\nvolTot 2.56\n<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Das Beispiel habe ich von https:\/\/www.mpi-forum.org\/docs\/mpi-3.1\/mpi31-report\/node425.htm Jeder Thread erstellt einen MPI Datentyp welcher die Offsett Addressen der struct Member Variablen hat. Thread 1 sendet Daten zu Thread 0 Thread 0 empfaenge Daten von Thread1 und seine eigenen Daten, so dass alle in einem Array dann liegen. \/\/ This example is based on https:\/\/www.mpi-forum.org\/docs\/mpi-3.1\/mpi31-report\/node425.htm \/\/ Jeder [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-5025","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/5025","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=5025"}],"version-history":[{"count":3,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/5025\/revisions"}],"predecessor-version":[{"id":5028,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/5025\/revisions\/5028"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5025"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}