OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
Message.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  ***************************************************************************/
7 
8 #ifndef MESSAGE_H
9 #define MESSAGE_H
10 
11 /***************************************************************************
12  * Message - contains a list of items that comprise a set of data to be
13  * sent, or received from, another node in a parallel architecture. A person
14  * creates a Message object, loads it with data to be sent, and gives it
15  * to a Communicate object.
16  *
17  * The message consists of N 'MsgItem' objects, which each contain some
18  * data; data is added sequentially to a new message using the 'put'
19  * routine, and extracted using the 'get' routine. The messages are
20  * retrieved in a FIFO fashion - you put in messages, and get them out
21  * in the order in which they were put in. You can access MsgItem's via
22  * random access with the [] operator, but it is important
23  * to actually remove the data using 'get' as this will properly deal with
24  * copying data and freeing up memory (if necessary).
25  *
26  * Note on usage: A Message is primarily intended to be created once,
27  * given to a Communicate instance to transmit to another node, and then
28  * to be unpacked or otherwise read by the receiver. A received message
29  * may be forwarded to another node, but it cannot be combined with another
30  * or used to initialize a copy of the Message. This is due to the problems
31  * of resolving who needs to free up the storage used for the Message elements.
32  ***************************************************************************/
33 
34 #include <complex>
35 #include <cstddef>
36 #include <vector>
37 #include <iostream>
38 #include <cstring>
39 #include <cstdlib>
40 
41 // forward declarations
42 class Communicate;
43 class Message;
44 std::ostream& operator<<(std::ostream& o, const Message& m);
45 
46 // Macros
48 // simple template traits class to tell if a type is a built-in type
49 // or not. The classes have an enum which is 1 if the type is build-in,
50 // 0 otherwise. The default case is 0, but specialized to 1 for other types.
51 template <class T>
53 {
54  enum { builtin = 0 };
55  enum { pointer = 0 };
56 };
57 
58 #define DEFINE_BUILTIN_TRAIT_CLASS(T) \
59 template <> \
60 struct MessageTypeIntrinsic<T> { \
61  enum { builtin = 1 }; \
62  enum { pointer = 0 }; \
63 }; \
64 template <> \
65 struct MessageTypeIntrinsic<T *> { \
66  enum { builtin = 1 }; \
67  enum { pointer = 1 }; \
68 }; \
69 template <int N> \
70 struct MessageTypeIntrinsic<T[N]> { \
71  enum { builtin = 1 }; \
72  enum { pointer = 1 }; \
73 };
74 
75 #define DEFINE_ALL_BUILTIN_TRAIT_CLASS(T) \
76 DEFINE_BUILTIN_TRAIT_CLASS(T) \
77 DEFINE_BUILTIN_TRAIT_CLASS(const T)
78 
92 
94 // a class to put single items into a Message, which can be specialized
95 // to the case of built-in types and other types.
96 
97 template <class T, bool builtin, bool pointer>
98 struct PutSingleItem { };
99 
100 // specialization to a non-built-in type, which is never assumed to be a ptr
101 template <class T>
102 struct PutSingleItem<T, false, false>
103 {
104  // put a value into a message
105  static Message& put(Message&, const T&);
106  // get a value out of a message
107  static Message& get(Message&, T&);
108  // version of put using a pair of iterators
109  static Message& put(Message&, T, T);
110  // version of put using a list of indices and an iterator
111  static Message& put(Message&, const std::vector<size_t>&, T);
112  // get_iter uses an output iterator
113  static Message& get_iter(Message&, T);
114 };
115 
116 // specialization to a built-in type that is not a pointer
117 template <class T>
118 struct PutSingleItem<T, true, false>
119 {
120  // put a value into a message
121  static Message& put(Message&, const T&);
122  // get a value out of a message
123  static Message& get(Message&, T&);
124 };
125 
126 // specialization to a pointer to a built-in type. In this class, we
127 // know that 'T' is a pointer type.
128 template <class T>
129 struct PutSingleItem<T, true, true>
130 {
131  // put using a pair of pointers
132  static Message& put(Message&, T, T);
133  // get using a pointer
134  static Message& get(Message&, T);
135  // put using a list of indices and a pointer
136  static Message& put(Message&, const std::vector<size_t>&, T);
137  // get using an output iterator
138  static Message& get_iter(Message&, T);
139 };
140 
141 
142 class Message
143 {
144 
145 public:
146  // a class which stores a single message element. This will either store
147  // a reference to the data (if copy=false), make an internal copy (if
148  // copy=true, and it is large enough), or put the data into an internal
149  // fast buffer (the MsgItemBuf struct).
150  class MsgItem
151  {
152  private:
153  // a very simple struct for storing MsgItem data
154  struct MsgItemBuf
155  {
156  unsigned long long d1, d2, d3, d4;
157 
159  MsgItemBuf(const MsgItemBuf& m) : d1(m.d1),d2(m.d2),d3(m.d3),d4(m.d4) {}
161  };
162 
163  public:
164 
165  // default constructor
166  MsgItem() : item(0), elements(0), bytesize(0), needDelete(false) { }
167 
168  // regular constructor, with data to store
169  MsgItem(void *d, unsigned int elems, unsigned int totbytes,
170  bool needcopy, bool needdel) : item(&defbuf), elements(elems),
171  bytesize(totbytes), needDelete(needdel)
172  {
173  if (totbytes > 0 && d != 0)
174  {
175  if (needcopy)
176  {
177  if (totbytes <= sizeof(MsgItemBuf))
178  {
179  // copy data into internal buffer
180  needDelete = false;
181  }
182  else
183  {
184  // malloc and copy over data
185  item = malloc(totbytes);
186  needDelete = true;
187  }
188  memcpy(item, d, totbytes);
189  }
190  else
191  {
192  // we just store a reference, we do not copy
193  item = d;
194  }
195  }
196  else
197  {
198  // no data in message
199  item = 0;
200  elements = 0;
201  needDelete = false;
202  }
203  }
204 
205  // copy constructor
208  {
209  // either we just copy the 'item' pointer, or we copy the default buf
210  if (m.item != &(m.defbuf))
211  item = m.item;
212  }
213 
214  // destructor
215  ~MsgItem() { }
216 
217  // return our total byte size, number of elements, and elem size
218  unsigned int numBytes() const
219  {
220  return bytesize;
221  }
222  unsigned int numElems() const
223  {
224  return elements;
225  }
226  unsigned int elemSize() const
227  {
228  return (elements>0?bytesize/elements:0);
229  }
230 
231  // will we need to delete our data?
232  bool willNeedDelete() const
233  {
234  return (needDelete && item != 0);
235  }
236 
237  // cancel the need to delete the data
239  {
240  needDelete = false;
241  }
242 
243  // return our item pointer
244  void *data()
245  {
246  return item;
247  }
248 
249  // delete our data item
250  void deleteData()
251  {
252  if (willNeedDelete())
253  free(item);
254  }
255 
256  private:
257  // pointer to the item; must be newed/deleted, or pointing to defbuf
258  void *item;
259 
260  // number of individual elements, and total storage size in bytes
261  unsigned int elements, bytesize;
262 
263  // default storage space; used for speed
265 
266  // do we need to delete this item storage?
268  };
269 
270 public:
271  //
272  // constructors and destructors
273  //
274 
275  // 'default' constructor: just make an empty message, optionally requesting
276  // how many items we should preallocate space for
277  Message(unsigned int numelems = 8)
278  : numRemoved(0), DoCopy(true), DoDelete(true), comm(0), commdata(0)
279  {
280  MsgItemList.reserve(numelems);
281  }
282 
283  // destructor: delete all items in this message, as if 'get' had been
284  // called for all the items
285  ~Message();
286 
287  //
288  // global Message operations
289  //
290 
291  // return number of items left in this message
292  size_t size() const
293  {
294  return (MsgItemList.size() - numRemoved);
295  }
296  size_t removed() const
297  {
298  return numRemoved;
299  }
300  bool empty() const
301  {
302  return (size() == 0);
303  }
304 
305  // returns a reference to the Nth MsgItem. Note that 'n' refers
306  // to the index from te first unremoved item, and that 'get' and 'remove'
307  // will remove the top item.
308  MsgItem& item(size_t n)
309  {
310  return MsgItemList[n + numRemoved];
311  }
312  const MsgItem& item(size_t n) const
313  {
314  return MsgItemList[n+numRemoved];
315  }
316 
317  // indicate that the next message item should be copied (t) or just
318  // remembered via a pointer (f)
319  Message& setCopy(const bool c)
320  {
321  DoCopy = c;
322  return *this;
323  }
324  bool willCopy() const
325  {
326  return DoCopy;
327  }
328 
329  // indicate that the next message item memory should be deleted by this
330  // object when the Message is deleted (t)
331  Message& setDelete(const bool c)
332  {
333  DoDelete = c;
334  return *this;
335  }
336  bool willDelete() const
337  {
338  return DoDelete;
339  }
340 
341  // clear the message; deletes all its items
342  Message& clear();
343 
344  // return and remove the next item from this message ... if the item
345  // does not exist, NULL is returned. This is similar to get, except that
346  // just a void* pointer to the data is returned (instead of having the
347  // data copied into given storage), and this data is DEFINITELY a malloced
348  // block of data that the user must deallocate using 'free' (NOT delete).
349  // Like 'get', after this is called, the top MsgItem is removed.
350  // If you wish to just access the Nth item's item pointer, use
351  // item(N).item .
352  void *remove();
353 
354  // tell this Message to call the special function 'cleanupMessage' with
355  // the provided pointer, in case the message is using buffer space
356  // allocated by the Communicate object. If no Communicate object has
357  // been provided, nothing is done
358  void useCommunicate(Communicate *c, void *d)
359  {
360  comm = c;
361  commdata = d;
362  }
363 
364  //
365  // routines to get and put data out of/into the message.
366  //
367 
368  // NOTES for 'put' routines:
369  // For intrinsic scalar values, there is one argument: the scalar item.
370  // For arrays, there are two arguments: the begining and (one-past-end)
371  // pointers (i.e. like iterators, but restricted to pointers).
372  // For any other arbitrary type, calling put will in turn call the method
373  // 'putMessage' in the provided object. 'putMessage' can then call put
374  // to put in the proper intrinsic-type objects.
375  //
376  // When putting in data, you can have the data copied over, or just have
377  // a pointer stored. If a pointer is stored (copy=F), you must also
378  // specify whether this Message object should be responsible for deleting
379  // the data (delstor=T), or should just leave the storage alone after the
380  // data has been retrieved with get. These flags are set by calling
381  // 'setCopy' and 'setDelete' with the desired setting. After an item
382  // has been 'put', the are set back to the default values 'copy=true' and
383  // 'delete=true'. You can use them in this way:
384  // Message msg;
385  // msg.setCopy(false).setDelete(false).put(data);
386  // copy and delstor are used to increase performance. They
387  // should be used in the following circumstances:
388  // a. Data to be sent/rec is in a location that will not change before the
389  // msg is used, but should not be affected after the Message is deleted.
390  // For this case, use copy=F, delstor=F.
391  // b. Data for a message has already had space allocated for it, and so
392  // does not need to be copied. Also, since the space has been allocated
393  // already, it must be freed when the msg is sent. For this case, use
394  // copy=F, delstor=T.
395  // c. For data that is in a volatile location, it must be copied to new
396  // storage, so use copy=T, and don't specify any value for delstor (it will
397  // be ignored if copy=T).
398 
399  // general templated version of put
400  // for an arbitrary type, call the function 'putMessage' with this
401  // message so that it can put in data any way it wants. That function
402  // should return a reference to this message.
403  // 'putMessage' should be defined as:
404  // Message& putMessage(Message &);
405  template <class T>
406  Message& put(const T& val)
407  {
408  return PutSingleItem<T,
411  }
412 
413  // specialized versions of put for character strings
414  /*
415  Message &put(char *d) { // null-terminated string
416  return putmsg((void *)d, sizeof(char), strlen(d) + 1);
417  }
418  */
419  Message &put(const char *d) // null-terminated string
420  {
421  return putmsg((void *)d, sizeof(char), strlen(d) + 1);
422  }
423  // specialized version for string class
424  Message& put(const std::string& s)
425  {
426  int len = s.length() + 1;
427  put(len);
428  put(s.c_str());
429  return *this;
430  }
431 
432  // general templated version of put for two iterators
433  // Template put using a pair of iterators. This version is called by
434  // the public 'put' with two iterators after getting the proper type
435  // of the data pointed to by the iterators
436  template <class ForwardIterator>
437  Message& put(ForwardIterator beg, ForwardIterator end)
438  {
439  return PutSingleItem<ForwardIterator,
442  *this, beg, end);
443  }
444 
445  // for using an indirection list
446  // Template put using an indirection list. This version is called by
447  // the public 'put' with an indirection list and a RandomAccessIterator
448  // after getting the proper type of the data pointed to by the iterator
449  template <class RandomAccessIterator>
450  Message& put(const std::vector<size_t>& indices,
451  RandomAccessIterator beg)
452  {
453  return PutSingleItem<RandomAccessIterator,
456  indices, beg);
457  }
458 
459  // general put routine; called by other cases
460  // arguments are the item, its element size (in bytes),
461  // and how many items total to copy (if 0, this is a scalar).
462  Message &putmsg(void *, int, int = 0);
463 
464 
465  // general templated version of get, for a ref or a pointer
466  // for an arbitrary type, call the function 'getMessage' with this
467  // message so that it can get data any way it wants. That function
468  // should return a reference to this message.
469  // 'getMessage' should be defined as:
470  // Message& getMessage(Message &);
471  // NOTE: the argument is a const ref, but will be cast to non-const,
472  // to eliminate warning messages about anachronisms.
474  // general templated version of get.
475  template <class T>
476  Message& get(const T& cval)
477  {
478  T& val = const_cast<T&>(cval);
479  return PutSingleItem<T,
482  }
483 
484  // specialized version for string class
485  Message& get(const std::string& s)
486  {
487  std::string& ncs = const_cast<std::string&>(s);
488  int len = 0;
489  get(len);
490  char* cstring = new char[len];
491  get(cstring);
492  ncs = cstring;
493  delete [] cstring;
494  return *this;
495  }
496 
497  // this version of get just removes the data without copying it
499  {
500  return getmsg(0);
501  }
502 
503  // an iterator-based version of get, which uses a general
504  // iterator approach to copy the data out of the storage into
505  // the space pointed to by the given iterator
507  // Template get using a pair of iterators. This version is called by
508  // the public 'get' with two iterators after getting the proper type
509  // of the data pointed to by the iterators
510  template <class OutputIterator>
511  Message& get_iter(OutputIterator o)
512  {
513  return PutSingleItem<OutputIterator,
516  }
517 
518  // general get routine; called by other cases
519  // arguments are the location where to write the data, and the type
520  // of the data.
521  Message &getmsg(void *);
522 
523 private:
524  // MsgItem's that are in this message
525  std::vector<MsgItem> MsgItemList;
526 
527  // number of elements that have been removed (via get or remove)
528  size_t numRemoved;
529 
530  // should we copy the next added item? if not, just store pointer
531  bool DoCopy;
532 
533  // should we be responsible for deleting the next item?
534  bool DoDelete;
535 
536  // a Communicate object which should be informed when this object is
537  // deleted, and a comm-supplied object that it might need
539  void *commdata;
540 
541  // delete the data in the top MsgItem, and remove that item from the top
542  // (by incrementing numRemoved)
543  void deleteMsgItem();
544 };
545 
546 
547 // General template for the put routine:
548 template<class T>
549 inline void putMessage(Message &m, const T &t)
550 {
551  m.put(t);
552 }
553 
554 // for using a pair of iterators
555 template<class ForwardIterator>
556 inline void putMessage(Message &m, ForwardIterator beg, ForwardIterator end)
557 {
558  m.put(beg, end);
559 }
560 
561 // for using an indirection list
562 template <class RandomAccessIterator>
563 inline void putMessage(Message &m, const std::vector<size_t> &v,
564  RandomAccessIterator r)
565 {
566  m.put(v, r);
567 }
568 
569 
570 // General template for the get routine:
571 template<class T>
572 inline void getMessage(Message &m, T &t)
573 {
574  m.get(t);
575 }
576 
577 // this templated version of getMessage is for arbitrary pointers
578 template<class T>
579 inline void getMessage(Message &m, T *t)
580 {
581  m.get_iter(t);
582 }
583 
584 // this templated version of getMessage is for arbitrary pointers
585 template<class T>
586 inline void getMessage(Message &m, T *t, T *)
587 {
588  m.get_iter(t);
589 }
590 
591 // an iterator-based version of get, which uses a general
592 // iterator approach to copy the data out of the storage into
593 // the space pointed to by the given iterator
594 template<class OutputIterator>
595 inline void getMessage_iter(Message &m, OutputIterator o)
596 {
597  m.get_iter(o);
598 }
599 
600 #include "Message/Message.hpp"
601 
602 #endif // MESSAGE_H
elements
Definition: IndexMap.cpp:163
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
void putMessage(Message &m, const T &t)
Definition: Message.h:549
#define DEFINE_ALL_BUILTIN_TRAIT_CLASS(T)
Definition: Message.h:75
std::ostream & operator<<(std::ostream &o, const Message &m)
void getMessage_iter(Message &m, OutputIterator o)
Definition: Message.h:595
void getMessage(Message &m, T &t)
Definition: Message.h:572
MMatrix< m_complex > complex(MMatrix< double > real)
Definition: MMatrix.cpp:396
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:51
Message & put(const char *d)
Definition: Message.h:419
Message & setDelete(const bool c)
Definition: Message.h:331
bool willDelete() const
Definition: Message.h:336
size_t size() const
Definition: Message.h:292
void deleteMsgItem()
Message & put(const std::vector< size_t > &indices, RandomAccessIterator beg)
Definition: Message.h:450
Message & put(const T &val)
Definition: Message.h:406
Message & get()
Definition: Message.h:498
Message & putmsg(void *, int, int=0)
size_t numRemoved
Definition: Message.h:528
Message & get_iter(OutputIterator o)
Definition: Message.h:511
Message & getmsg(void *)
void * commdata
Definition: Message.h:539
Message & clear()
Message(unsigned int numelems=8)
Definition: Message.h:277
bool DoDelete
Definition: Message.h:534
std::vector< MsgItem > MsgItemList
Definition: Message.h:525
const MsgItem & item(size_t n) const
Definition: Message.h:312
bool DoCopy
Definition: Message.h:531
void * remove()
size_t removed() const
Definition: Message.h:296
Message & put(ForwardIterator beg, ForwardIterator end)
Definition: Message.h:437
bool empty() const
Definition: Message.h:300
void useCommunicate(Communicate *c, void *d)
Definition: Message.h:358
Message & setCopy(const bool c)
Definition: Message.h:319
Message & put(const std::string &s)
Definition: Message.h:424
MsgItem & item(size_t n)
Definition: Message.h:308
bool willCopy() const
Definition: Message.h:324
Message & get(const T &cval)
Definition: Message.h:476
Message & get(const std::string &s)
Definition: Message.h:485
Communicate * comm
Definition: Message.h:538
unsigned int numBytes() const
Definition: Message.h:218
MsgItemBuf defbuf
Definition: Message.h:264
MsgItem(void *d, unsigned int elems, unsigned int totbytes, bool needcopy, bool needdel)
Definition: Message.h:169
void deleteData()
Definition: Message.h:250
void cancelDelete()
Definition: Message.h:238
void * data()
Definition: Message.h:244
unsigned int elemSize() const
Definition: Message.h:226
bool willNeedDelete() const
Definition: Message.h:232
unsigned int bytesize
Definition: Message.h:261
unsigned int numElems() const
Definition: Message.h:222
MsgItem(const MsgItem &m)
Definition: Message.h:206
unsigned int elements
Definition: Message.h:261
unsigned long long d2
Definition: Message.h:156
unsigned long long d1
Definition: Message.h:156
MsgItemBuf(const MsgItemBuf &m)
Definition: Message.h:159
unsigned long long d4
Definition: Message.h:156
unsigned long long d3
Definition: Message.h:156