1 /*
2  *  send_buffer_position.h
3  *
4  *  This file is part of NEST.
5  *
6  *  Copyright (C) 2004 The NEST Initiative
7  *
8  *  NEST is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  NEST is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #ifndef SEND_BUFFER_POSITION_H
24 #define SEND_BUFFER_POSITION_H
25 
26 // C++ includes:
27 #include <cassert>
28 #include <vector>
29 #include <limits>
30 
31 // Includes from nestkernel:
32 #include "vp_manager.h"
33 
34 namespace nest
35 {
36 
37 /**
38  * This class simplifies keeping track of write position in MPI buffer
39  * while collocating spikes.
40  */
41 class SendBufferPosition
42 {
43 private:
44   thread begin_rank_;
45   thread end_rank_;
46   thread max_size_;
47   size_t num_spike_data_written_;
48   size_t send_recv_count_per_rank_;
49   std::vector< thread > idx_;
50   std::vector< thread > begin_;
51   std::vector< thread > end_;
52 
53   thread rank_to_index_( const thread rank ) const;
54 
55 public:
56   SendBufferPosition( const AssignedRanks& assigned_ranks, const unsigned int send_recv_count_per_rank );
57 
58   /**
59    * Returns current index of specified rank in MPI buffer.
60    */
61   unsigned int idx( const thread rank ) const;
62 
63   /**
64    * Returns begin index of specified rank in MPI buffer.
65    */
66   unsigned int begin( const thread rank ) const;
67 
68   /**
69    * Returns end index of specified rank in MPI buffer.
70    */
71   unsigned int end( const thread rank ) const;
72 
73   /**
74    * Returns whether the part of the buffer on the specified rank has been
75    * filled.
76    *
77    * @param rank Rank denoting which part of the buffer we check
78    */
79   bool is_chunk_filled( const thread rank ) const;
80 
81   /**
82    * Returns whether the parts of the  MPI buffer assigned to this thread has
83    * been filled.
84    */
85   bool are_all_chunks_filled() const;
86 
87   void increase( const thread rank );
88 };
89 
SendBufferPosition(const AssignedRanks & assigned_ranks,const unsigned int send_recv_count_per_rank)90 inline SendBufferPosition::SendBufferPosition( const AssignedRanks& assigned_ranks,
91   const unsigned int send_recv_count_per_rank )
92   : begin_rank_( assigned_ranks.begin )
93   , end_rank_( assigned_ranks.end )
94   , max_size_( assigned_ranks.max_size )
95   , num_spike_data_written_( 0 )
96   , send_recv_count_per_rank_( send_recv_count_per_rank )
97 {
98   idx_.resize( assigned_ranks.size );
99   begin_.resize( assigned_ranks.size );
100   end_.resize( assigned_ranks.size );
101   for ( thread rank = assigned_ranks.begin; rank < assigned_ranks.end; ++rank )
102   {
103     // thread-local index of (global) rank
104     const thread lr_idx = rank % assigned_ranks.max_size;
105     assert( lr_idx < assigned_ranks.size );
106     idx_[ lr_idx ] = rank * send_recv_count_per_rank;
107     begin_[ lr_idx ] = rank * send_recv_count_per_rank;
108     end_[ lr_idx ] = ( rank + 1 ) * send_recv_count_per_rank;
109   }
110 }
111 
112 inline thread
rank_to_index_(const thread rank)113 SendBufferPosition::rank_to_index_( const thread rank ) const
114 {
115   assert( begin_rank_ <= rank );
116   assert( rank < end_rank_ );
117   return rank % max_size_;
118 }
119 
120 inline unsigned int
idx(const thread rank)121 SendBufferPosition::idx( const thread rank ) const
122 {
123   return idx_[ rank_to_index_( rank ) ];
124 }
125 
126 inline unsigned int
begin(const thread rank)127 SendBufferPosition::begin( const thread rank ) const
128 {
129   return begin_[ rank_to_index_( rank ) ];
130 }
131 
132 inline unsigned int
end(const thread rank)133 SendBufferPosition::end( const thread rank ) const
134 {
135   return end_[ rank_to_index_( rank ) ];
136 }
137 
138 inline bool
is_chunk_filled(const thread rank)139 SendBufferPosition::is_chunk_filled( const thread rank ) const
140 {
141   return idx( rank ) == end( rank );
142 }
143 
144 inline bool
are_all_chunks_filled()145 SendBufferPosition::are_all_chunks_filled() const
146 {
147   return num_spike_data_written_ == send_recv_count_per_rank_ * idx_.size();
148 }
149 
150 inline void
increase(const thread rank)151 SendBufferPosition::increase( const thread rank )
152 {
153   ++idx_[ rank_to_index_( rank ) ];
154   ++num_spike_data_written_;
155 }
156 
157 } // namespace nest
158 
159 #endif /* SEND_BUFFER_POSITION_H */
160