Skip to content

Commit

Permalink
Merge pull request #1 from cheng-zhao/develop
Browse files Browse the repository at this point in the history
MPI optimization
  • Loading branch information
cheng-zhao authored Jun 26, 2022
2 parents c0c0d5d + 634d272 commit 16e18b3
Show file tree
Hide file tree
Showing 33 changed files with 572 additions and 483 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# FCFC Change Log

## [1.0.1] – 2022-06-26

- Refactorized the implementation of MPI and OpenMP parallelisms.
- Optimized MPI communications with custom structs, and fixed the deadlock due to multiple broadcasts.

4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ TARGETS = FCFC_2PT_BOX FCFC_2PT

# Set mandatory options (do not edit below this line).
LIBS += -lm
INCL += -Isrc/fcfc/common -Isrc/io -Isrc/lib -Isrc/math -Isrc/tree
SRCS = $(wildcard src/fcfc/common/*.c src/*/*.c)
INCL += -Isrc/util -Isrc/io -Isrc/lib -Isrc/math -Isrc/tree
SRCS = $(wildcard src/*/*.c)


all: $(TARGETS)
Expand Down
4 changes: 2 additions & 2 deletions options.mk
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ WITH_MU_ONE :=
# Set `WITH_CFITSIO := T` to enable FITS file format.
# The paths for cfitsio header (fitsio.h) and library (libcfitsio.{a,so,dylib})
# files can be set via `CFITSIO_INC_DIR` and `CFITSIO_LIB_DIR`, respectively.
WITH_CFITSIO := T
WITH_CFITSIO :=
CFITSIO_INC_DIR :=
CFITSIO_LIB_DIR :=

# Set `WITH_HDF5 := T` to enable HDF5 file format.
# The paths for libhdf5 header (hdf5.h) and library (libhdf5.{a,so,dylib})
# files can be set via `HDF5_INC_DIR` and `HDF5_LIB_DIR`, respectively.
WITH_HDF5 := T
WITH_HDF5 :=
HDF5_INC_DIR :=
HDF5_LIB_DIR :=

21 changes: 8 additions & 13 deletions src/fcfc/2pt/build_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef MPI
#include <mpi.h>
#endif

/*============================================================================*\
Function for pre-processing the input catalog
Expand Down Expand Up @@ -147,13 +144,13 @@ Function `tree_create`:
* `conf`: structure for storing configurations;
* `cf`: structure for correlation function evaluations;
* `idx`: index of the catalogue to be processed;
* `rank`: ID of MPI task.
* `para`: structure for parallelisms.
Return:
Address of the tree on success; NULL on error.
******************************************************************************/
void *tree_create(const CONF *conf, CF *cf, const int idx
#ifdef MPI
, const int rank
, const PARA *para
#endif
) {
void *tree = NULL;
Expand All @@ -165,7 +162,7 @@ void *tree_create(const CONF *conf, CF *cf, const int idx
DATA *data = cf->data + idx;

#ifdef MPI
if (rank == FCFC_MPI_ROOT) {
if (para->rank == para->root) {
#endif
if (!conf) {
P_ERR("configuration parameters are not loaded\n");
Expand Down Expand Up @@ -317,9 +314,8 @@ void *tree_create(const CONF *conf, CF *cf, const int idx
/* Broadcast the data catalog and tree. */
switch (cf->treetype) {
case FCFC_STRUCT_KDTREE:
kdtree_broadcast((KDT **) (&tree), &nnode, cf->wt[idx], FCFC_MPI_ROOT,
rank);
if (rank != FCFC_MPI_ROOT) {
kdtree_broadcast((KDT **) (&tree), &nnode, cf->wt[idx], para);
if (para->rank != para->root) {
KDT *root = (KDT *) tree;
cf->data[idx].n = root->n;
cf->data[idx].x[0] = root->x[0];
Expand All @@ -330,9 +326,8 @@ void *tree_create(const CONF *conf, CF *cf, const int idx
}
break;
case FCFC_STRUCT_BALLTREE:
balltree_broadcast((BLT **) (&tree), &nnode, cf->wt[idx], FCFC_MPI_ROOT,
rank);
if (rank != FCFC_MPI_ROOT) {
balltree_broadcast((BLT **) (&tree), &nnode, cf->wt[idx], para);
if (para->rank != para->root) {
BLT *root = (BLT *) tree;
cf->data[idx].n = root->n;
cf->data[idx].x[0] = root->x[0];
Expand All @@ -347,7 +342,7 @@ void *tree_create(const CONF *conf, CF *cf, const int idx
return NULL;
}

if (rank == FCFC_MPI_ROOT) {
if (para->rank == para->root) {
#endif
printf(FMT_DONE);
#ifdef MPI
Expand Down
4 changes: 2 additions & 2 deletions src/fcfc/2pt/build_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ Function `tree_create`:
* `conf`: structure for storing configurations;
* `cf`: structure for correlation function evaluations;
* `idx`: index of the catalogue to be processed;
* `rank`: ID of MPI task.
* `para`: structure for parallelisms.
Return:
Address of the tree on success; NULL on error.
******************************************************************************/
void *tree_create(const CONF *conf, CF *cf, const int idx
#ifdef MPI
, const int rank
, const PARA *para
#endif
);

Expand Down
52 changes: 24 additions & 28 deletions src/fcfc/2pt/count_func.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#ifdef MPI
#include <mpi.h>
#endif
#ifdef OMP
#include <omp.h>
#endif
Expand Down Expand Up @@ -4842,15 +4839,14 @@ Function `count_pairs`:
* `cnt`: array for storing pair counts;
* `isauto`: true for counting auto pairs;
* `withwt`: true for enabling weights;
* `ntask`: number of MPI tasks;
* `rank`: ID of MPI task.
* `para`: structure for parallelisms.
Return:
Zero on success; non-zero on error.
******************************************************************************/
int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,
const bool isauto, const bool withwt
#ifdef MPI
, const int ntask, const int rank
, const PARA *para
#endif
) {
void (*paircnt_func) (STACK_DUAL_NODE *, const void *, void *) = NULL;
Expand Down Expand Up @@ -7114,7 +7110,7 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,
/* Prepare for dynamic MPI scheduler. */
uint32_t *addr = NULL;
MPI_Aint win_size = 0;
if (rank == FCFC_MPI_ROOT) {
if (para->rank == para->root) {
win_size = sizeof(uint32_t);
if (MPI_Alloc_mem(win_size, MPI_INFO_NULL, &addr)) {
P_ERR("failed to allocate memory for MPI window\n");
Expand All @@ -7124,14 +7120,14 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,
}
MPI_Win win;
if (MPI_Win_create(addr, win_size, sizeof(uint32_t), MPI_INFO_NULL,
MPI_COMM_WORLD, &win)) {
para->comm, &win)) {
P_ERR("failed to create the MPI window\n");
free(conf); FCFC_QUIT(FCFC_ERR_MPI);
}
uint32_t start, step = cf->nthread * FCFC_STACK_SIZE_PER_THREAD;

/* Compute the tree level for dual-node distribution. */
size_t nnodes = ntask * FCFC_STACK_SIZE_PER_TASK;
size_t nnodes = para->ntask * FCFC_STACK_SIZE_PER_TASK;
#ifdef OMP /* both MPI and OMP */
nnodes *= cf->nthread * FCFC_STACK_SIZE_PER_THREAD;
#endif
Expand All @@ -7147,9 +7143,9 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,

/* Distribute dual nodes to tasks dynamically. */
do {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, FCFC_MPI_ROOT, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, FCFC_MPI_ROOT, 0,
MPI_SUM, win) || MPI_Win_unlock(FCFC_MPI_ROOT, win)) {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, para->root, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, para->root, 0,
MPI_SUM, win) || MPI_Win_unlock(para->root, win)) {
P_ERR("failed to fetch dual nodes with MPI tasks\n");
free(conf); free(nodes);
FCFC_QUIT(FCFC_ERR_MPI);
Expand Down Expand Up @@ -7210,9 +7206,9 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,

/* Distribute dual nodes to tasks dynamically. */
do {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, FCFC_MPI_ROOT, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, FCFC_MPI_ROOT, 0,
MPI_SUM, win) || MPI_Win_unlock(FCFC_MPI_ROOT, win)) {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, para->root, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, para->root, 0,
MPI_SUM, win) || MPI_Win_unlock(para->root, win)) {
P_ERR("failed to fetch dual nodes with MPI tasks\n");
free(conf); free(nodes1); free(nodes2);
FCFC_QUIT(FCFC_ERR_MPI);
Expand Down Expand Up @@ -7270,9 +7266,9 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,

/* Distribute dual nodes to tasks dynamically. */
do {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, FCFC_MPI_ROOT, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, FCFC_MPI_ROOT, 0,
MPI_SUM, win) || MPI_Win_unlock(FCFC_MPI_ROOT, win)) {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, para->root, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, para->root, 0,
MPI_SUM, win) || MPI_Win_unlock(para->root, win)) {
P_ERR("failed to fetch dual nodes with MPI tasks\n");
free(conf); free(nodes);
FCFC_QUIT(FCFC_ERR_MPI);
Expand Down Expand Up @@ -7333,9 +7329,9 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,

/* Distribute dual nodes to tasks dynamically. */
do {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, FCFC_MPI_ROOT, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, FCFC_MPI_ROOT, 0,
MPI_SUM, win) || MPI_Win_unlock(FCFC_MPI_ROOT, win)) {
if (MPI_Win_lock(MPI_LOCK_EXCLUSIVE, para->root, 0, win) ||
MPI_Fetch_and_op(&step, &start, MPI_UINT32_T, para->root, 0,
MPI_SUM, win) || MPI_Win_unlock(para->root, win)) {
P_ERR("failed to fetch dual nodes with MPI tasks\n");
free(conf); free(nodes1); free(nodes2);
FCFC_QUIT(FCFC_ERR_MPI);
Expand Down Expand Up @@ -7386,7 +7382,7 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,

/* Cleanup MPI scheduler. */
if (MPI_Win_free(&win) ||
(rank == FCFC_MPI_ROOT && MPI_Free_mem(addr))) {
(para->rank == para->root && MPI_Free_mem(addr))) {
P_ERR("failed to release memory for MPI scheduler\n");
free(conf); stack_destroy(&stack);
FCFC_QUIT(FCFC_ERR_MPI);
Expand Down Expand Up @@ -7630,16 +7626,16 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,
for (size_t i = 0; i < cf->ntot; i++) pcnt[i] = cnt[i].d;
}

if (rank == FCFC_MPI_ROOT) {
if (para->rank == para->root) {
if (MPI_Ireduce(MPI_IN_PLACE, pcnt, cf->ntot, MPI_DOUBLE, MPI_SUM,
FCFC_MPI_ROOT, MPI_COMM_WORLD, &req)) {
para->root, para->comm, &req)) {
P_ERR("failed to gather pair counts from MPI tasks\n");
FCFC_QUIT(FCFC_ERR_MPI);
}
}
else {
if (MPI_Ireduce(pcnt, NULL, cf->ntot, MPI_DOUBLE, MPI_SUM,
FCFC_MPI_ROOT, MPI_COMM_WORLD, &req)) {
para->root, para->comm, &req)) {
P_ERR("failed to gather pair counts from MPI tasks\n");
FCFC_QUIT(FCFC_ERR_MPI);
}
Expand All @@ -7662,16 +7658,16 @@ int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,
for (size_t i = 0; i < cf->ntot; i++) pcnt[i] = cnt[i].i;
}

if (rank == FCFC_MPI_ROOT) {
if (para->rank == para->root) {
if (MPI_Ireduce(MPI_IN_PLACE, pcnt, cf->ntot, MPI_INT64_T, MPI_SUM,
FCFC_MPI_ROOT, MPI_COMM_WORLD, &req)) {
para->root, para->comm, &req)) {
P_ERR("failed to gather pair counts from MPI tasks\n");
FCFC_QUIT(FCFC_ERR_MPI);
}
}
else {
if (MPI_Ireduce(pcnt, NULL, cf->ntot, MPI_INT64_T, MPI_SUM,
FCFC_MPI_ROOT, MPI_COMM_WORLD, &req)) {
para->root, para->comm, &req)) {
P_ERR("failed to gather pair counts from MPI tasks\n");
FCFC_QUIT(FCFC_ERR_MPI);
}
Expand Down
5 changes: 2 additions & 3 deletions src/fcfc/2pt/count_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,14 @@ Function `kdtree_count_cross_pairs`:
* `cnt`: array for storing pair counts;
* `isauto`: true for counting auto pairs;
* `withwt`: true for enabling weights;
* `ntask`: number of MPI tasks;
* `rank`: ID of MPI task.
* `para`: structure for parallelisms.
Return:
Zero on success; non-zero on error.
******************************************************************************/
int count_pairs(const void *tree1, const void *tree2, CF *cf, COUNT *cnt,
const bool isauto, const bool withwt
#ifdef MPI
, const int ntask, const int rank
, const PARA *para
#endif
);

Expand Down
Loading

0 comments on commit 16e18b3

Please sign in to comment.