17#define DBM_MULTIPLY_COMM_MEMPOOL
24static int gcd(
const int a,
const int b) {
35static int lcm(
const int a,
const int b) {
return (a * b) /
gcd(a, b); }
44 assert(0 <= nelements);
45 assert(element_size <= INT_MAX);
46 assert(nelements <= INT_MAX / (
int)element_size);
47 return nelements * (int)element_size;
54static inline int isum(
const int n,
const int input[n]) {
56 for (
int i = 0;
i < n;
i++) {
66static inline void icumsum(
const int n,
const int input[n],
int output[n]) {
69 int oval = output[0] = 0, ival = input[0];
70 for (
int i = 1;
i < n;
i++) {
71 output[
i] = (oval += ival);
81 const int blks_recv_count[nranks],
82 const int blks_recv_displ[nranks],
83 const int free_index_sizes[],
84 const int sum_index_sizes[],
86 int data_recv_count[nranks]) {
89 memset(data_recv_count, 0, nranks *
sizeof(
int));
90 for (
int irank = 0; irank < nranks; irank++) {
91 for (
int i = 0;
i < blks_recv_count[irank];
i++) {
93 &blks_recv[blks_recv_displ[irank] +
i];
94 const int block_size =
96 assert(block_size >= 0);
97 assert(data_recv_count[irank] <= INT_MAX - block_size);
98 data_recv_count[irank] += block_size;
121 return ((
unsigned long long)sum_index * 1021ULL) % (
unsigned long long)nticks;
133 const int npacks,
plan_t *plans_per_pack[npacks],
134 int nblks_per_pack[npacks],
135 int ndata_per_pack[npacks]) {
136 memset(nblks_per_pack, 0, npacks *
sizeof(
int));
137 memset(ndata_per_pack, 0, npacks *
sizeof(
int));
142 int nblks_mythread[npacks];
143 memset(nblks_mythread, 0, npacks *
sizeof(
int));
144#pragma omp for schedule(static)
147 for (
int iblock = 0; iblock < shard->
nblocks; iblock++) {
149 const int sum_index = (trans_matrix) ? blk->
row : blk->
col;
151 const int ipack = itick64 / dist_ticks->
nranks;
152 nblks_mythread[ipack]++;
158 for (
int ipack = 0; ipack < npacks; ipack++) {
159 nblks_per_pack[ipack] += nblks_mythread[ipack];
160 nblks_mythread[ipack] = nblks_per_pack[ipack];
164 for (
int ipack = 0; ipack < npacks; ipack++) {
165 const int nblks = nblks_per_pack[ipack];
166 plans_per_pack[ipack] = malloc(nblks *
sizeof(
plan_t));
167 assert(plans_per_pack[ipack] != NULL || nblks == 0);
171 int ndata_mythread[npacks];
172 memset(ndata_mythread, 0, npacks *
sizeof(
int));
173#pragma omp for schedule(static)
176 for (
int iblock = 0; iblock < shard->
nblocks; iblock++) {
178 const int free_index = (trans_matrix) ? blk->
col : blk->
row;
179 const int sum_index = (trans_matrix) ? blk->
row : blk->
col;
181 const int ipack = itick64 / dist_ticks->
nranks;
183 const int coord_free_idx = dist_indices->
index2coord[free_index];
184 const int coord_sum_idx = itick64 % dist_ticks->
nranks;
185 const int coords[2] = {(trans_dist) ? coord_sum_idx : coord_free_idx,
186 (trans_dist) ? coord_free_idx : coord_sum_idx};
190 ndata_mythread[ipack] += row_size * col_size;
192 const int iplan = --nblks_mythread[ipack];
193 plans_per_pack[ipack][iplan].blk = blk;
194 plans_per_pack[ipack][iplan].rank = rank;
195 plans_per_pack[ipack][iplan].row_size = row_size;
196 plans_per_pack[ipack][iplan].col_size = col_size;
200 for (
int ipack = 0; ipack < npacks; ipack++) {
201 ndata_per_pack[ipack] += ndata_mythread[ipack];
211 const dbm_matrix_t *matrix,
const bool trans_matrix,
const int nblks_send,
212 const int ndata_send,
plan_t plans[nblks_send],
const int nranks,
213 int blks_send_count[nranks],
int data_send_count[nranks],
214 int blks_send_displ[nranks],
int data_send_displ[nranks],
216 memset(blks_send_count, 0, nranks *
sizeof(
int));
217 memset(data_send_count, 0, nranks *
sizeof(
int));
222 int nblks_mythread[nranks], ndata_mythread[nranks];
223 memset(nblks_mythread, 0, nranks *
sizeof(
int));
224 memset(ndata_mythread, 0, nranks *
sizeof(
int));
225#pragma omp for schedule(static)
226 for (
int iblock = 0; iblock < nblks_send; iblock++) {
227 const plan_t *plan = &plans[iblock];
228 nblks_mythread[plan->
rank] += 1;
234 for (
int irank = 0; irank < nranks; irank++) {
235 blks_send_count[irank] += nblks_mythread[irank];
236 data_send_count[irank] += ndata_mythread[irank];
237 nblks_mythread[irank] = blks_send_count[irank];
238 ndata_mythread[irank] = data_send_count[irank];
245 icumsum(nranks, blks_send_count, blks_send_displ);
246 icumsum(nranks, data_send_count, data_send_displ);
247 const int m = nranks - 1;
248 assert(nblks_send == blks_send_displ[m] + blks_send_count[m]);
249 assert(ndata_send == data_send_displ[m] + data_send_count[m]);
254#pragma omp for schedule(static)
255 for (
int iblock = 0; iblock < nblks_send; iblock++) {
256 const plan_t *
const plan = &plans[iblock];
260 const double *blk_data = &shard->
data[blk->
offset];
262 const int plan_size = row_size * col_size;
263 const int irank = plan->
rank;
268 nblks_mythread[irank] -= 1;
269 ndata_mythread[irank] -= plan_size;
270 const int offset = data_send_displ[irank] + ndata_mythread[irank];
271 const int jblock = blks_send_displ[irank] + nblks_mythread[irank];
276 for (
int i = 0;
i < row_size;
i++) {
277 for (
int j = 0; j < col_size; j++) {
278 const double element = blk_data[j * row_size +
i];
279 data_send[offset +
i * col_size + j] = element;
280 norm += element * element;
283 blks_send[jblock].free_index = plan->
blk->
col;
284 blks_send[jblock].sum_index = plan->
blk->
row;
286 for (
int i = 0;
i < plan_size;
i++) {
287 const double element = blk_data[
i];
288 data_send[offset +
i] = element;
289 norm += element * element;
291 blks_send[jblock].free_index = plan->
blk->
row;
292 blks_send[jblock].sum_index = plan->
blk->
col;
294 blks_send[jblock].norm = (float)norm;
297 blks_send[jblock].offset = offset - data_send_displ[irank];
317 const int nranks,
const int nshards,
const int nblocks_recv,
318 const int blks_recv_count[nranks],
const int blks_recv_displ[nranks],
319 const int data_recv_displ[nranks],
321 int nblocks_per_shard[nshards], shard_start[nshards];
322 memset(nblocks_per_shard, 0, nshards *
sizeof(
int));
325 assert(blocks_tmp != NULL || nblocks_recv == 0);
330 for (
int irank = 0; irank < nranks; irank++) {
332 for (
int i = 0;
i < blks_recv_count[irank];
i++) {
333 blks_recv[blks_recv_displ[irank] +
i].offset += data_recv_displ[irank];
338 int nblocks_mythread[nshards];
339 memset(nblocks_mythread, 0, nshards *
sizeof(
int));
340#pragma omp for schedule(static)
341 for (
int iblock = 0; iblock < nblocks_recv; iblock++) {
342 blocks_tmp[iblock] = blks_recv[iblock];
343 const int ishard = blks_recv[iblock].
free_index % nshards;
344 nblocks_mythread[ishard]++;
347 for (
int ishard = 0; ishard < nshards; ishard++) {
348 nblocks_per_shard[ishard] += nblocks_mythread[ishard];
349 nblocks_mythread[ishard] = nblocks_per_shard[ishard];
353 icumsum(nshards, nblocks_per_shard, shard_start);
355#pragma omp for schedule(static)
356 for (
int iblock = 0; iblock < nblocks_recv; iblock++) {
357 const int ishard = blocks_tmp[iblock].
free_index % nshards;
358 const int jblock = --nblocks_mythread[ishard] + shard_start[ishard];
359 blks_recv[jblock] = blocks_tmp[iblock];
364 for (
int ishard = 0; ishard < nshards; ishard++) {
365 if (nblocks_per_shard[ishard] > 1) {
366 qsort(&blks_recv[shard_start[ishard]], nblocks_per_shard[ishard],
380 const bool trans_dist,
388 const dbm_dist_1d_t *dist_indices = (trans_dist) ? &dist->cols : &dist->rows;
389 const dbm_dist_1d_t *dist_ticks = (trans_dist) ? &dist->rows : &dist->cols;
390 const int *free_index_sizes =
391 (trans_matrix) ? matrix->col_sizes : matrix->row_sizes;
392 const int *sum_index_sizes =
393 (trans_matrix) ? matrix->row_sizes : matrix->col_sizes;
396 const int nsend_packs = nticks / dist_ticks->
nranks;
397 assert(nsend_packs * dist_ticks->
nranks == nticks);
403 assert(packed.
send_packs != NULL || nsend_packs == 0);
406 plan_t *plans_per_pack[nsend_packs];
407 int nblks_send_per_pack[nsend_packs], ndata_send_per_pack[nsend_packs];
409 dist_ticks, nticks, nsend_packs, plans_per_pack,
410 nblks_send_per_pack, ndata_send_per_pack);
413 int nblks_send_max = 0, ndata_send_max = 0;
414 for (
int ipack = 0; ipack < nsend_packs; ++ipack) {
415 nblks_send_max =
imax(nblks_send_max, nblks_send_per_pack[ipack]);
416 ndata_send_max =
imax(ndata_send_max, ndata_send_per_pack[ipack]);
423 for (
int ipack = 0; ipack < nsend_packs; ipack++) {
425 const int nranks = dist->nranks;
426 int blks_send_count[nranks], data_send_count[nranks];
427 int blks_send_displ[nranks], data_send_displ[nranks];
429 ndata_send_per_pack[ipack], plans_per_pack[ipack], nranks,
430 blks_send_count, data_send_count, blks_send_displ,
431 data_send_displ, blks_send, data_send);
432 free(plans_per_pack[ipack]);
435 int blks_recv_count[nranks], blks_recv_displ[nranks];
437 icumsum(nranks, blks_recv_count, blks_recv_displ);
438 const int nblocks_recv =
isum(nranks, blks_recv_count);
443 int blks_send_count_byte[nranks], blks_send_displ_byte[nranks];
444 int blks_recv_count_byte[nranks], blks_recv_displ_byte[nranks];
445 for (
int i = 0;
i < nranks;
i++) {
446 blks_send_count_byte[
i] =
448 blks_send_displ_byte[
i] =
450 blks_recv_count_byte[
i] =
452 blks_recv_displ_byte[
i] =
456 blks_recv, blks_recv_count_byte, blks_recv_displ_byte,
460 int data_recv_count[nranks], data_recv_displ[nranks];
462 free_index_sizes, sum_index_sizes, blks_recv,
464 icumsum(nranks, data_recv_count, data_recv_displ);
465 const int ndata_recv =
isum(nranks, data_recv_count);
468#if defined(DBM_MULTIPLY_COMM_MEMPOOL)
475 data_recv, data_recv_count, data_recv_displ,
480 blks_recv_count, blks_recv_displ,
481 data_recv_displ, blks_recv);
493 int max_nblocks = 0, max_data_size = 0;
494 for (
int ipack = 0; ipack < packed.
nsend_packs; ipack++) {
504#if defined(DBM_MULTIPLY_COMM_MEMPOOL)
525 const int itick_of_rank0 = (itick + nticks - my_rank) % nticks;
526 const int send_rank = (my_rank + nticks - itick_of_rank0) % nranks;
527 const int send_itick = (itick_of_rank0 + send_rank) % nticks;
528 const int send_ipack = send_itick / nranks;
529 assert(send_itick % nranks == my_rank);
532 const int recv_rank = itick % nranks;
533 const int recv_ipack = itick / nranks;
536 if (send_rank == my_rank) {
537 assert(send_rank == recv_rank && send_ipack == recv_ipack);
579#if defined(DBM_MULTIPLY_COMM_MEMPOOL)
584 for (
int ipack = 0; ipack < packed->
nsend_packs; ipack++) {
586#if defined(DBM_MULTIPLY_COMM_MEMPOOL)
605 assert(iter != NULL);
635 const int itick = (iter->
itick + shift) % iter->
nticks;
void cp_mpi_free_mem(void *mem)
Wrapper around MPI_Free_mem.
void cp_mpi_max_int(int *values, const int count, const cp_mpi_comm_t comm)
Wrapper around MPI_Allreduce for op MPI_MAX and datatype MPI_INT.
int cp_mpi_sendrecv_byte(const void *sendbuf, const int sendcount, const int dest, const int sendtag, void *recvbuf, const int recvcount, const int source, const int recvtag, const cp_mpi_comm_t comm)
Wrapper around MPI_Sendrecv for datatype MPI_BYTE.
void cp_mpi_alltoallv_double(const double *sendbuf, const int *sendcounts, const int *sdispls, double *recvbuf, const int *recvcounts, const int *rdispls, const cp_mpi_comm_t comm)
Wrapper around MPI_Alltoallv for datatype MPI_DOUBLE.
int cp_mpi_cart_rank(const cp_mpi_comm_t comm, const int coords[])
Wrapper around MPI_Cart_rank.
void * cp_mpi_alloc_mem(size_t size)
Wrapper around MPI_Alloc_mem.
void cp_mpi_alltoall_int(const int *sendbuf, const int sendcount, int *recvbuf, const int recvcount, const cp_mpi_comm_t comm)
Wrapper around MPI_Alltoall for datatype MPI_INT.
bool cp_mpi_comms_are_similar(const cp_mpi_comm_t comm1, const cp_mpi_comm_t comm2)
Wrapper around MPI_Comm_compare.
void cp_mpi_alltoallv_byte(const void *sendbuf, const int *sendcounts, const int *sdispls, void *recvbuf, const int *recvcounts, const int *rdispls, const cp_mpi_comm_t comm)
Wrapper around MPI_Alltoallv for datatype MPI_BYTE.
int cp_mpi_sendrecv_double(const double *sendbuf, const int sendcount, const int dest, const int sendtag, double *recvbuf, const int recvcount, const int source, const int recvtag, const cp_mpi_comm_t comm)
Wrapper around MPI_Sendrecv for datatype MPI_DOUBLE.
static int imax(int x, int y)
Returns the larger of two given integers (missing from the C standard).
static int dbm_get_shard_index(const dbm_matrix_t *matrix, const int row, const int col)
Internal routine for getting a block's shard index.
static int dbm_get_num_shards(const dbm_matrix_t *matrix)
Internal routine that returns the number of shards for given matrix.
static void free_packed_matrix(dbm_packed_matrix_t *packed)
Private routine for releasing a packed matrix.
static void icumsum(const int n, const int input[n], int output[n])
Private routine for computing the cumulative sums of given numbers.
static void create_pack_plans(const bool trans_matrix, const bool trans_dist, const dbm_matrix_t *matrix, const cp_mpi_comm_t comm, const dbm_dist_1d_t *dist_indices, const dbm_dist_1d_t *dist_ticks, const int nticks, const int npacks, plan_t *plans_per_pack[npacks], int nblks_per_pack[npacks], int ndata_per_pack[npacks])
Private routine for planing packs.
static void postprocess_received_blocks(const int nranks, const int nshards, const int nblocks_recv, const int blks_recv_count[nranks], const int blks_recv_displ[nranks], const int data_recv_displ[nranks], dbm_pack_block_t blks_recv[nblocks_recv])
Private routine for post-processing received blocks.
dbm_comm_iterator_t * dbm_comm_iterator_start(const bool transa, const bool transb, const dbm_matrix_t *matrix_a, const dbm_matrix_t *matrix_b, const dbm_matrix_t *matrix_c)
Internal routine for creating a communication iterator.
static void fill_send_buffers(const dbm_matrix_t *matrix, const bool trans_matrix, const int nblks_send, const int ndata_send, plan_t plans[nblks_send], const int nranks, int blks_send_count[nranks], int data_send_count[nranks], int blks_send_displ[nranks], int data_send_displ[nranks], dbm_pack_block_t blks_send[nblks_send], double data_send[ndata_send])
Private routine for filling send buffers.
static int gcd(const int a, const int b)
Private routine for computing greatest common divisor of two numbers.
static int lcm(const int a, const int b)
Private routine for computing least common multiple of two numbers.
void dbm_comm_iterator_stop(dbm_comm_iterator_t *iter)
Internal routine for releasing the given communication iterator.
static dbm_packed_matrix_t pack_matrix(const bool trans_matrix, const bool trans_dist, const dbm_matrix_t *restrict matrix, const dbm_distribution_t *restrict dist, const int nticks)
Private routine for redistributing a matrix along selected dimensions.
static dbm_pack_t * sendrecv_pack(const int itick, const int nticks, dbm_packed_matrix_t *packed)
Private routine for sending and receiving the pack for the given tick.
static int compare_pack_blocks_by_sum_index(const void *a, const void *b)
Private comperator passed to qsort to compare two blocks by sum_index.
bool dbm_comm_iterator_next(dbm_comm_iterator_t *iter, dbm_pack_t **pack_a, dbm_pack_t **pack_b)
Internal routine for retrieving next pair of packs of given iterator.
static unsigned long long calculate_tick_index(int sum_index, int nticks)
Private routine for calculating tick indices in pack plans.
static void compute_data_recv_count(const int nranks, const int blks_recv_count[nranks], const int blks_recv_displ[nranks], const int free_index_sizes[], const int sum_index_sizes[], const dbm_pack_block_t blks_recv[], int data_recv_count[nranks])
Private routine computing received data counts from block metadata.
static int isum(const int n, const int input[n])
Private routine for computing the sum of the given integers.
static int checked_byte_count(const int nelements, const size_t element_size)
Private routine for converting element counts to byte counts.
static void const int const int i
void offload_mempool_host_free(const void *memory)
Internal routine for releasing memory back to the pool.
void * offload_mempool_host_malloc(const size_t size)
Internal routine for allocating host memory from the pool.
Internal struct for storing a block's metadata.
Internal struct for storing a communication iterator.
dbm_packed_matrix_t packed_a
dbm_distribution_t * dist
dbm_packed_matrix_t packed_b
Internal struct for storing a one dimensional distribution.
Internal struct for storing a two dimensional distribution.
Internal struct for storing a matrix.
dbm_distribution_t * dist
Internal struct for storing a dbm_block_t plus its norm.
Internal struct for storing a pack - essentially a shard for MPI.
dbm_pack_block_t * blocks
Internal struct for storing a packed matrix.
const dbm_dist_1d_t * dist_ticks
const dbm_dist_1d_t * dist_indices
Internal struct for storing a matrix shard.
Private struct used for planing during pack_matrix.