/*
    -- clMAGMA (version 0.1) --
       Univ. of Tennessee, Knoxville
       Univ. of California, Berkeley
       Univ. of Colorado, Denver
       April 2012
*/

#include "common_magma.h"


// -------------------------
// Returns version of MAGMA, as defined by
// MAGMA_VERSION_MAJOR, MAGMA_VERSION_MINOR, MAGMA_VERSION_MICRO constants.
void magma_version( int* major, int* minor, int* micro )
{
    if ( major != NULL && minor != NULL && micro != NULL ) {
        *major = MAGMA_VERSION_MAJOR;
        *minor = MAGMA_VERSION_MINOR;
        *micro = MAGMA_VERSION_MICRO;
    }
}


/* ////////////////////////////////////////////////////////////////////////////
   -- Used by chk() macro to print error message.
*/
void chk_helper( int err, const char* func, const char* file, int line )
{
    if ( err != 0 ) {
        printf( "error in %s at %s:%d: %s (%d)\n",
                func, file, line, magma_strerror(err), err );
    }
}


/* ////////////////////////////////////////////////////////////////////////////
   -- Print the available GPU devices
*/
extern "C"
void printout_devices( )
{
	#if 0  // CUDA
	int ndevices;
    	cuDeviceGetCount( &ndevices );
    	for( int idevice = 0; idevice < ndevices; idevice++ ) {
        	char name[200];
		#if CUDA_VERSION > 3010 
        	size_t totalMem;
		#else
       	 	unsigned int totalMem;
		#endif

        	int clock;
        	int major, minor;
        	CUdevice dev;

        	cuDeviceGet( &dev, idevice );
        	cuDeviceGetName( name, sizeof(name), dev );
        	cuDeviceComputeCapability( &major, &minor, dev );
        	cuDeviceTotalMem( &totalMem, dev );
        	cuDeviceGetAttribute( &clock,
                CU_DEVICE_ATTRIBUTE_CLOCK_RATE, dev );
        	printf( "device %d: %s, %.1f MHz clock, %.1f MB memory, capability %d.%d\n",
                	idevice, name, clock/1000.f, totalMem/1024.f/1024.f, major, minor );
    		}
	#endif // CUDA

	uint16_t hostid, *self, *scif_nodes;
	int i, num_nodes = -1;
	hostid = 0;
	self = (unsigned short *)&hostid;
	num_nodes = scif_get_nodeIDs(NULL, 0, self);

	printf("Number of SCIF nodes(including Host): %d\n", num_nodes);

	scif_nodes = (uint16_t *)malloc(sizeof(uint16_t) * num_nodes);
	scif_get_nodeIDs(scif_nodes, num_nodes, self);

	for(i = 0; i < num_nodes; i++) {
	      if(scif_nodes[i] == 0)
	              printf("Card %d ---> HOST\n", i);
	      else
	              printf("Card %d ---> MIC-%d\n", i, scif_nodes[i]);
	}

	free(scif_nodes);			
}


/* ////////////////////////////////////////////////////////////////////////////
   -- Auxiliary function: ipiv(i) indicates that row i has been swapped with 
      ipiv(i) from top to bottom. This function rearranges ipiv into newipiv
      where row i has to be moved to newipiv(i). The new pivoting allows for
      parallel processing vs the original one assumes a specific ordering and
      has to be done sequentially.
*/
extern "C"
void swp2pswp( magma_trans_t trans, magma_int_t n, magma_int_t *ipiv, magma_int_t *newipiv)
{
  magma_int_t i, newind, ind;

  for(i=0; i<n; i++)
    newipiv[i] = -1;
  
  if ( trans == MagmaNoTrans ){
    for(i=0; i<n; i++){
      newind = ipiv[i] - 1;
      if (newipiv[newind] == -1) {
        if (newipiv[i]==-1){
          newipiv[i] = newind;
          if (newind>i)
            newipiv[newind]= i;
        }
        else
          {
            ind = newipiv[i];
            newipiv[i] = newind;
            if (newind>i)
              newipiv[newind]= ind;
          }
      }
      else {
        if (newipiv[i]==-1){
          if (newind>i){
            ind = newipiv[newind];
            newipiv[newind] = i;
            newipiv[i] = ind;
          }
          else
            newipiv[i] = newipiv[newind];
        }
        else{
          ind = newipiv[i];
          newipiv[i] = newipiv[newind];
          if (newind > i)
            newipiv[newind] = ind;
        }
      }
    }
  } else {
    for(i=n-1; i>=0; i--){
      newind = ipiv[i] - 1;
      if (newipiv[newind] == -1) {
        if (newipiv[i]==-1){
          newipiv[i] = newind;
          if (newind>i)
            newipiv[newind]= i;
        }
        else
          {
            ind = newipiv[i];
            newipiv[i] = newind;
            if (newind>i)
              newipiv[newind]= ind;
          }
      }
      else {
        if (newipiv[i]==-1){
          if (newind>i){
            ind = newipiv[newind];
            newipiv[newind] = i;
            newipiv[i] = ind;
          }
          else
            newipiv[i] = newipiv[newind];
        }
        else{
          ind = newipiv[i];
          newipiv[i] = newipiv[newind];
          if (newind > i)
            newipiv[newind] = ind;
        }
      }
    }
  }
}
