#include <getopt.h> #include <mpi.h> #include <stdlib.h> #include <stdio.h> #include "configuration.h" const char *verbosity_levels[] = {"OFF", "INFO", "DEBUG", "TRACE"}; const char *transmission_modes[] = { "Dynamic - MPI_Issend / MPI_Iprobe / MPI_Ibarrier", "Collective - MPI_Alltoall / MPI_Alltoallw", "Remote Memory Access (RMA) - MPI_Accumulate / MPI_Probe" }; // --------------------------------------------- Helper function declarations const char* set_ncells(conf_t *c, int nprocs); long parse_long(const char *str); int log_enabled(const conf_t *c, int lvl); // ========================================================================== void conf_init(conf_t *c) { c->verbosity_level = INFO; c->ncells_x = 0; c->ncells_y = 0; c->debug_rank = -1; c->use_cartesian_topology = 0; #if MPI_VERSION >= 3 c->transmission_mode = DYNAMIC; #else #pragma message("MPI_VERSION < 3: Default transmission mode will be collective.") c->transmission_mode = COLLECTIVE; #endif // Default values: c->n_iterations = 100; c->particles_per_cell_initial = 1<<14; // 16k particles c->delta_t = 1.0; c->min_mass = 1.0; c->max_mass = 1.0; c->max_force = 0.0; c->max_velocity_initial = 1.0; // 1 cell width per iteration } const char* conf_set_from_args(conf_t *c, int argc, char* argv[], int nprocs) { struct option long_options[] = { {"verbose", required_argument, NULL, 'v'}, {"debug-rank", required_argument, NULL, 'g'}, {"use-cart-topo", no_argument, &c->use_cartesian_topology, 1}, {"collective", no_argument, &c->transmission_mode, COLLECTIVE}, {"dynamic", no_argument, &c->transmission_mode, DYNAMIC}, {"rma", no_argument, &c->transmission_mode, RMA}, {"ncells-x", required_argument, NULL, 'x'}, {"ncells-y", required_argument, NULL, 'y'}, {"iterations", required_argument, NULL, 'i'}, {"particles-per-cell", required_argument, NULL, 'n'}, {"particles-total", required_argument, NULL, 'N'}, {"delta-t", required_argument, NULL, 't'}, {"min-mass", required_argument, NULL, 'm'}, {"max-mass", required_argument, NULL, 'M'}, {"max-force", required_argument, NULL, 'F'}, {"max-velocity", required_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; int option; while((option = getopt_long(argc, argv, "v:g:x:y:i:n:N:t:m:M:F:V:", long_options, NULL)) >= 0) { switch(option) { case 'v': c->verbosity_level = atoi(optarg); break; case 'g': c->debug_rank = atoi(optarg); break; case 'x': c->ncells_x = atoi(optarg); break; case 'y': c->ncells_y = atoi(optarg); break; case 'i': c->n_iterations = parse_long(optarg); break; case 'n': c->particles_per_cell_initial = parse_long(optarg); break; case 'N': c->particles_per_cell_initial = parse_long(optarg) / nprocs; break; case 't': c->delta_t = atof(optarg); break; case 'm': c->min_mass = atof(optarg); break; case 'M': c->max_mass = atof(optarg); break; case 'F': c->max_force = atof(optarg); break; case 'V': c->max_velocity_initial = atof(optarg); break; } } return set_ncells(c, nprocs); } void conf_print(const conf_t *c, FILE *f) { int i = c->verbosity_level; if(i < 0) i = 0; else if(i > 3) i = 3; fprintf(f, "Configuration:\n"); fprintf(f, " * Verbosity level: %s (%d)\n", verbosity_levels[i], c->verbosity_level); fprintf(f, " * Use MPI Cart. Topology: %s\n", c->use_cartesian_topology ? "YES" : "NO"); fprintf(f, " * Transmission mode: %s\n", transmission_modes[c->transmission_mode]); fprintf(f, " * Number of cells: %d x %d\n", c->ncells_x, c->ncells_y); fprintf(f, " * Particles per cell: %d\n", c->particles_per_cell_initial); fprintf(f, " * Number of iterations: %d\n", c->n_iterations); fprintf(f, " * Init. Velocity max: %f\n", c->max_velocity_initial); fprintf(f, " * Timestep: %f\n", c->delta_t); fprintf(f, " * Particle mass (min-max): %f - %f\n", c->min_mass, c->max_mass); fprintf(f, " * Max. random force: %f\n", c->max_force); fprintf(f, "\n"); } const char* set_ncells(conf_t *c, int nprocs) { static char error[1024]; int nx = c->ncells_x; int ny = c->ncells_y; if(nx > 0) { if(ny > 0) { if(nx * ny != nprocs) { snprintf(error, sizeof(error), "Number of cells in x and y direction does not match the number of processes (%d * %d != %d).", nx, ny, nprocs); return error; } } if(nprocs % nx != 0) { snprintf(error, sizeof(error), "Number of cells in x direction must divide the number of processes (%d %% %d != 0).", nprocs, nx); return error; } ny = nprocs / nx; } else if(ny > 0) { if(nprocs % ny != 0) { snprintf(error, sizeof(error), "Number of cells in y direction must divide the number of processes (%d %% %d != 0).", nprocs, ny); return error; } nx = nprocs / ny; } else { snprintf(error, sizeof(error), "Number of cells in x and y directions not defined. Use option --ncells-x or --ncells-y."); return error; } c->ncells_x = nx; c->ncells_y = ny; return NULL; } int log_enabled(const conf_t *c, int lvl) { static int rank = -1; if(rank < 0) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); } return c->verbosity_level >= lvl && (rank == 0 || rank == c->debug_rank); } int info_enabled(const conf_t *c) { return log_enabled(c, INFO); } int debug_enabled(const conf_t *c) { return log_enabled(c, DEBUG); } int trace_enabled(const conf_t *c) { return log_enabled(c, TRACE); } // --------------------------------------------------------- Helper functions long parse_long(const char *str) { char* p; long result = strtol(str, &p, 10); if(*p == 'k') { result <<= 10; } else if(*p == 'M') { result <<= 20; } return result; }