skeleton_and_content.qbk 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. [section:skeleton_and_content Separating structure from content]
  2. When communicating data types over MPI that are not fundamental to MPI
  3. (such as strings, lists, and user-defined data types), Boost.MPI must
  4. first serialize these data types into a buffer and then communicate
  5. them; the receiver then copies the results into a buffer before
  6. deserializing into an object on the other end. For some data types,
  7. this overhead can be eliminated by using [classref
  8. boost::mpi::is_mpi_datatype `is_mpi_datatype`]. However,
  9. variable-length data types such as strings and lists cannot be MPI
  10. data types.
  11. Boost.MPI supports a second technique for improving performance by
  12. separating the structure of these variable-length data structures from
  13. the content stored in the data structures. This feature is only
  14. beneficial when the shape of the data structure remains the same but
  15. the content of the data structure will need to be communicated several
  16. times. For instance, in a finite element analysis the structure of the
  17. mesh may be fixed at the beginning of computation but the various
  18. variables on the cells of the mesh (temperature, stress, etc.) will be
  19. communicated many times within the iterative analysis process. In this
  20. case, Boost.MPI allows one to first send the "skeleton" of the mesh
  21. once, then transmit the "content" multiple times. Since the content
  22. need not contain any information about the structure of the data type,
  23. it can be transmitted without creating separate communication buffers.
  24. To illustrate the use of skeletons and content, we will take a
  25. somewhat more limited example wherein a master process generates
  26. random number sequences into a list and transmits them to several
  27. slave processes. The length of the list will be fixed at program
  28. startup, so the content of the list (i.e., the current sequence of
  29. numbers) can be transmitted efficiently. The complete example is
  30. available in `example/random_content.cpp`. We being with the master
  31. process (rank 0), which builds a list, communicates its structure via
  32. a [funcref boost::mpi::skeleton `skeleton`], then repeatedly
  33. generates random number sequences to be broadcast to the slave
  34. processes via [classref boost::mpi::content `content`]:
  35. // Generate the list and broadcast its structure
  36. std::list<int> l(list_len);
  37. broadcast(world, mpi::skeleton(l), 0);
  38. // Generate content several times and broadcast out that content
  39. mpi::content c = mpi::get_content(l);
  40. for (int i = 0; i < iterations; ++i) {
  41. // Generate new random values
  42. std::generate(l.begin(), l.end(), &random);
  43. // Broadcast the new content of l
  44. broadcast(world, c, 0);
  45. }
  46. // Notify the slaves that we're done by sending all zeroes
  47. std::fill(l.begin(), l.end(), 0);
  48. broadcast(world, c, 0);
  49. The slave processes have a very similar structure to the master. They
  50. receive (via the [funcref boost::mpi::broadcast
  51. `broadcast()`] call) the skeleton of the data structure, then use it
  52. to build their own lists of integers. In each iteration, they receive
  53. via another `broadcast()` the new content in the data structure and
  54. compute some property of the data:
  55. // Receive the content and build up our own list
  56. std::list<int> l;
  57. broadcast(world, mpi::skeleton(l), 0);
  58. mpi::content c = mpi::get_content(l);
  59. int i = 0;
  60. do {
  61. broadcast(world, c, 0);
  62. if (std::find_if
  63. (l.begin(), l.end(),
  64. std::bind1st(std::not_equal_to<int>(), 0)) == l.end())
  65. break;
  66. // Compute some property of the data.
  67. ++i;
  68. } while (true);
  69. The skeletons and content of any Serializable data type can be
  70. transmitted either via the [memberref
  71. boost::mpi::communicator::send `send`] and [memberref
  72. boost::mpi::communicator::recv `recv`] members of the
  73. [classref boost::mpi::communicator `communicator`] class
  74. (for point-to-point communicators) or broadcast via the [funcref
  75. boost::mpi::broadcast `broadcast()`] collective. When
  76. separating a data structure into a skeleton and content, be careful
  77. not to modify the data structure (either on the sender side or the
  78. receiver side) without transmitting the skeleton again. Boost.MPI can
  79. not detect these accidental modifications to the data structure, which
  80. will likely result in incorrect data being transmitted or unstable
  81. programs.
  82. [endsect:skeleton_and_content]