packing.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 #ifndef LIBMESH_PACKING_H
20 #define LIBMESH_PACKING_H
21 
22 // libMesh Includes
23 #include "libmesh/libmesh_common.h"
24 
25 // C++ includes
26 #include <cstddef>
27 #include <iterator>
28 #include <vector>
29 
30 namespace libMesh
31 {
32 
33 namespace Parallel
34 {
35 
43 template <typename T>
44 class Packing {
45 public:
46  // Should be an MPI sendable type in specializations, e.g.
47  // typedef char buffer_type;
48  // typedef unsigned int buffer_type;
49 
50  // Should copy an encoding of the provided object into the provided
51  // output iterator (which is of type buffer_type)
52  template <typename OutputIter, typename Context>
53  static void pack(const T & object,
54  OutputIter data_out,
55  const Context * context);
56 
57  // Should return the number of array entries (of type buffer_type)
58  // required to encode the provided object
59  template <typename Context>
60  static unsigned int packable_size(const T & object,
61  const Context * context);
62 
63  // Should return the number of array entries which were used to
64  // encode the provided serialization of an object which begins at
65  // \p iter
66  template <typename BufferIter>
67  static unsigned int packed_size(BufferIter iter);
68 
69  // Decode a potentially-variable-size object from a subsequence of a
70  // data array, returning a heap-allocated pointer to the result.
71  template <typename BufferIter, typename Context>
72  static T unpack(BufferIter in, Context * ctx);
73 };
74 
75 
80 template <typename Context, typename buffertype,
81  typename OutputIter, typename T>
82 inline void unpack_range (const typename std::vector<buffertype> & buffer,
83  Context * context,
84  OutputIter out,
85  const T * output_type /* used only to infer T */);
86 
95 template <typename Context, typename buffertype, typename Iter>
96 inline Iter pack_range (const Context * context,
97  Iter range_begin,
98  const Iter range_end,
99  typename std::vector<buffertype> & buffer,
100  std::size_t approx_buffer_size = 1000000);
101 
106 template <typename Context, typename Iter>
107 inline std::size_t packed_range_size (const Context * context,
108  Iter range_begin,
109  const Iter range_end);
110 
111 // ------------------------------------------------------------
112 // Packing member functions, global functions
113 
117 template <typename Context, typename Iter>
118 inline std::size_t packed_range_size (const Context * context,
119  Iter range_begin,
120  const Iter range_end)
121 {
122  typedef typename std::iterator_traits<Iter>::value_type T;
123 
124  std::size_t buffer_size = 0;
125  for (Iter range_count = range_begin;
126  range_count != range_end;
127  ++range_count)
128  {
129  buffer_size += Parallel::Packing<T>::packable_size(*range_count, context);
130  }
131  return buffer_size;
132 }
133 
134 
138 template <typename Context, typename buffertype, typename Iter>
139 inline Iter pack_range (const Context * context,
140  Iter range_begin,
141  const Iter range_end,
142  std::vector<buffertype> & buffer,
143  // When we serialize into buffers, we need to use large buffers to optimize MPI
144  // bandwidth, but not so large as to risk allocation failures. max_buffer_size
145  // is measured in number of buffer type entries; number of bytes may be 4 or 8
146  // times larger depending on configuration.
147  std::size_t approx_buffer_size)
148 {
149  typedef typename std::iterator_traits<Iter>::value_type T;
150 
151  // Count the total size of and preallocate buffer for efficiency.
152  // Prepare to stop early if the buffer would be too large.
153  std::size_t buffer_size = 0;
154  Iter range_stop = range_begin;
155  for (; range_stop != range_end && buffer_size < approx_buffer_size;
156  ++range_stop)
157  {
158  std::size_t next_buffer_size =
159  Parallel::Packing<T>::packable_size(*range_stop, context);
160  buffer_size += next_buffer_size;
161  }
162  buffer.reserve(buffer.size() + buffer_size);
163 
164  // Pack the objects into the buffer
165  for (; range_begin != range_stop; ++range_begin)
166  {
167 #ifndef NDEBUG
168  std::size_t old_size = buffer.size();
169 #endif
170 
172  (*range_begin, back_inserter(buffer), context);
173 
174 #ifndef NDEBUG
175  unsigned int my_packable_size =
176  Parallel::Packing<T>::packable_size(*range_begin, context);
177  unsigned int my_packed_size =
178  Parallel::Packing<T>::packed_size (buffer.begin() + old_size);
179  libmesh_assert_equal_to (my_packable_size, my_packed_size);
180  libmesh_assert_equal_to (buffer.size(), old_size + my_packable_size);
181 #endif
182  }
183 
184  return range_stop;
185 }
186 
187 
188 
192 template <typename Context, typename buffertype,
193  typename OutputIter, typename T>
194 inline void unpack_range (const std::vector<buffertype> & buffer,
195  Context * context,
196  OutputIter out_iter,
197  const T * /* output_type */)
198 {
199  // Loop through the buffer and unpack each object, returning the
200  // object pointer via the output iterator
201  typename std::vector<buffertype>::const_iterator
202  next_object_start = buffer.begin();
203 
204  while (next_object_start < buffer.end())
205  {
206  *out_iter++ = Parallel::Packing<T>::unpack(next_object_start, context);
207  next_object_start +=
208  Parallel::Packing<T>::packed_size(next_object_start);
209  }
210 
211  // We should have used up the exact amount of data in the buffer
212  libmesh_assert (next_object_start == buffer.end());
213 }
214 
215 
216 } // namespace Parallel
217 
218 } // namespace libMesh
219 
220 #endif // LIBMESH_PACKING_H
Iter pack_range(const Context *context, Iter range_begin, const Iter range_end, typename std::vector< buffertype > &buffer, std::size_t approx_buffer_size=1000000)
Definition: packing.h:139
std::size_t packed_range_size(const Context *context, Iter range_begin, const Iter range_end)
Definition: packing.h:118
static unsigned int packable_size(const T &object, const Context *context)
static unsigned int packed_size(BufferIter iter)
static void pack(const T &object, OutputIter data_out, const Context *context)
OStreamProxy out(std::cout)
void unpack_range(const typename std::vector< buffertype > &buffer, Context *context, OutputIter out, const T *output_type)
static T unpack(BufferIter in, Context *ctx)