phdMesh Version of the Day
ParallelComm.hpp
00001 /*------------------------------------------------------------------------*/
00002 /*      phdMesh : Parallel Heterogneous Dynamic unstructured Mesh         */
00003 /*                Copyright (2007) Sandia Corporation                     */
00004 /*                                                                        */
00005 /*  Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive   */
00006 /*  license for use of this work by or on behalf of the U.S. Government.  */
00007 /*                                                                        */
00008 /*  This library is free software; you can redistribute it and/or modify  */
00009 /*  it under the terms of the GNU Lesser General Public License as        */
00010 /*  published by the Free Software Foundation; either version 2.1 of the  */
00011 /*  License, or (at your option) any later version.                       */
00012 /*                                                                        */
00013 /*  This library is distributed in the hope that it will be useful,       */
00014 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
00015 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     */
00016 /*  Lesser General Public License for more details.                       */
00017 /*                                                                        */
00018 /*  You should have received a copy of the GNU Lesser General Public      */
00019 /*  License along with this library; if not, write to the Free Software   */
00020 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307   */
00021 /*  USA                                                                   */
00022 /*------------------------------------------------------------------------*/
00028 #ifndef util_ParallelComm_hpp
00029 #define util_ParallelComm_hpp
00030 
00031 #include <cstddef>
00032 #include <iosfwd>
00033 #include <util/Basics.hpp>
00034 #include <util/Parallel.hpp>
00035 
00036 //------------------------------------------------------------------------
00037 
00038 namespace phdmesh {
00039 
00048 class CommAll ;
00049 
00052 class CommBuffer ;
00053 
00066 bool comm_sizes( ParallelMachine ,
00067                  const unsigned   num_msg_bound ,
00068                        unsigned & num_msg_maximum ,
00069                  const unsigned * const send_size ,
00070                        unsigned * const recv_size ,
00071                  bool local_flag = false );
00072 
00075 bool comm_dense_sizes( ParallelMachine ,
00076                        const unsigned * const send_size ,
00077                              unsigned * const recv_size ,
00078                        bool local_flag = false );
00079 
00080 //------------------------------------------------------------------------
00081 
00082 class CommBuffer {
00083 public:
00084 
00086   template<typename T> void pack( const T & value );
00087 
00089   template<typename T> void pack( const T * value , size_t number );
00090 
00092   template<typename T> void unpack( T & value );
00093 
00095   template<typename T> void unpack( T * value , size_t number );
00096 
00098   template<typename T> void peek( T & value );
00099 
00101   template<typename T> void peek( T * value , size_t number );
00102 
00104   template<typename T> void skip( size_t number );
00105 
00107   void reset();
00108 
00112   size_t capacity() const ;
00113 
00118   size_t size() const ;
00119 
00126   ptrdiff_t remaining() const ;
00127 
00129   void * buffer() const ;
00130 
00131   ~CommBuffer();
00132   CommBuffer();
00133 
00134 private:
00135   friend class CommAll ;
00136   friend class CommGather ;
00137   friend class CommBroadcast ;
00138 
00139   static CommBuffer * allocate( const unsigned, const unsigned * const );
00140   static void deallocate( const unsigned , CommBuffer * );
00141 
00142   void pack_overflow() const ;
00143   void unpack_overflow() const ;
00144 
00145   CommBuffer( const CommBuffer & );
00146   CommBuffer & operator = ( const CommBuffer & );
00147 
00148   typedef unsigned char * ucharp ;
00149 
00150   ucharp m_beg ;
00151   ucharp m_ptr ;
00152   ucharp m_end ;
00153 };
00154 
00155 //------------------------------------------------------------------------
00156 
00157 class CommAll {
00158 public:
00159 
00160   ParallelMachine parallel()      const { return m_comm ; }
00161   unsigned        parallel_size() const { return m_size ; }
00162   unsigned        parallel_rank() const { return m_rank ; }
00163 
00165   CommBuffer & send_buffer( unsigned ) const ;
00166 
00168   CommBuffer & recv_buffer( unsigned ) const ;
00169 
00170   //----------------------------------------
00174   CommAll();
00175 
00183   bool allocate_buffers( ParallelMachine ,
00184                          const unsigned num_msg_bounds ,
00185                          const unsigned * const send_size ,
00186                          const unsigned * const recv_size ,
00187                          const bool local_flag = false );
00188 
00189   //----------------------------------------
00202   explicit CommAll( ParallelMachine );
00203 
00210   bool allocate_buffers( const unsigned num_msg_bounds ,
00211                          const bool symmetric = false ,
00212                          const bool local_flag = false );
00213 
00214   //----------------------------------------
00216   void communicate();
00217 
00218   //----------------------------------------
00220   void swap_send_recv();
00221 
00225   void reset_buffers();
00226 
00227   ~CommAll();
00228 
00229 private:
00230 
00231   CommAll( const CommAll & );
00232   CommAll & operator = ( const CommAll & );
00233 
00234   void rank_error( const char * , unsigned ) const ;
00235 
00236   bool allocate_buffers( const unsigned * const send_size ,
00237                          const unsigned * const recv_size ,
00238                          bool local_flag );
00239 
00240   ParallelMachine m_comm ;
00241   unsigned        m_size ;
00242   unsigned        m_rank ;
00243   unsigned        m_bound ;
00244   unsigned        m_max ;
00245   CommBuffer    * m_send ;
00246   CommBuffer    * m_recv ;
00247 };
00248 
00249 //------------------------------------------------------------------------
00250 
00251 class CommBroadcast {
00252 public:
00253 
00254   ParallelMachine parallel()      const { return m_comm ; }
00255   unsigned        parallel_size() const { return m_size ; }
00256   unsigned        parallel_rank() const { return m_rank ; }
00257 
00259   CommBuffer & send_buffer();
00260 
00262   CommBuffer & recv_buffer();
00263 
00264   //----------------------------------------
00265 
00266   CommBroadcast( ParallelMachine , unsigned root_rank );
00267 
00268   void communicate();
00269 
00270   bool allocate_buffer( const bool local_flag = false );
00271 
00272   ~CommBroadcast();
00273 
00274 private:
00275 
00276   CommBroadcast();
00277   CommBroadcast( const CommBroadcast & );
00278   CommBroadcast & operator = ( const CommBroadcast & );
00279 
00280   ParallelMachine m_comm ;
00281   unsigned        m_size ;
00282   unsigned        m_rank ;
00283   unsigned        m_root_rank ;
00284   CommBuffer      m_buffer ;
00285 };
00286 
00287 //----------------------------------------------------------------------
00288 
00289 class CommGather {
00290 public:
00291 
00292   ParallelMachine parallel()      const { return m_comm ; }
00293   unsigned        parallel_size() const { return m_size ; }
00294   unsigned        parallel_rank() const { return m_rank ; }
00295 
00296   ~CommGather();
00297 
00298   CommGather( ParallelMachine , unsigned root_rank , unsigned send_size );
00299 
00300   CommBuffer & send_buffer() { return m_send ; }
00301 
00302   void communicate();
00303 
00304   CommBuffer & recv_buffer( unsigned );
00305 
00306   void reset(); 
00307 
00308 private:
00309 
00310   CommGather();
00311   CommGather( const CommBroadcast & );
00312   CommGather & operator = ( const CommBroadcast & );
00313 
00314   ParallelMachine m_comm ;
00315   unsigned        m_size ;
00316   unsigned        m_rank ;
00317   unsigned        m_root_rank ;
00318   CommBuffer      m_send ;
00319   CommBuffer    * m_recv ;
00320   int           * m_recv_count ;
00321   int           * m_recv_displ ;
00322 };
00323 
00324 }
00325 
00326 //----------------------------------------------------------------------
00327 //----------------------------------------------------------------------
00328 // Inlined template implementations for the CommBuffer
00329 
00330 namespace phdmesh {
00331 
00332 template<unsigned N> struct CommBufferAlign ;
00333 
00334 template<>
00335 struct CommBufferAlign<1> {
00336   static size_t align( size_t ) { return 0 ; }
00337 };
00338 
00339 template<unsigned N>
00340 struct CommBufferAlign {
00341   static size_t align( size_t i ) { i %= N ; return i ? ( N - i ) : 0 ; }
00342 };
00343 
00344 template<typename T>
00345 inline
00346 void CommBuffer::pack( const T & value )
00347 {
00348   enum { Size = sizeof(T) };
00349   size_t nalign = CommBufferAlign<Size>::align( m_ptr - m_beg );
00350   if ( m_beg ) {
00351     if ( m_end < m_ptr + nalign + Size ) { pack_overflow(); }
00352     while ( nalign ) { --nalign ; *m_ptr = 0 ; ++m_ptr ; }
00353     T * tmp = reinterpret_cast<T*>(m_ptr);
00354     *tmp = value ;
00355     m_ptr = reinterpret_cast<ucharp>( ++tmp );
00356   }
00357   else {
00358     m_ptr += nalign + Size ;
00359   }
00360 }
00361 
00362 template<typename T>
00363 inline
00364 void CommBuffer::pack( const T * value , size_t number )
00365 {
00366   enum { Size = sizeof(T) };
00367   size_t nalign = CommBufferAlign<Size>::align( m_ptr - m_beg );
00368   if ( m_beg ) {
00369     if ( m_end < m_ptr + nalign + number * Size ) { pack_overflow(); }
00370     while ( nalign ) { --nalign ; *m_ptr = 0 ; ++m_ptr ; }
00371     T * tmp = reinterpret_cast<T*>(m_ptr);
00372     while ( number ) { --number ; *tmp = *value ; ++tmp ; ++value ; }
00373     m_ptr = reinterpret_cast<ucharp>( tmp );
00374   }
00375   else {
00376     m_ptr += nalign + number * Size ;
00377   }
00378 }
00379 
00380 template<typename T>
00381 inline
00382 void CommBuffer::skip( size_t number )
00383 {
00384   enum { Size = sizeof(T) };
00385   m_ptr += CommBufferAlign<Size>::align( m_ptr - m_beg ) + Size * number ;
00386   if ( m_beg && m_end < m_ptr ) { unpack_overflow(); }
00387 }
00388 
00389 template<typename T>
00390 inline
00391 void CommBuffer::unpack( T & value )
00392 {
00393   enum { Size = sizeof(T) };
00394   const size_t nalign = CommBufferAlign<Size>::align( m_ptr - m_beg );
00395   T * tmp = reinterpret_cast<T*>( m_ptr + nalign );
00396   value = *tmp ;
00397   m_ptr = reinterpret_cast<ucharp>( ++tmp );
00398   if ( m_end < m_ptr ) { unpack_overflow(); }
00399 }
00400 
00401 template<typename T>
00402 inline
00403 void CommBuffer::unpack( T * value , size_t number )
00404 {
00405   enum { Size = sizeof(T) };
00406   const size_t nalign = CommBufferAlign<Size>::align( m_ptr - m_beg );
00407   T * tmp = reinterpret_cast<T*>( m_ptr + nalign );
00408   while ( number ) { --number ; *value = *tmp ; ++tmp ; ++value ; }
00409   m_ptr = reinterpret_cast<ucharp>( tmp );
00410   if ( m_end < m_ptr ) { unpack_overflow(); }
00411 }
00412 
00413 template<typename T>
00414 inline
00415 void CommBuffer::peek( T & value )
00416 {
00417   enum { Size = sizeof(T) };
00418   const size_t nalign = CommBufferAlign<Size>::align( m_ptr - m_beg );
00419   T * tmp = reinterpret_cast<T*>( m_ptr + nalign );
00420   value = *tmp ;
00421   if ( m_end < reinterpret_cast<ucharp>(++tmp) ) { unpack_overflow(); }
00422 }
00423 
00424 template<typename T>
00425 inline
00426 void CommBuffer::peek( T * value , size_t number )
00427 {
00428   enum { Size = sizeof(T) };
00429   const size_t nalign = CommBufferAlign<Size>::align( m_ptr - m_beg );
00430   T * tmp = reinterpret_cast<T*>( m_ptr + nalign );
00431   while ( number ) { --number ; *value = *tmp ; ++tmp ; ++value ; }
00432   if ( m_end < reinterpret_cast<ucharp>(tmp) ) { unpack_overflow(); }
00433 }
00434 
00435 inline
00436 void CommBuffer::reset()
00437 { m_ptr = m_beg ; }
00438 
00439 inline
00440 size_t CommBuffer::capacity() const
00441 { return m_end - m_beg ; }
00442 
00443 inline
00444 size_t CommBuffer::size() const
00445 { return m_ptr - m_beg ; }
00446 
00447 inline
00448 ptrdiff_t CommBuffer::remaining() const
00449 { return m_end - m_ptr ; }
00450 
00451 inline
00452 void * CommBuffer::buffer() const
00453 { return static_cast<void*>( m_beg ); }
00454 
00455 //----------------------------------------------------------------------
00456 // Inline implementations for the CommAll
00457 
00458 inline
00459 CommBuffer & CommAll::send_buffer( unsigned p ) const
00460 {
00461   if ( m_size <= p ) { rank_error("send_buffer",p); }
00462   return m_send[p] ;
00463 }
00464 
00465 inline
00466 CommBuffer & CommAll::recv_buffer( unsigned p ) const
00467 {
00468   if ( m_size <= p ) { rank_error("recv_buffer",p); }
00469   return m_recv[p] ;
00470 }
00471 
00472 }
00473 
00474 //----------------------------------------------------------------------
00475 //----------------------------------------------------------------------
00476 
00477 #endif
00478 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator