NEST main@caf0ae8
 
Loading...
Searching...
No Matches
mpi_manager.h
Go to the documentation of this file.
1/*
2 * mpi_manager.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 MPI_MANAGER_H
24#define MPI_MANAGER_H
25
26// Generated includes:
27#include "config.h"
28
29// C includes:
30#include <unistd.h>
31#ifdef HAVE_MPI
32#include <mpi.h>
33#endif
34
35// C++ includes:
36#include <cassert>
37#include <cmath>
38#include <iostream>
39#include <limits>
40#include <numeric>
41#include <vector>
42
43// Includes from libnestutil:
44#include "manager_interface.h"
45#include "stopwatch.h"
46
47// Includes from nestkernel:
48#include "nest_types.h"
49#include "spike_data.h"
50#include "target_data.h"
51
52
53namespace nest
54{
55
57{
58public:
59 // forward declaration of internal classes
60 class OffGridSpike;
61
62 MPIManager();
63 ~MPIManager() override
64 {
65 }
66
67 void initialize( const bool ) override;
68 void finalize( const bool ) override;
69 void set_status( const Dictionary& ) override;
70 void get_status( Dictionary& ) override;
71
72 void init_mpi( int* argc, char** argv[] );
73#ifdef HAVE_MPI
74 void set_communicator( MPI_Comm );
75
76 MPI_Comm
77 get_communicator()
78 {
79 return comm;
80 };
81#endif
82
90 size_t get_num_processes() const;
91
95 size_t get_rank() const;
96
103 size_t get_process_id_of_vp( const size_t vp ) const;
104
105 /*
106 * Return the process id of the node with the specified node ID.
107 */
108 size_t get_process_id_of_node_id( const size_t node_id ) const;
109
114 void mpi_finalize( int exitcode );
115
119 void mpi_abort( int exitcode );
120
121 // gather all send_buffer vectors on other mpi process to recv_buffer
122 // vector
123 void communicate( std::vector< size_t >& send_buffer, std::vector< size_t >& recv_buffer );
124
128 void communicate( std::vector< unsigned int >& send_buffer,
129 std::vector< unsigned int >& recv_buffer,
130 std::vector< int >& displacements );
131
135 void communicate( std::vector< OffGridSpike >& send_buffer,
136 std::vector< OffGridSpike >& recv_buffer,
137 std::vector< int >& displacements );
138
139 void communicate( std::vector< double >& send_buffer,
140 std::vector< double >& recv_buffer,
141 std::vector< int >& displacements );
142
143 void communicate( std::vector< unsigned long >& send_buffer,
144 std::vector< unsigned long >& recv_buffer,
145 std::vector< int >& displacements );
146
147 void
148 communicate( std::vector< int >& send_buffer, std::vector< int >& recv_buffer, std::vector< int >& displacements );
149
150 void communicate( double, std::vector< double >& );
151 void communicate( std::vector< int >& );
152 void communicate( std::vector< long >& );
153
155 void communicate_Allreduce_sum_in_place( double buffer );
156 void communicate_Allreduce_sum_in_place( std::vector< double >& buffer );
157 void communicate_Allreduce_sum_in_place( std::vector< int >& buffer );
158 void communicate_Allreduce_sum( std::vector< double >& send_buffer, std::vector< double >& recv_buffer );
159
167 bool equal_cross_ranks( const double value );
168
169 std::string get_processor_name();
170
171 bool is_mpi_used();
172
176 size_t get_buffer_size_target_data() const;
177
181 unsigned int get_send_recv_count_target_data_per_rank() const;
182
186 size_t get_buffer_size_spike_data() const;
187
191 unsigned int get_send_recv_count_spike_data_per_rank() const;
192
197
202
203#ifdef HAVE_MPI
204
205 void communicate_Alltoall_( void* send_buffer, void* recv_buffer, const unsigned int send_recv_count );
206
207 void communicate_Alltoallv_( void* send_buffer,
208 const int* send_counts,
209 const int* send_displacements,
210 void* recv_buffer,
211 const int* recv_counts,
212 const int* recv_displacements );
213
214#endif /* HAVE_MPI */
215
216 template < class D >
217 void communicate_Alltoall( std::vector< D >& send_buffer,
218 std::vector< D >& recv_buffer,
219 const unsigned int send_recv_count );
220 template < class D >
221 void communicate_target_data_Alltoall( std::vector< D >& send_buffer, std::vector< D >& recv_buffer );
222 template < class D >
223 void communicate_spike_data_Alltoall( std::vector< D >& send_buffer, std::vector< D >& recv_buffer );
224 template < class D >
225 void communicate_off_grid_spike_data_Alltoall( std::vector< D >& send_buffer, std::vector< D >& recv_buffer );
226 template < class D >
227 void communicate_secondary_events_Alltoallv( std::vector< D >& send_buffer, std::vector< D >& recv_buffer );
228
233 void synchronize();
234
235 bool any_true( const bool );
236
243 double time_communicate( int num_bytes, int samples = 1000 );
244 double time_communicatev( int num_bytes, int samples = 1000 );
245 double time_communicate_offgrid( int num_bytes, int samples = 1000 );
246 double time_communicate_alltoall( int num_bytes, int samples = 1000 );
247 double time_communicate_alltoallv( int num_bytes, int samples = 1000 );
248
249 void set_buffer_size_target_data( size_t buffer_size );
250 void set_buffer_size_spike_data( size_t buffer_size );
251
257
261 bool adaptive_target_buffers() const;
262
268 void set_recv_counts_secondary_events_in_int_per_rank( const std::vector< int >& recv_counts_in_int_per_rank );
269
275 size_t get_recv_count_secondary_events_in_int( const size_t source_rank ) const;
276
282 size_t get_recv_displacement_secondary_events_in_int( const size_t source_rank ) const;
283
287 size_t get_send_count_secondary_events_in_int( const size_t target_rank ) const;
288
292 size_t get_send_displacement_secondary_events_in_int( const size_t target_rank ) const;
293
297 size_t get_done_marker_position_in_secondary_events_send_buffer( const size_t target_rank ) const;
298
302 size_t get_done_marker_position_in_secondary_events_recv_buffer( const size_t source_rank ) const;
303
305
306private:
308 int rank_;
311 bool use_mpi_;
313 // communication of connections
314
316 // communication of spikes
317
319 // communication of connections
320
322 // connections resize on the fly
323
326
328
331
334
335 std::vector< int >
337
340
343
344#ifdef HAVE_MPI
345
346 std::vector< int > comm_step_;
347
348 unsigned int COMM_OVERFLOW_ERROR; //<! array containing communication partner for each step.
349
350
352 MPI_Comm comm;
353 MPI_Datatype MPI_OFFGRID_SPIKE;
354
355 void communicate_Allgather( std::vector< unsigned int >& send_buffer,
356 std::vector< unsigned int >& recv_buffer,
357 std::vector< int >& displacements );
358
359 void communicate_Allgather( std::vector< OffGridSpike >& send_buffer,
360 std::vector< OffGridSpike >& recv_buffer,
361 std::vector< int >& displacements );
362
363 void communicate_Allgather( std::vector< int >& );
364 void communicate_Allgather( std::vector< long >& );
365
366 template < typename T >
367 void communicate_Allgatherv( std::vector< T >& send_buffer,
368 std::vector< T >& recv_buffer,
369 std::vector< int >& displacements,
370 std::vector< int >& recv_counts );
371
372 template < typename T >
373 void communicate_Allgather( std::vector< T >& send_buffer,
374 std::vector< T >& recv_buffer,
375 std::vector< int >& displacements );
376
377#endif /* #ifdef HAVE_MPI */
378
379public:
390 {
391 friend void MPIManager::init_mpi( int*, char*** );
392
393 public:
396 typedef unsigned int node_id_external_type;
397
399 : node_id_( 0 )
400 , offset_( 0.0 )
401 {
402 }
403 OffGridSpike( node_id_external_type node_idv, double offsetv )
404 : node_id_( node_idv )
405 , offset_( offsetv )
406 {
407 }
408
409 unsigned int
411 {
412 return static_cast< node_id_external_type >( node_id_ );
413 }
414 void
416 {
417 node_id_ = static_cast< double >( node_id );
418 }
419 double
421 {
422 return offset_;
423 }
424
425 private:
426 double node_id_;
427 double offset_;
428
430 static void
432 {
433 assert( std::numeric_limits< double >::digits > std::numeric_limits< node_id_external_type >::digits );
434
435 // the next one is doubling up, better be safe than sorry
436 const node_id_external_type maxnode_id = std::numeric_limits< node_id_external_type >::max();
437 OffGridSpike ogs( maxnode_id, 0.0 );
438 assert( maxnode_id == ogs.get_node_id() );
439 }
440 };
441};
442
443inline void
444MPIManager::set_recv_counts_secondary_events_in_int_per_rank( const std::vector< int >& recv_counts_in_int_per_rank )
445{
446 recv_counts_secondary_events_in_int_per_rank_ = recv_counts_in_int_per_rank;
447
448 std::partial_sum( recv_counts_secondary_events_in_int_per_rank_.begin(),
451}
452
453inline size_t
455{
457}
458
459inline size_t
464
465inline size_t
467{
469}
470
471inline size_t
476
477inline size_t
483
484inline size_t
490
491inline size_t
493{
494 return num_processes_;
495}
496
497inline size_t
499{
500 return rank_;
501}
502
503inline bool
505{
506 return use_mpi_;
507}
508
509inline size_t
514
515inline unsigned int
520
521inline size_t
526
527inline unsigned int
532
533inline size_t
540
541inline size_t
548
549inline void
551{
552 assert( buffer_size >= static_cast< size_t >( 2 * get_num_processes() ) );
553 if ( buffer_size <= max_buffer_size_target_data_ )
554 {
555 buffer_size_target_data_ = buffer_size;
556 }
557 else
558 {
560 }
561 send_recv_count_target_data_per_rank_ = static_cast< size_t >(
562 floor( static_cast< double >( get_buffer_size_target_data() ) / static_cast< double >( get_num_processes() ) ) );
563
565}
566
567inline void
568MPIManager::set_buffer_size_spike_data( const size_t buffer_size )
569{
570 assert( buffer_size >= static_cast< size_t >( 2 * get_num_processes() ) );
571 buffer_size_spike_data_ = buffer_size;
572
574
576}
577
578inline bool
580{
581 assert( adaptive_target_buffers_ );
583 {
584 return false;
585 }
586 else
587 {
589 {
590 // this also adjusts send_recv_count_target_data_per_rank_
592 static_cast< size_t >( floor( buffer_size_target_data_ * growth_factor_buffer_target_data_ ) ) );
593 }
594 else
595 {
596 // this also adjusts send_recv_count_target_data_per_rank_
598 }
599 return true;
600 }
601}
602
603inline bool
608
609#ifndef HAVE_MPI
610inline std::string
612{
613 char name[ 1024 ];
614 name[ 1023 ] = '\0';
615 gethostname( name, 1023 );
616 return name;
617}
618
619inline void
621{
622}
623
624inline void
625MPIManager::communicate( std::vector< int >& )
626{
627}
628
629inline void
630MPIManager::communicate( std::vector< long >& )
631{
632}
633
634inline void
638
639inline void
640test_link( int, int )
641{
642}
643
644inline void
646{
647}
648
649inline bool
650MPIManager::any_true( const bool my_bool )
651{
652 return my_bool;
653}
654
655inline double
657{
658 return 0.0;
659}
660
661inline double
663{
664 return 0.0;
665}
666
667inline double
669{
670 return 0.0;
671}
672
673inline double
675{
676 return 0.0;
677}
678
679inline double
681{
682 return 0.0;
683}
684
685#endif /* HAVE_MPI */
686
687#ifdef HAVE_MPI
688template < class D >
689void
690MPIManager::communicate_Alltoall( std::vector< D >& send_buffer,
691 std::vector< D >& recv_buffer,
692 const unsigned int send_recv_count )
693{
694 void* send_buffer_int = static_cast< void* >( &send_buffer[ 0 ] );
695 void* recv_buffer_int = static_cast< void* >( &recv_buffer[ 0 ] );
696
697 communicate_Alltoall_( send_buffer_int, recv_buffer_int, send_recv_count );
698}
699
700template < class D >
701void
702MPIManager::communicate_secondary_events_Alltoallv( std::vector< D >& send_buffer, std::vector< D >& recv_buffer )
703{
704 void* send_buffer_int = static_cast< void* >( &send_buffer[ 0 ] );
705 void* recv_buffer_int = static_cast< void* >( &recv_buffer[ 0 ] );
706
707 communicate_Alltoallv_( send_buffer_int,
710 recv_buffer_int,
713}
714
715#else // HAVE_MPI
716template < class D >
717void
718MPIManager::MPIManager::communicate_Alltoall( std::vector< D >& send_buffer,
719 std::vector< D >& recv_buffer,
720 const unsigned int )
721{
722 recv_buffer.swap( send_buffer );
723}
724
725template < class D >
726void
727MPIManager::communicate_secondary_events_Alltoallv( std::vector< D >& send_buffer, std::vector< D >& recv_buffer )
728{
729 recv_buffer.swap( send_buffer );
730}
731
732#endif /* HAVE_MPI */
733
734template < class D >
735void
736MPIManager::communicate_target_data_Alltoall( std::vector< D >& send_buffer, std::vector< D >& recv_buffer )
737{
738 const size_t send_recv_count_target_data_in_int_per_rank =
739 sizeof( TargetData ) / sizeof( unsigned int ) * send_recv_count_target_data_per_rank_;
740
741 communicate_Alltoall( send_buffer, recv_buffer, send_recv_count_target_data_in_int_per_rank );
742}
743
744template < class D >
745void
746MPIManager::communicate_spike_data_Alltoall( std::vector< D >& send_buffer, std::vector< D >& recv_buffer )
747{
748 const size_t send_recv_count_spike_data_in_int_per_rank =
749 sizeof( SpikeData ) / sizeof( unsigned int ) * send_recv_count_spike_data_per_rank_;
750
751 communicate_Alltoall( send_buffer, recv_buffer, send_recv_count_spike_data_in_int_per_rank );
752}
753
754template < class D >
755void
756MPIManager::communicate_off_grid_spike_data_Alltoall( std::vector< D >& send_buffer, std::vector< D >& recv_buffer )
757{
758 const size_t send_recv_count_off_grid_spike_data_in_int_per_rank =
759 sizeof( OffGridSpikeData ) / sizeof( unsigned int ) * send_recv_count_spike_data_per_rank_;
760
761 communicate_Alltoall( send_buffer, recv_buffer, send_recv_count_off_grid_spike_data_in_int_per_rank );
762}
763}
764
765#endif /* MPI_MANAGER_H */
Dictionary class for interface to Python and C++ API.
Definition dictionary.h:213
Combined storage of node ID and offset information for off-grid spikes.
Definition mpi_manager.h:390
double offset_
offset of spike from grid
Definition mpi_manager.h:427
double node_id_
node ID of neuron that spiked
Definition mpi_manager.h:426
double get_offset() const
Definition mpi_manager.h:420
static void assert_datatype_compatibility_()
This function asserts that doubles can hold node IDs without loss.
Definition mpi_manager.h:431
OffGridSpike()
Definition mpi_manager.h:398
void set_node_id(node_id_external_type node_id)
Definition mpi_manager.h:415
unsigned int node_id_external_type
We defined this type explicitly, so that the assert function below always tests the correct type.
Definition mpi_manager.h:396
unsigned int get_node_id() const
Definition mpi_manager.h:410
OffGridSpike(node_id_external_type node_idv, double offsetv)
Definition mpi_manager.h:403
Definition mpi_manager.h:57
std::vector< int > send_counts_secondary_events_in_int_per_rank_
how many secondary elements (in ints) will be sent to each rank
Definition mpi_manager.h:336
double time_communicate_offgrid(int num_bytes, int samples=1000)
Definition mpi_manager.h:668
size_t get_recv_displacement_secondary_events_in_int(const size_t source_rank) const
Returns the rdispls parameter of Alltoallv for communication of secondary events, i....
Definition mpi_manager.h:460
size_t max_buffer_size_target_data_
maximal size of MPI buffer for
Definition mpi_manager.h:318
void communicate_Allreduce_sum_in_place(double buffer)
Sum across all ranks.
Definition mpi_manager.cpp:1090
void communicate_secondary_events_Alltoallv(std::vector< D > &send_buffer, std::vector< D > &recv_buffer)
Definition mpi_manager.h:727
std::string get_processor_name()
Definition mpi_manager.h:611
size_t get_recv_buffer_size_secondary_events_in_int() const
Returns total size of MPI recv buffer for communication of secondary events.
Definition mpi_manager.h:542
bool is_mpi_used()
Definition mpi_manager.h:504
std::vector< int > recv_counts_secondary_events_in_int_per_rank_
How many secondary elements (in ints) will be received from each rank.
Definition mpi_manager.h:333
size_t get_process_id_of_node_id(const size_t node_id) const
Definition mpi_manager_impl.h:86
size_t buffer_size_target_data_
total size of MPI buffer for
Definition mpi_manager.h:312
size_t get_process_id_of_vp(const size_t vp) const
Return the process id for a given virtual process.
Definition mpi_manager_impl.h:42
void init_mpi(int *argc, char **argv[])
Definition mpi_manager.cpp:81
double time_communicatev(int num_bytes, int samples=1000)
Definition mpi_manager.h:662
bool use_mpi_
whether MPI is used
Definition mpi_manager.h:311
bool any_true(const bool)
Definition mpi_manager.h:650
std::vector< int > send_displacements_secondary_events_in_int_per_rank_
Offset in the MPI send buffer (in ints) from which elements send to each rank will be read.
Definition mpi_manager.h:342
bool adaptive_target_buffers() const
Returns whether MPI buffers for communication of connections are adaptive.
Definition mpi_manager.h:604
int num_processes_
number of MPI processes
Definition mpi_manager.h:307
void set_status(const Dictionary &) override
Set the status of the manager.
Definition mpi_manager.cpp:224
size_t get_num_processes() const
Return the number of processes used during simulation.
Definition mpi_manager.h:492
void communicate_off_grid_spike_data_Alltoall(std::vector< D > &send_buffer, std::vector< D > &recv_buffer)
Definition mpi_manager.h:756
~MPIManager() override
Definition mpi_manager.h:63
void mpi_finalize(int exitcode)
Finalize MPI communication (needs to be separate from MPIManager::finalize when compiled with MUSIC s...
Definition mpi_manager.cpp:306
unsigned int send_recv_count_spike_data_per_rank_
Definition mpi_manager.h:329
void mpi_abort(int exitcode)
If MPI is available, this method calls MPI_Abort with the exitcode.
Definition mpi_manager.h:620
double shrink_factor_buffer_spike_data_
Definition mpi_manager.h:327
size_t get_recv_count_secondary_events_in_int(const size_t source_rank) const
Returns the recvcounts parameter of Alltoallv for communication of secondary events,...
Definition mpi_manager.h:454
void communicate_recv_counts_secondary_events()
Definition mpi_manager.cpp:1117
double growth_factor_buffer_spike_data_
Definition mpi_manager.h:324
int send_buffer_size_
expected size of send buffer
Definition mpi_manager.h:309
MPIManager()
Definition mpi_manager.cpp:54
void communicate_Allreduce_sum(std::vector< double > &send_buffer, std::vector< double > &recv_buffer)
Definition mpi_manager.cpp:1105
void communicate_Alltoall(std::vector< D > &send_buffer, std::vector< D > &recv_buffer, const unsigned int send_recv_count)
void set_buffer_size_target_data(size_t buffer_size)
Definition mpi_manager.h:550
void communicate_spike_data_Alltoall(std::vector< D > &send_buffer, std::vector< D > &recv_buffer)
Definition mpi_manager.h:746
int recv_buffer_size_
size of receive buffer
Definition mpi_manager.h:310
void synchronize()
Ensure all processes have reached the same stage by waiting until all processes have sent a dummy mes...
Definition mpi_manager.h:635
void set_buffer_size_spike_data(size_t buffer_size)
Definition mpi_manager.h:568
size_t get_buffer_size_spike_data() const
Returns total size of MPI buffer for communication of spikes.
Definition mpi_manager.h:522
void communicate_target_data_Alltoall(std::vector< D > &send_buffer, std::vector< D > &recv_buffer)
Definition mpi_manager.h:736
unsigned int get_send_recv_count_spike_data_per_rank() const
Returns size of MPI buffer for spikes divided by number of processes.
Definition mpi_manager.h:528
size_t get_send_displacement_secondary_events_in_int(const size_t target_rank) const
Returns the send displacement of elements (in ints) to be sent to rank target_rank.
Definition mpi_manager.h:472
double growth_factor_buffer_target_data_
Definition mpi_manager.h:325
unsigned int send_recv_count_target_data_per_rank_
Definition mpi_manager.h:330
size_t get_send_count_secondary_events_in_int(const size_t target_rank) const
Returns the number of elements (in ints) to be sent to target_rank.
Definition mpi_manager.h:466
int rank_
rank of the MPI process
Definition mpi_manager.h:308
void finalize(const bool) override
Take down manager after operation.
Definition mpi_manager.cpp:219
double time_communicate_alltoallv(int num_bytes, int samples=1000)
Definition mpi_manager.h:680
void get_status(Dictionary &) override
Retrieve the status of the manager.
Definition mpi_manager.cpp:260
void set_recv_counts_secondary_events_in_int_per_rank(const std::vector< int > &recv_counts_in_int_per_rank)
Sets the recvcounts parameter of Alltoallv for communication of secondary events, i....
Definition mpi_manager.h:444
double time_communicate_alltoall(int num_bytes, int samples=1000)
Definition mpi_manager.h:674
size_t get_rank() const
Get rank of MPI process.
Definition mpi_manager.h:498
void communicate(std::vector< size_t > &send_buffer, std::vector< size_t > &recv_buffer)
Definition mpi_manager.cpp:1085
double time_communicate(int num_bytes, int samples=1000)
Benchmark communication time of different MPI methods.
Definition mpi_manager.h:656
size_t get_send_buffer_size_secondary_events_in_int() const
Returns total size of MPI send buffer for communication of secondary events.
Definition mpi_manager.h:534
size_t get_done_marker_position_in_secondary_events_send_buffer(const size_t target_rank) const
Returns where the done marker is located in the MPI send buffer for target_rank.
Definition mpi_manager.h:478
void initialize(const bool) override
Prepare manager for operation.
Definition mpi_manager.cpp:181
bool equal_cross_ranks(const double value)
Equal across all ranks.
Definition mpi_manager.cpp:1111
bool increase_buffer_size_target_data()
Increases the size of the MPI buffer for communication of connections if it needs to be increased.
Definition mpi_manager.h:579
unsigned int get_send_recv_count_target_data_per_rank() const
Returns size of MPI buffer for connections divided by number of processes.
Definition mpi_manager.h:516
bool adaptive_target_buffers_
whether MPI buffers for communication of
Definition mpi_manager.h:321
size_t buffer_size_spike_data_
total size of MPI buffer for
Definition mpi_manager.h:315
size_t get_buffer_size_target_data() const
Returns total size of MPI buffer for communication of connections.
Definition mpi_manager.h:510
std::vector< int > recv_displacements_secondary_events_in_int_per_rank_
Offset in the MPI receive buffer (in ints) at which elements received from each rank will be written.
Definition mpi_manager.h:339
size_t get_done_marker_position_in_secondary_events_recv_buffer(const size_t source_rank) const
Returns where the done marker is located in the MPI recv buffer for source_rank.
Definition mpi_manager.h:485
Interface for kernel manager classes.
Definition manager_interface.h:46
Definition spike_data.h:395
Used to communicate spikes.
Definition spike_data.h:101
Used to communicate part of the connection infrastructure from post- to presynaptic side.
Definition target_data.h:175
Namespace for the NEST simulation kernel.
Definition beta_normalization_factor.h:33
void test_link(int, int)
Definition mpi_manager.h:640
void test_links()
Definition mpi_manager.h:645