/****************************************************************************
**  LinkTest                                                               **
*****************************************************************************
**  Copyright (c) 2008-2010                                                **
**  Forschungszentrum Juelich, Juelich Supercomputing Centre               **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/

#include <mpi.h>
#include <stdio.h>
#include <string.h>

#ifdef _BGP
/* #include <spi/kernel_interface.h> */
#include <common/bgp_personality.h>
#include <common/bgp_personality_inlines.h>
#endif

#include <assert.h>
#include <stdlib.h>

#include "mapping.h"




int write_mapping (char *filename) {
  int num_procs, my_rank;
  int i,j;
  int *pos;
  int mypos[4];
  double a;

#ifdef _BGP
  char location[BGPPERSONALITY_MAX_LOCATION];
  FILE *outfile;
  _BGP_Personality_t personality;

  MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

  if(my_rank==10) {
    pos=(int *) malloc(num_procs*4*sizeof(int));
    if(!pos) {
      fprintf(stderr,"cannot allocate memory for mapping data\n");
      return(0);
    }
  } else {
    pos=NULL;
  }
  
  /*
   * BlueGene runtime: get and print BG personality
   */

  Kernel_GetPersonality(&personality, sizeof(personality));
  BGP_Personality_getLocationString(&personality, location);
  
  mypos[0] = personality.Network_Config.Xcoord;
  mypos[1] = personality.Network_Config.Ycoord;
  mypos[2] = personality.Network_Config.Zcoord;
  mypos[3] = Kernel_PhysicalProcessorID();

  MPI_Gather(mypos,4,MPI_INT,pos,4,MPI_INT,10,MPI_COMM_WORLD);

  if(my_rank==10) {
      outfile=fopen(filename,"w");
      if(outfile) {
	  fprintf(outfile,"BGL-Mapping: type=MPI_COMM_WORLD\n");
	  fprintf(outfile,"MPI-SIZE:  %d\n",num_procs);
	  fprintf(outfile,"VN-MODE:   %d\n",personality.Kernel_Config.ProcessConfig);
	  fprintf(outfile,"PART-SIZE: %d %d %d %d\n",	 personality.Network_Config.Xnodes,
		  personality.Network_Config.Ynodes,
		  personality.Network_Config.Znodes,
		  personality.Kernel_Config.ProcessConfig+1);
	  for(i=0;i<num_procs;i++) {
	      fprintf(outfile,"%04d %4d %4d %4d %4d\n",i,pos[i*4+0],pos[i*4+1],pos[i*4+2],pos[i*4+3]);
	  }
	  fclose(outfile);
      } else {
	  fprintf(stderr,"cannot open output file for mapping data: %s\n",filename);
	  return(0);
      }
      
  }

#endif
  return(1);
}

int  get_mapping (char **locationptr, int **mappingptr) {
  int num_procs, my_rank;
  int i,j;
  int *pos;
  int mypos[4];
  double a;
#ifdef _BGP
  char location[BGPPERSONALITY_MAX_LOCATION];
  _BGP_Personality_t personality;
#else
  char location[MAX_LOCATION_LENGTH];
#endif
  MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

  *mappingptr=(int *) malloc(4*sizeof(int));
  if(!*mappingptr) {
    fprintf(stderr,"cannot allocate memory for mapping data\n");
    return(0);
  }

  *locationptr=(char *) malloc(MAX_LOCATION_LENGTH);
  if(!*locationptr) {
    fprintf(stderr,"cannot allocate memory for mapping data\n");
    return(0);
  }
  
  /*
   * BlueGene runtime: get and print BG personality
   */

#ifdef _BGP
  Kernel_GetPersonality(&personality, sizeof(personality));
  BGP_Personality_getLocationString(&personality, location);
  
  (*mappingptr)[0] = personality.Network_Config.Xcoord;
  (*mappingptr)[1] = personality.Network_Config.Ycoord;
  (*mappingptr)[2] = personality.Network_Config.Zcoord;
  (*mappingptr)[3] = Kernel_PhysicalProcessorID();
#else
  (*mappingptr)[0] = my_rank;
  (*mappingptr)[1] = 0;
  (*mappingptr)[2] = 0;
  (*mappingptr)[3] = 0;
  gethostname(location,256);
#endif
  strncpy(*locationptr,location,MAX_LOCATION_LENGTH-1); 
  (*locationptr)[MAX_LOCATION_LENGTH-1]='\0'; 
/*   printf("WF: in get_mapping rank=%d >%s< max_location_length=%d bgppersonality_max_location=%d\n",my_rank,*locationptr,MAX_LOCATION_LENGTH,BGPPERSONALITY_MAX_LOCATION); */


  return(1);
}

int write_cart_mapping (char *filename, MPI_Comm cartesian_comm, int dim, int *dims) {
  int num_procs, my_rank, my_cart_rank;
  int i,j;
  int *pos;
  int *cartpos;
  int mypos[4];
  int mycartpos[5];
  int coords[16];
  double a;

#ifdef _BGP
  char location[BGPPERSONALITY_MAX_LOCATION];
  FILE *outfile;
  _BGP_Personality_t personality;

  MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

  pos=(int *) malloc(num_procs*4*sizeof(int));
  if(!pos) {
      fprintf(stderr,"cannot allocate memory for mapping data\n");
      return(0);
  }

  cartpos=(int *) malloc(num_procs*5*sizeof(int));
  if(!pos) {
      fprintf(stderr,"cannot allocate memory for mapping data\n");
      return(0);
  }
  
  /*
   * BlueGene runtime: get and print BG personality
   */

  Kernel_GetPersonality(&personality, sizeof(personality));
  BGP_Personality_getLocationString(&personality, location);
  
  mypos[0] = personality.Network_Config.Xcoord;
  mypos[1] = personality.Network_Config.Ycoord;
  mypos[2] = personality.Network_Config.Zcoord;
  mypos[3] = Kernel_PhysicalProcessorID();
  
  MPI_Gather(mypos,4,MPI_INT,pos,4,MPI_INT,0,MPI_COMM_WORLD);


  MPI_Cart_coords(cartesian_comm, my_rank, 4, coords);
  for(i=0; i<4; i++) mycartpos[i]=coords[i];
  MPI_Comm_rank(cartesian_comm, &my_cart_rank);
  mycartpos[4]=my_cart_rank;
  MPI_Gather(mycartpos,5,MPI_INT,cartpos,5,MPI_INT,0,MPI_COMM_WORLD);

  if(my_rank==10) {
      outfile=fopen(filename,"w");
      if(outfile) {
	  fprintf(outfile,"BGL-Mapping: type=cartesian grid dim=%d\n",dim);
	  fprintf(outfile,"MPI-SIZE:  %d\n",num_procs);
	  fprintf(outfile,"MPI-DIMS:  %d %d %d %d\n",	 dims[0],dims[1],dims[2],dims[3]);
	  fprintf(outfile,"VN-MODE:   %d\n",personality.Kernel_Config.ProcessConfig);
	  fprintf(outfile,"PART-SIZE: %d %d %d %d\n",	 personality.Network_Config.Xnodes,
		  personality.Network_Config.Ynodes,
		  personality.Network_Config.Znodes,
		  personality.Kernel_Config.ProcessConfig+1);
	  for(i=0;i<num_procs;i++) {
	      fprintf(outfile,"%04d %4d %4d %4d %4d  %4d   %4d %4d %4d %4d\n",i,
		      pos[i*4+0],pos[i*4+1],pos[i*4+2],pos[i*4+3],
		      cartpos[i*5+4],
		      cartpos[i*5+0],cartpos[i*5+1],cartpos[i*5+2],cartpos[i*5+3]
		  );
	  }
	  fclose(outfile);
      } else {
	  fprintf(stderr,"cannot open output file for mapping data: %s\n",filename);
	  return(0);
      }
      
  }

#endif
  return(1);
}
    
