Skip to content
Snippets Groups Projects
configuration.c 5.87 KiB
Newer Older
#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;
}