GCC Code Coverage Report
Directory: . Exec Total Coverage
File: frame/base/hmlp_mpi.hpp Lines: 7 78 9.0 %
Date: 2019-01-14 Branches: 0 611 0.0 %

Line Exec Source
1
#ifndef HMLP_MPI_HPP
2
#define HMLP_MPI_HPP
3
#include <external/mpi_prototypes.h>
4
5
#include <vector>
6
#include <stdlib.h>
7
#include <stdint.h>
8
#include <limits.h>
9
#include <type_traits>
10
#include <cstdio>
11
#include <cstdint>
12
#include <cassert>
13
#include <vector>
14
15
#if SIZE_MAX == UCHAR_MAX
16
#define HMLP_MPI_SIZE_T MPI_UNSIGNED_CHAR
17
#elif SIZE_MAX == USHRT_MAX
18
#define HMLP_MPI_SIZE_T MPI_UNSIGNED_SHORT
19
#elif SIZE_MAX == UINT_MAX
20
#define HMLP_MPI_SIZE_T MPI_UNSIGNED
21
#elif SIZE_MAX == ULONG_MAX
22
#define HMLP_MPI_SIZE_T MPI_UNSIGNED_LONG
23
#elif SIZE_MAX == ULLONG_MAX
24
#define HMLP_MPI_SIZE_T MPI_UNSIGNED_LONG_LONG
25
#else
26
#error "what is happening here?"
27
#endif
28
29
30
/** -lmemkind */
31
#ifdef HMLP_MIC_AVX512
32
#include <hbwmalloc.h>
33
#include <hbw_allocator.h>
34
#endif // ifdef HMLP}_MIC_AVX512
35
36
37
using namespace std;
38
39
namespace hmlp
40
{
41
/** MPI compatable interface */
42
namespace mpi
43
{
44
typedef MPI_Status Status;
45
typedef MPI_Request Request;
46
typedef MPI_Comm Comm;
47
typedef MPI_Datatype Datatype;
48
typedef MPI_Op Op;
49
50
/** MPI 1.0 functionality */
51
int Init( int *argc, char ***argv );
52
int Initialized( int *flag );
53
int Finalize( void );
54
int Finalized( int *flag );
55
int Send( const void *buf, int count, Datatype datatype, int dest, int tag, Comm comm );
56
int Isend( const void *buf, int count, Datatype datatype, int dest, int tag, Comm comm, Request *request );
57
int Recv( void *buf, int count, Datatype datatype, int source, int tag, Comm comm, Status *status );
58
int Irecv( void *buf, int count, Datatype datatype, int source, int tag, Comm comm, Request *request );
59
int Sendrecv( void *sendbuf, int sendcount, Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, Datatype recvtype, int source, int recvtag, Comm comm, Status *status );
60
int Get_count( Status *status, Datatype datatype, int *count );
61
int Comm_size( Comm comm, int *size );
62
int Comm_rank( Comm comm, int *rank );
63
int Comm_dup( Comm comm, Comm *newcomm );
64
int Comm_split( Comm comm, int color, int key, Comm *newcomm );
65
int Type_contiguous( int count, Datatype oldtype, Datatype *newtype );
66
int Type_commit( Datatype *datatype );
67
int Test( Request *request, int *flag, Status *status );
68
int Barrier( Comm comm );
69
int Ibarrier( Comm comm, Request *request );
70
int Bcast( void *buffer, int count, Datatype datatype, int root, Comm comm );
71
int Reduce( void *sendbuf, void *recvbuf, int count, Datatype datatype, Op op, int root, Comm comm );
72
int Gather( const void *sendbuf, int sendcount, Datatype sendtype, void *recvbuf, int recvcount, Datatype recvtype, int root, Comm comm );
73
int Gatherv( void *sendbuf, int sendcount, Datatype sendtype, void *recvbuf, const int *recvcounts, const int *displs, Datatype recvtype, int root, Comm comm );
74
int Scan( void *sendbuf, void *recvbuf, int count, Datatype datatype, Op op, Comm comm );
75
int Allreduce( void* sendbuf, void* recvbuf, int count, Datatype datatype, Op op, Comm comm );
76
int Allgather( void *sendbuf, int sendcount, Datatype sendtype, void *recvbuf, int recvcount, Datatype recvtype, Comm comm );
77
int Allgatherv( void *sendbuf, int sendcount, Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, Datatype recvtype, Comm comm );
78
int Alltoall( void *sendbuf, int sendcount, Datatype sendtype, void *recvbuf, int recvcount, Datatype recvtype, Comm comm );
79
int Alltoallv( void *sendbuf, int *sendcounts, int *sdispls, Datatype sendtype, void *recvbuf, int *recvcounts, int *rdispls, Datatype recvtype, Comm comm );
80
81
/** MPI 2.0 and 3.0 functionality */
82
int Init_thread( int *argc, char ***argv, int required, int *provided );
83
int Probe( int source, int tag, Comm comm, Status *status );
84
int Iprobe( int source, int tag, Comm comm, int *flag, Status *status );
85
86
/** HMLP MPI extension */
87
void PrintProgress( const char *s, mpi::Comm comm );
88
89
class MPIObject
90
{
91
  public:
92
93
    MPIObject() {};
94
95
1
    MPIObject( mpi::Comm comm ) { AssignCommunicator( comm ); };
96
97
1
    void AssignCommunicator( mpi::Comm &comm )
98
    {
99
1
      this->comm = comm;
100
1
      mpi::Comm_dup( comm, &private_comm );
101
1
      mpi::Comm_size( comm, &comm_size );
102
1
      mpi::Comm_rank( comm, &comm_rank );
103
1
    };
104
105
    mpi::Comm GetComm() { return comm; };
106
107
      mpi::Comm GetPrivateComm() { return private_comm; };
108
109
      int GetCommSize() { return comm_size; };
110
111
      int GetCommRank() { return comm_rank; };
112
113
      int Comm_size()
114
      {
115
         int size;
116
         mpi::Comm_size( comm, &size );
117
         return size;
118
      };
119
120
      int Comm_rank()
121
      {
122
         int rank;
123
         mpi::Comm_rank( comm, &rank );
124
         return rank;
125
      };
126
127
    int Barrier() { return mpi::Barrier( comm ); };
128
129
    int PrivateBarrier() { return mpi::Barrier( private_comm ); };
130
131
  private:
132
133
    /** This is the assigned communicator. */
134
    mpi::Comm comm = MPI_COMM_WORLD;
135
    /** This communicator is duplicated from comm */
136
    mpi::Comm private_comm;
137
    /** (Default) there is only one MPI process. */
138
    int comm_size = 1;
139
    /** (Default) the only MPI process has rank 0. */
140
    int comm_rank = 0;
141
142
}; /** end class MPIObject */
143
144
145
146
147
148
149
/** Type insensitive interface */
150
151
template<typename T>
152
struct NumberIntPair { T val; int key; };
153
154
155
template<typename T>
156
Datatype GetMPIDatatype()
157
{
158
  Datatype datatype;
159
  if ( std::is_same<T, int>::value )
160
    datatype = MPI_INT;
161
  else if ( std::is_same<T, float>::value )
162
    datatype = MPI_FLOAT;
163
  else if ( std::is_same<T, double>::value )
164
    datatype = MPI_DOUBLE;
165
  else if ( std::is_same<T, size_t>::value )
166
    datatype = HMLP_MPI_SIZE_T;
167
  else if ( std::is_same<T, NumberIntPair<float> >::value )
168
    datatype = MPI_FLOAT_INT;
169
  else if ( std::is_same<T, NumberIntPair<double> >::value )
170
  {
171
    datatype = MPI_DOUBLE_INT;
172
  }
173
  else
174
  {
175
    Type_contiguous( sizeof( T ), MPI_BYTE, &datatype );
176
    Type_commit( &datatype );
177
178
    //printf( "request datatype is not supported in the simplified interface\n" );
179
    //exit( 1 );
180
  }
181
  return datatype;
182
183
}; /** end GetMPIDatatype() */
184
185
186
187
template<typename TSEND>
188
int Send( TSEND *buf, int count,
189
    int dest, int tag, Comm comm )
190
{
191
  Datatype datatype = GetMPIDatatype<TSEND>();
192
  return Send( buf, count, datatype, dest, tag, comm );
193
}; /** end Send() */
194
195
196
template<typename TSEND>
197
int Isend( TSEND *buf, int count,
198
		int dest, int tag, Comm comm, Request *request )
199
{
200
  Datatype datatype = GetMPIDatatype<TSEND>();
201
  return Isend( buf, count, datatype, dest, tag, comm, request );
202
}; /** end Isend() */
203
204
205
206
template<typename TRECV>
207
int Recv( TRECV *buf, int count,
208
    int source, int tag, Comm comm, Status *status )
209
{
210
  Datatype datatype = GetMPIDatatype<TRECV>();
211
  return Recv( buf, count, datatype, source, tag, comm, status );
212
}; /** end Recv() */
213
214
template<typename T>
215
int Bcast( T *buffer, int count, int root, Comm comm )
216
{
217
  Datatype datatype = GetMPIDatatype<T>();
218
  return Bcast( buffer, count, datatype, root, comm );
219
}; /** end Bcast() */
220
221
222
template<typename TSEND, typename TRECV>
223
int Sendrecv(
224
    TSEND *sendbuf, int sendcount, int dest,   int sendtag,
225
    TRECV *recvbuf, int recvcount, int source, int recvtag,
226
    Comm comm, Status *status )
227
{
228
  Datatype sendtype = GetMPIDatatype<TSEND>();
229
  Datatype recvtype = GetMPIDatatype<TRECV>();
230
  return Sendrecv(
231
      sendbuf, sendcount, sendtype,   dest, sendtag,
232
      recvbuf, recvcount, recvtype, source, recvtag,
233
      comm, status );
234
235
}; /** end Sendrecv() */
236
237
238
template<typename T>
239
int Reduce( T *sendbuf, T *recvbuf, int count,
240
    Op op, int root, Comm comm )
241
{
242
  Datatype datatype = GetMPIDatatype<T>();
243
	return Reduce( sendbuf, recvbuf, count, datatype, op, root, comm );
244
}; /** end Reduce() */
245
246
247
248
template<typename TSEND, typename TRECV>
249
int Gather( const TSEND *sendbuf, int sendcount,
250
    TRECV *recvbuf, int recvcount,
251
    int root, Comm comm )
252
{
253
  Datatype sendtype = GetMPIDatatype<TSEND>();
254
  Datatype recvtype = GetMPIDatatype<TRECV>();
255
  return Gather( sendbuf, sendcount, sendtype,
256
      recvbuf, recvcount, recvtype, root, comm );
257
};
258
259
260
template<typename TSEND, typename TRECV>
261
int Gatherv(
262
    TSEND *sendbuf, int sendcount,
263
    TRECV *recvbuf, const int *recvcounts, const int *displs,
264
    int root, Comm comm )
265
{
266
  Datatype sendtype = GetMPIDatatype<TSEND>();
267
  Datatype recvtype = GetMPIDatatype<TRECV>();
268
  return Gatherv( sendbuf, sendcount, sendtype,
269
      recvbuf, recvcounts, displs, recvtype, root, comm );
270
}; /** end Gatherv() */
271
272
273
template<typename T>
274
int Allreduce( T* sendbuf, T* recvbuf, int count, Op op, Comm comm )
275
{
276
  Datatype datatype = GetMPIDatatype<T>();
277
  return Allreduce( sendbuf, recvbuf, count, datatype, op, comm );
278
}; /** end Allreduce() */
279
280
281
template<typename TSEND, typename TRECV>
282
int Allgather(
283
    TSEND *sendbuf, int sendcount,
284
    TRECV *recvbuf, int recvcount, Comm comm )
285
{
286
  Datatype sendtype = GetMPIDatatype<TSEND>();
287
  Datatype recvtype = GetMPIDatatype<TRECV>();
288
  return Allgather(
289
      sendbuf, sendcount, sendtype,
290
      recvbuf, recvcount, recvtype, comm );
291
}; /** end Allgather() */
292
293
294
template<typename TSEND, typename TRECV>
295
int Allgatherv(
296
    TSEND *sendbuf, int sendcount,
297
    TRECV *recvbuf, int *recvcounts, int *displs, Comm comm )
298
{
299
  Datatype sendtype = GetMPIDatatype<TSEND>();
300
  Datatype recvtype = GetMPIDatatype<TRECV>();
301
  return Allgatherv(
302
      sendbuf, sendcount, sendtype,
303
      recvbuf, recvcounts, displs, recvtype, comm );
304
}; /** end Allgatherv() */
305
306
307
template<typename TSEND, typename TRECV>
308
int Alltoall(
309
    TSEND *sendbuf, int sendcount,
310
    TRECV *recvbuf, int recvcount, Comm comm )
311
{
312
  Datatype sendtype = GetMPIDatatype<TSEND>();
313
  Datatype recvtype = GetMPIDatatype<TRECV>();
314
  return Alltoall(
315
      sendbuf, sendcount, sendtype,
316
      recvbuf, recvcount, recvtype, comm );
317
}; /** end Alltoall() */
318
319
320
template<typename TSEND, typename TRECV>
321
int Alltoallv(
322
    TSEND *sendbuf, int *sendcounts, int *sdispls,
323
    TRECV *recvbuf, int *recvcounts, int *rdispls, Comm comm )
324
{
325
  Datatype sendtype = GetMPIDatatype<TSEND>();
326
  Datatype recvtype = GetMPIDatatype<TRECV>();
327
  return Alltoallv(
328
      sendbuf, sendcounts, sdispls, sendtype,
329
      recvbuf, recvcounts, rdispls, recvtype, comm );
330
}; /** end Alltoallv() */
331
332
333
/**
334
 *  @brief This is a short hand for sending a vector, which
335
 *         involves two MPI_Send() calls.
336
 */
337
#ifdef HMLP_MIC_AVX512
338
/** use hbw::allocator for Intel Xeon Phi */
339
template<class T, class Allocator = hbw::allocator<T> >
340
#else
341
/** use default stl allocator */
342
template<class T, class Allocator = std::allocator<T> >
343
#endif
344
int SendVector(
345
    std::vector<T, Allocator> &bufvector, int dest, int tag, Comm comm )
346
{
347
  Datatype datatype = GetMPIDatatype<T>();
348
  size_t count = bufvector.size();
349
350
  /** send the count size first */
351
  //printf( "beg send count %lu to %d\n", count, dest );
352
  Send( &count, 1, dest, tag, comm );
353
  //printf( "end send count %lu to %d\n", count, dest );
354
355
  /** now send the vector itself */
356
  return Send( bufvector.data(), count, dest, tag, comm );
357
358
}; /** end SendVector() */
359
360
361
362
/**
363
 *  @brief This is a short hand for receving a vector, which
364
 *         involves two MPI_Recv() calls.
365
 */
366
#ifdef HMLP_MIC_AVX512
367
/** use hbw::allocator for Intel Xeon Phi */
368
template<class T, class Allocator = hbw::allocator<T> >
369
#else
370
/** use default stl allocator */
371
template<class T, class Allocator = std::allocator<T> >
372
#endif
373
int RecvVector(
374
    std::vector<T, Allocator> &bufvector, int source, int tag, Comm comm, Status *status )
375
{
376
  Datatype datatype = GetMPIDatatype<T>();
377
  size_t count = 0;
378
379
  /** recv the count size first */
380
  //printf( "beg recv count %lu from %d\n", count, source );
381
  Recv( &count, 1, source, tag, comm, status );
382
  //printf( "end recv count %lu from %d\n", count, source );
383
384
  /** resize receiving vector */
385
  bufvector.resize( count );
386
387
  /** now recv the vector itself */
388
  return Recv( bufvector.data(), count, source, tag, comm, status );
389
390
}; /** end RecvVector() */
391
392
393
394
#ifdef HMLP_MIC_AVX512
395
/** use hbw::allocator for Intel Xeon Phi */
396
template<class T, class Allocator = hbw::allocator<T> >
397
#else
398
/** use default stl allocator */
399
template<class T, class Allocator = std::allocator<T> >
400
#endif
401
int ExchangeVector(
402
    vector<T, Allocator> &sendvector,   int dest, int sendtag,
403
    vector<T, Allocator> &recvvector, int source, int recvtag,
404
    Comm comm, Status *status )
405
{
406
  Datatype datatype = GetMPIDatatype<T>();
407
  size_t send_size = sendvector.size();
408
  size_t recv_size = 0;
409
410
  /** exechange size */
411
  Sendrecv(
412
      &send_size, 1,   dest, sendtag,
413
      &recv_size, 1, source, recvtag,
414
      comm, status );
415
  /** resize receiving vector */
416
  recvvector.resize( recv_size );
417
  /** exechange buffer */
418
  return Sendrecv(
419
      sendvector.data(), send_size,   dest, sendtag,
420
      recvvector.data(), recv_size, source, recvtag,
421
      comm, status );
422
423
}; /** end ExchangeVector() */
424
425
426
template<typename T>
427
int GatherVector( vector<T> &sendvector, vector<T> &recvvector, int root, Comm comm )
428
{
429
  int size = 0; Comm_size( comm, &size );
430
  int rank = 0; Comm_rank( comm, &rank );
431
432
  Datatype datatype = GetMPIDatatype<T>();
433
  int send_size = sendvector.size();
434
  vector<int> recv_sizes( size, 0 );
435
  vector<int> rdispls( size + 1, 0 );
436
437
  /** Use typeless Gather() for counting. */
438
  Gather( &send_size, 1, recv_sizes.data(), 1, root, comm );
439
  /** Accumulate received displs. */
440
  for ( int i = 1; i < size + 1; i ++ )
441
    rdispls[ i ] = rdispls[ i - 1 ] + recv_sizes[ i - 1 ];
442
  /** Resize recvvector to fit. */
443
  recvvector.resize( rdispls[ size ] );
444
  /** Gather vectors. */
445
  return Gatherv( sendvector.data(), send_size,
446
      recvvector.data(), recv_sizes.data(), rdispls.data(), root, comm );
447
}; /** end GatherVector() */
448
449
450
451
452
453
#ifdef HMLP_MIC_AVX512
454
/** use hbw::allocator for Intel Xeon Phi */
455
template<class T, class Allocator = hbw::allocator<T> >
456
#else
457
/** use default stl allocator */
458
template<class T, class Allocator = std::allocator<T> >
459
#endif
460
int AlltoallVector(
461
    const vector<vector<T, Allocator>>& sendvector,
462
    vector<vector<T, Allocator>>& recvvector, Comm comm )
463
{
464
  int size = 0; Comm_size( comm, &size );
465
  int rank = 0; Comm_rank( comm, &rank );
466
467
  assert( sendvector.size() == size );
468
  assert( recvvector.size() == size );
469
470
  vector<T> sendbuf;
471
  vector<T> recvbuf;
472
  vector<int> sendcounts( size, 0 );
473
  vector<int> recvcounts( size, 0 );
474
  vector<int> sdispls( size + 1, 0 );
475
  vector<int> rdispls( size + 1, 0 );
476
477
  //printf( "rank %d ", rank );
478
  for ( size_t p = 0; p < size; p ++ )
479
  {
480
    sendcounts[ p ] = sendvector[ p ].size();
481
    sdispls[ p + 1 ] = sdispls[ p ] + sendcounts[ p ];
482
    sendbuf.insert( sendbuf.end(),
483
        sendvector[ p ].begin(),
484
        sendvector[ p ].end() );
485
    //printf( "%d ", sendcounts[ j ] );
486
  }
487
  //printf( "\n" );
488
489
490
  //printf( "before Alltoall (mpi size = %d)\n", size ); fflush( stdout );
491
  //Barrier( comm );
492
493
  /** exchange sendcount */
494
  Alltoall( sendcounts.data(), 1, recvcounts.data(), 1, comm );
495
496
497
  //printf( "after Alltoall\n" ); fflush( stdout );
498
  //Barrier( comm );
499
500
  //printf( "rank %d ", rank );
501
  size_t total_recvcount = 0;
502
  for ( size_t p = 0; p < size; p ++ )
503
  {
504
    rdispls[ p + 1 ] = rdispls[ p ] + recvcounts[ p ];
505
    total_recvcount += recvcounts[ p ];
506
    //printf( "%d ", recvcounts[ j ] );
507
  }
508
  //printf( "\n" );
509
510
  /** resize receving buffer */
511
  recvbuf.resize( total_recvcount );
512
513
514
  //printf( "before Alltoall2 recvbuf.size() %lu\n", recvbuf.size() ); fflush( stdout );
515
  //Barrier( comm );
516
517
518
  Alltoallv(
519
      sendbuf.data(), sendcounts.data(), sdispls.data(),
520
      recvbuf.data(), recvcounts.data(), rdispls.data(), comm );
521
522
523
  //printf( "after Alltoall2\n" ); fflush( stdout );
524
  //Barrier( comm );
525
526
527
  recvvector.resize( size );
528
  for ( size_t p = 0; p < size; p ++ )
529
  {
530
    recvvector[ p ].insert( recvvector[ p ].end(),
531
        recvbuf.begin() + rdispls[ p ],
532
        recvbuf.begin() + rdispls[ p + 1 ] );
533
  }
534
535
  return 0;
536
537
}; /** end AlltoallVector() */
538
539
540
541
/**
542
 *  This interface supports hmlp::Data. [ m, n ] will be set
543
 *  after the routine.
544
 *
545
 */
546
//template<typename T>
547
//int AlltoallVector(
548
//    std::vector<hmlp::Data<T>> &sendvector,
549
//    std::vector<hmlp::Data<T>> &recvvector, Comm comm )
550
//{
551
//  int size = 0;
552
//  int rank = 0;
553
//  Comm_size( comm, &size );
554
//  Comm_rank( comm, &rank );
555
//
556
//  assert( sendvector.size() == size );
557
//  assert( recvvector.size() == size );
558
//
559
//  std::vector<T> sendbuf;
560
//  std::vector<T> recvbuf;
561
//  std::vector<int> sendcounts( size, 0 );
562
//  std::vector<int> recvcounts( size, 0 );
563
//  std::vector<int> sdispls( size + 1, 0 );
564
//  std::vector<int> rdispls( size + 1, 0 );
565
//
566
//
567
//  for ( size_t p = 0; p < size; p ++ )
568
//  {
569
//    sendcounts[ p ] = sendvector[ p ].size();
570
//    sdispls[ p + 1 ] = sdispls[ p ] + sendcounts[ p ];
571
//    sendbuf.insert( sendbuf.end(),
572
//        sendvector[ p ].begin(),
573
//        sendvector[ p ].end() );
574
//  }
575
//
576
//  /** exchange sendcount */
577
//  Alltoall( sendcounts.data(), 1, recvcounts.data(), 1, comm );
578
//
579
//  /** compute total receiving count */
580
//  size_t total_recvcount = 0;
581
//  for ( size_t p = 0; p < size; p ++ )
582
//  {
583
//    rdispls[ p + 1 ] = rdispls[ p ] + recvcounts[ p ];
584
//    total_recvcount += recvcounts[ p ];
585
//  }
586
//
587
//  /** resize receving buffer */
588
//  recvbuf.resize( total_recvcount );
589
//
590
//
591
//
592
//
593
//
594
//
595
//}; /** end AlltoallVector() */
596
597
598
599
600
}; /** end namespace mpi */
601
}; /** end namespace hmlp */
602
603
#endif /** define HMLP_MPI_HPP */
604
605