14#ifdef YAC_NETCDF_ENABLED
18#define IO_RANK_LIST_STR "YAC_IO_RANK_LIST"
19#define IO_MAX_NUM_RANKS_STR "YAC_IO_MAX_NUM_RANKS"
20#define IO_RANK_EXCLUDE_LIST_STR "YAC_IO_RANK_EXCLUDE_LIST"
21#define IO_MAX_NUM_RANKS_PER_NODE "YAC_IO_MAX_NUM_RANKS_PER_NODE"
22#define DEFAULT_MAX_NUM_IO_RANK_PER_NODE (1)
24static inline int compare_int(
const void * a,
const void * b) {
26 int const * a_ = a, * b_ = b;
28 return (*a_ > *b_) - (*b_ > *a_);
32 char const * env_name, MPI_Comm comm,
size_t * num_ranks_,
int ** ranks_) {
45 char * rank_list_str = getenv(env_name);
46 if ((rank_list_str != NULL) && (rank_list_str[0] !=
'\0')) {
48 int temp_num_ranks = 1;
49 for (
char * curr_char = rank_list_str + 1; *curr_char !=
'\0'; ++curr_char)
50 if (*curr_char ==
',') ++temp_num_ranks;
52 char * rank_list_copy =
xstrdup(rank_list_str);
54 int * world_ranks =
xmalloc(temp_num_ranks *
sizeof(*world_ranks));
56 yac_mpi_call(MPI_Comm_size(MPI_COMM_WORLD, &world_size), MPI_COMM_WORLD);
59 char * rank_str = strtok(rank_list_copy,
",");
60 while (rank_str != NULL) {
61 int curr_rank = atoi(rank_str);
62 YAC_ASSERT_F(curr_rank >= 0,
"\"%s\" is not a valid rank", rank_str);
64 curr_rank < world_size,
"rank %d exceeds size of MPI_COMM_WORLD (%d)",
65 curr_rank, world_size);
66 world_ranks[num_ranks++] = curr_rank;
67 rank_str = strtok(NULL,
",");
72 qsort(world_ranks, num_ranks,
sizeof(*world_ranks),
compare_int);
78 ranks =
xmalloc(num_ranks *
sizeof(ranks));
79 MPI_Group world_group, comm_group;
81 MPI_Comm_group(MPI_COMM_WORLD, &world_group), MPI_COMM_WORLD);
84 MPI_Group_translate_ranks(
85 world_group, (
int)num_ranks, world_ranks,
86 comm_group, ranks), MPI_COMM_WORLD);
88 yac_mpi_call(MPI_Group_free(&world_group), MPI_COMM_WORLD);
92 size_t new_num_ranks = 0;
93 for (
size_t i = 0; i < num_ranks; ++i) {
94 if (ranks[i] != MPI_UNDEFINED) {
95 if (i != new_num_ranks)
96 ranks[new_num_ranks] = ranks[i];
100 num_ranks = new_num_ranks;
103 qsort(ranks, num_ranks,
sizeof(*ranks),
compare_int);
110 ranks =
xrealloc(ranks, num_ranks *
sizeof(*ranks));
112 MPI_Bcast(ranks, (
int)num_ranks, MPI_INT, 0, comm), comm);
122 ranks =
xmalloc(num_ranks *
sizeof(*ranks));
124 MPI_Bcast(ranks, (
int)num_ranks, MPI_INT, 0, comm), comm);
127 *num_ranks_ = num_ranks;
132 MPI_Comm comm,
size_t * num_io_ranks,
int ** io_ranks) {
138 MPI_Comm comm,
size_t * num_io_ranks_,
int ** io_ranks_) {
144 int max_num_io_rank_per_node;
146 max_num_io_rank_per_node =
151 if (max_num_io_rank_per_node == -1)
return;
157 comm, MPI_COMM_TYPE_SHARED, rank, MPI_INFO_NULL, &node_comm), comm);
161 yac_mpi_call(MPI_Comm_rank(node_comm, &node_rank), node_comm);
164 int * node_ranks =
xmalloc(*num_io_ranks_ *
sizeof(*node_ranks));
165 MPI_Group io_group, node_group;
167 yac_mpi_call(MPI_Comm_group(node_comm, &node_group), node_comm);
169 MPI_Group_translate_ranks(
170 io_group, (
int)*num_io_ranks_, *io_ranks_,
171 node_group, node_ranks), comm);
177 size_t num_node_io_ranks = 0;
178 for (
size_t i = 0; i < *num_io_ranks_; ++i) {
179 if (node_ranks[i] != MPI_UNDEFINED) {
180 if (i != num_node_io_ranks)
181 node_ranks[num_node_io_ranks] = node_ranks[i];
187 qsort(node_ranks, num_node_io_ranks,
sizeof(*node_ranks),
compare_int);
190 int local_is_io_rank = 0;
192 (i < num_node_io_ranks) &&
193 (i < (
size_t)max_num_io_rank_per_node) && !local_is_io_rank; ++i)
194 if (node_ranks[i] == node_rank) local_is_io_rank = 1;
198 int * is_io_rank =
xmalloc((
size_t)size *
sizeof(*is_io_rank));
201 &local_is_io_rank, 1, MPI_INT, is_io_rank, 1, MPI_INT, comm), comm);
204 size_t num_io_ranks = 0;
205 for (
int i = 0; i < size; ++i)
206 if (is_io_rank[i]) is_io_rank[num_io_ranks++] = i;
209 *num_io_ranks_ = num_io_ranks;
210 *io_ranks_ =
xrealloc(is_io_rank, num_io_ranks *
sizeof(**io_ranks_));
214 MPI_Comm comm,
size_t * num_io_ranks,
int ** io_ranks) {
222 if (max_num_ranks == -1)
return;
224 if ((max_num_ranks > 0) && ((
size_t)max_num_ranks < *num_io_ranks)) {
226 xrealloc(*io_ranks, (
size_t)max_num_ranks *
sizeof(**io_ranks));
227 *num_io_ranks = (size_t)max_num_ranks;
232 MPI_Comm comm,
size_t * num_io_ranks,
int ** io_ranks) {
235 size_t num_io_ranks_excluded;
236 int * io_ranks_excluded;
241 if (num_io_ranks_excluded > 0) {
244 qsort(*io_ranks, *num_io_ranks,
sizeof(**io_ranks),
compare_int);
247 size_t new_num_io_ranks = 0;
248 for (
size_t i = 0, j = 0; i < *num_io_ranks; ++i) {
250 while ((j < num_io_ranks_excluded) &&
251 (io_ranks_excluded[j] < (*io_ranks)[i])) ++j;
253 if ((j >= num_io_ranks_excluded) ||
254 ((*io_ranks)[i] != io_ranks_excluded[j])) {
256 if (i != new_num_io_ranks)
257 (*io_ranks)[new_num_io_ranks] = (*io_ranks)[i];
262 if (new_num_io_ranks != *num_io_ranks) {
263 *io_ranks =
xrealloc(*io_ranks, new_num_io_ranks *
sizeof(**io_ranks));
264 *num_io_ranks = new_num_io_ranks;
268 free(io_ranks_excluded);
272 MPI_Comm comm,
int * local_is_io_,
int ** io_ranks_,
int * num_io_ranks_) {
278 size_t num_io_ranks = 0;
279 int * io_ranks = NULL;
285 if (num_io_ranks == 0) {
286 num_io_ranks = (size_t)size;
287 io_ranks =
xmalloc(num_io_ranks *
sizeof(*io_ranks));
288 for (
int i = 0; i < size; ++i) io_ranks[i] = i;
300 YAC_ASSERT(num_io_ranks > 0,
"could not determine io ranks");
303 for (
size_t i = 0; (i < num_io_ranks) && !local_is_io; ++i)
304 if (io_ranks[i] == rank) local_is_io = 1;
306 *local_is_io_ = local_is_io;
307 *io_ranks_ = io_ranks;
308 *num_io_ranks_ = (int)num_io_ranks;
313#ifndef YAC_NETCDF_ENABLED
318 die(
"ERROR(yac_nc_open): YAC is built without the NetCDF support");
328#ifndef YAC_NETCDF_ENABLED
333 die(
"ERROR(yac_nc_create): YAC is built without the NetCDF support");
336 int status = nc_create(path, cmode, ncidp);
339 "failed to create file \"%s\" (NetCDF error message: \"%s\")",
340 path, nc_strerror(status));
346#ifndef YAC_NETCDF_ENABLED
351 die(
"ERROR(yac_nc_inq_dimid): YAC is built without the NetCDF support");
354 int status = nc_inq_dimid(ncid,
name, dimidp);
356 if (status == NC_EBADDIM) {
360 char * path =
xmalloc(pathlen *
sizeof(*path));
363 0,
"dimension \"%s\" could not be found in file \"%s\"",
name, path);
371#ifndef YAC_NETCDF_ENABLED
376 die(
"ERROR(yac_nc_inq_varid): YAC is built without the NetCDF support");
379 int status = nc_inq_varid(ncid,
name, varidp);
381 if (status == NC_ENOTVAR) {
385 char * path =
xmalloc(pathlen *
sizeof(*path));
388 0,
"variable \"%s\" could not be found in file \"%s\"",
name, path);
396 return !stat(filename,&
buffer);
401 YAC_ASSERT(path != NULL,
"path must not be NULL");
402 YAC_ASSERT(path[0] !=
'\0',
"path must not be an empty string");
404 FILE *f = fopen(path,
"r");
406 YAC_ASSERT_F(f,
"failed to open file \"%s\" for reading", path);
407 YAC_ASSERT(needle != NULL,
"needle must not be NULL");
408 YAC_ASSERT(needle[0] !=
'\0',
"needle must not be an empty string");
414 while (!found && (getline(&line, &line_cap, f) != -1)) {
415 found = strstr(line, needle) != NULL;
418 YAC_ASSERT_F(!ferror(f),
"failed to read file \"%s\"", path);
427 char const *path_prefix,
char const *path_suffix,
char const *extension) {
429 YAC_ASSERT(path_prefix != NULL,
"path_prefix must not be NULL");
430 YAC_ASSERT(path_prefix[0] !=
'\0',
"path_prefix must not be empty");
431 YAC_ASSERT(path_suffix != NULL,
"path_suffix must not be NULL");
432 YAC_ASSERT(path_suffix[0] !=
'\0',
"path_suffix must not be empty");
434 extension = extension ? extension :
"";
436 size_t len_prefix = strlen(path_prefix);
437 size_t len_suffix = strlen(path_suffix);
438 size_t len_extension = strlen(extension);
439 size_t len = len_prefix + len_suffix + len_extension + 2;
440 char * path =
xmalloc(len *
sizeof(*path));
442 int nw = snprintf(path, len,
"%s/%s%s", path_prefix, path_suffix, extension);
445 (nw >= 0) && ((
size_t)nw < len),
446 "failed to construct path from \"%s\", \"%s\", [and \"%s\"]",
447 path_prefix, path_suffix, extension);
454 YAC_ASSERT(path != NULL,
"path must not be NULL");
455 YAC_ASSERT(path[0] !=
'\0',
"path must not be an empty string");
457 DIR *dir = opendir(path);
459 YAC_ASSERT_F(dir != NULL,
"failed to open directory \"%s\"", path);
461 struct dirent *entry;
463 while ((entry = readdir(dir)) != NULL) {
466 if (!strcmp(entry->d_name,
".") ||
467 !strcmp(entry->d_name,
"..")) {
475 YAC_ASSERT_F(stat(child, &statbuf) == 0,
"failed to stat \"%s\"", child);
479 if (S_ISDIR(statbuf.st_mode)) {
485 int status = unlink(child);
487 YAC_ASSERT_F(status == 0,
"failed to remove file \"%s\"", child);
493 int status = closedir(dir);
494 YAC_ASSERT_F(status == 0,
"failed to close directory \"%s\"", path);
496 status = rmdir(path);
497 YAC_ASSERT_F(status == 0,
"failed to remove directory \"%s\"", path);
502 YAC_ASSERT(path != NULL,
"path must not be NULL");
503 YAC_ASSERT(path[0] !=
'\0',
"path must not be an empty string");
#define YAC_ASSERT(exp, msg)
#define IO_MAX_NUM_RANKS_PER_NODE
char * yac_file_path_join(char const *path_prefix, char const *path_suffix, char const *extension)
Join two path components with a '/' and optional extension.
static void read_io_rank_list(MPI_Comm comm, size_t *num_io_ranks, int **io_ranks)
#define DEFAULT_MAX_NUM_IO_RANK_PER_NODE
static void remove_directory_recursive(char const *path)
void yac_get_io_ranks(MPI_Comm comm, int *local_is_io_, int **io_ranks_, int *num_io_ranks_)
static void read_rank_list(char const *env_name, MPI_Comm comm, size_t *num_ranks_, int **ranks_)
void yac_nc_create(const char *path, int cmode, int *ncidp)
void yac_remove_directory(char const *path)
Remove a directory and its contents recursively.
void yac_nc_inq_varid(int ncid, char const *name, int *varidp)
#define IO_RANK_EXCLUDE_LIST_STR
static void check_io_max_num_ranks(MPI_Comm comm, size_t *num_io_ranks, int **io_ranks)
int yac_file_contains(char const *path, char const *needle)
Check whether a file contains a specific string.
static void check_io_max_num_ranks_per_node(MPI_Comm comm, size_t *num_io_ranks_, int **io_ranks_)
#define IO_MAX_NUM_RANKS_STR
int yac_file_exists(const char *filename)
Check whether a file exists.
static int compare_int(const void *a, const void *b)
void yac_nc_open(const char *path, int omode, int *ncidp)
void yac_nc_inq_dimid(int ncid, char const *name, int *dimidp)
static void check_io_rank_exclude_list(MPI_Comm comm, size_t *num_io_ranks, int **io_ranks)
#define xrealloc(ptr, size)
#define YAC_HANDLE_ERROR(exp)
int yac_getenv_int(const char *name, int default_value, int threshold, MPI_Comm comm)
static void yac_remove_duplicates_int(int *array, size_t *n)
#define YAC_ASSERT_F(exp, format,...)
#define yac_mpi_call(call, comm)