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