Tareas de ejemplo (secuencial y paralela)

Ejemplo 1. Una tarea secuencial en un solo nodo.

  1. Programa de metodo de montecarlo para el calculo de pi (montecarlo.c)
/*
* C program to compute the value of pi using Monte Carlo
*
* Command-line arguments:  number_of_samples, seed
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>   /* has fabs() */
#include <sys/time.h>

/* main program */

unsigned int mysecond()
{
                struct timeval tp;
                struct timezone tzp;
                int i;

                i = gettimeofday(&tp,&tzp);
                return ( (unsigned int) tp.tv_sec + (unsigned int) tp.tv_usec * 1.e-6);
}

int main(int argc, char* argv[]) {

        int num_samples,i;
        int seed;
        double start_time, end_time;
        int count, local_count = 0;
        double x, y;
        double pi = 0.0;
        int nprocs=1;

        /* process command-line arguments */
        if (argc != 2)  {
                fprintf(stderr, "usage:  %s number_of_samples\n", argv[0]);
        exit(1);
        }
        num_samples = atoi(argv[1]);
        seed = mysecond();
        if ((num_samples <= 0) || (seed <= 0)) {
                fprintf(stderr, "usage:  %s number_of_samples\n", argv[0]);
        exit(1);
        }

        /* do calculation */
        srand((unsigned int) seed);
        for (i = 0; i < num_samples; i += nprocs) {
                x = (double) rand() / (double) (RAND_MAX);
                y = (double) rand() / (double) (RAND_MAX);
                if ((x*x + y*y) <= 1.0)
                        ++local_count;
        }
        count=local_count;
                pi = 4.0 * (double) count / (double) num_samples;

                printf("Program results with %d processes:\n", nprocs);
                printf("number of samples = %d, seed = %d\n", num_samples, seed);
                printf("estimated pi = %12.10f\n", pi);
                printf("difference between estimated pi and math.h M_PI = %12.10f\n",fabs(pi - M_PI));
        return EXIT_SUCCESS;
}
  1. Programa de metodo de montecarlo para el calculo de pi (montecarlo.c)
$  icc  monte-carlo-pi.c -o montecarlo-pi
  1. Preparar el programa que se enviara al sistema PBS (montecarlo-pi.pbs)
#!/bin/bash
#PBS -N montecarlo-pi
#PBS -q intel
#PBS -o salidapi.out
#PBS -e salidapi.err

set -x
cd $PBS_O_WORKDIR
date > tiempoINTEL.txt
./montecarlo-pi 10000000000
date >> tiempoINTEL.txt
echo "Finalize"
  1. Ejecutarlo:
$  qsub  montecarlo-pi.pbs
  1. Salida:
$ more salidapi.out
Program results with 1 processes:
number of samples = 1410065408, seed = 1592253525
estimated pi = 3.1415875738
difference between estimated pi and math.h M_PI = 0.0000050798
Finalice

Ejemplo 2. Una tarea paralela usando MPI de intel ejecutandose en 96 cores

a)Programa fuente en C llamada matrix-mpi.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "mpi.h"

#define MatrixSIZE   1000
#define TYPE         float
#define MPITYPE      MPI_FLOAT

#define TAG_MATRIX1  1
#define TAG_MATRIX2  2
#define TAG_RESULT   3

TYPE Matrix1 [MatrixSIZE][MatrixSIZE];
TYPE Matrix2 [MatrixSIZE][MatrixSIZE];
TYPE Result  [MatrixSIZE][MatrixSIZE];

long Rows;

long i;
long Counter = 0;

double start_time;
double end_time;


int my_rank;
int p;
MPI_Status status;

TYPE GetRand()

{
TYPE fl;
int   num1, num2;
fl   = (char) random();
num1 = (int)  random();
num2 = (int)  random();
fl  += (TYPE) num2/num1;
return fl;
}

double GetTime()

{
struct timeval t;
gettimeofday(&t, (struct timezone *) 0);
return (t.tv_sec + ((double) t.tv_usec)/1000000);
}

void FillMatrix()

{
long i, i1;
for (i=0; i<MatrixSIZE; i++)
        {
        srandom( (int) GetTime());
        for (i1=0; i1<MatrixSIZE; i1++)
        {
                Matrix1[i][i1] = GetRand();
                Matrix2[i][i1] = GetRand();
        }
        }
}

void Multiply()

{
long i, i1, i2;

for (i = Rows*my_rank; i < Rows*(my_rank+1); i++)
        {
        for (i1 = 0; i1 < MatrixSIZE; i1++)
        {
                Result[i][i1] = 0;
                for (i2 = 0; i2 < MatrixSIZE; i2++)
                {
                        Result[i][i1] += (Matrix1[i][i2] * Matrix2[i2][i1]);
                }
        }
        }
}

void PrintMatrix(TYPE Matrix[MatrixSIZE][MatrixSIZE])

{
int i, i1;

for (i = 0; i < MatrixSIZE; i++)
        {
        for (i1 = 0; i1 < MatrixSIZE; i1++)
        {
                printf("%f  ", Matrix[i][i1]);
        }
        printf("\n");
        }
}

int main(int argc, char ** argv)


{
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);

if (my_rank == 0)
        {
        printf("Running on %d processors...\n", p);
        FillMatrix();
        printf("Finished Filling Matrix...\n");
        for (i = 1; i < p; i++)
        {
                MPI_Send(&Matrix1, MatrixSIZE*MatrixSIZE, MPITYPE, i, TAG_MATRIX1,
                                MPI_COMM_WORLD);
                MPI_Send(&Matrix2, MatrixSIZE*MatrixSIZE, MPITYPE, i, TAG_MATRIX2,
                                MPI_COMM_WORLD);
        }
        start_time = MPI_Wtime();
        }
else
        {
        MPI_Recv(&Matrix1, MatrixSIZE*MatrixSIZE, MPITYPE, 0, TAG_MATRIX1,
                                MPI_COMM_WORLD, &status);
        MPI_Recv(&Matrix2, MatrixSIZE*MatrixSIZE, MPITYPE, 0, TAG_MATRIX2,
                                MPI_COMM_WORLD, &status);
        }

Rows = MatrixSIZE/p;
Multiply();
MPI_Barrier(MPI_COMM_WORLD);
if (my_rank == 0)
        {
        end_time = MPI_Wtime();
        Counter = MatrixSIZE*MatrixSIZE*MatrixSIZE;
        printf("\nElapsed Time : %f, Ops : %d, MFLops : %f\n",
                        end_time-start_time, Counter, Counter/((end_time-start_time)*100000
0));
        for (i = 1; i < p; i++)
        {
                MPI_Recv(&Result[Rows*i][0], Rows*MatrixSIZE, MPITYPE, i,
                                TAG_RESULT, MPI_COMM_WORLD, &status);
        }
        }
else
        {
        MPI_Send(&Result[Rows*my_rank][0], Rows*MatrixSIZE, MPITYPE, 0,
                        TAG_RESULT, MPI_COMM_WORLD);
        }
MPI_Finalize();
}
  1. Compilacion del programa matrix-mpi.c
mpiicc matrix-mpi.c -o matrix-mpi
  1. Realizacion del script en PBS con las directivas enviarse al sistema de colas.
#!/bin/bash
#PBS -N matrix-mpi_8x12
#PBS -l nodes=8:ppn=12
#PBS -q intel
#PBS -o pi.log
#PBS -e pi.error

cd $PBS_O_WORKDIR
sort -u $PBS_NODEFILE > nodes.file
mpirun -ppn $PBS_NUM_PPN -n $PBS_NP ./matrix-mpi >out.mpi
  1. Ejecucion:
qsub matrix-mpi.pbs
  1. El resultado.
$ more out.mpi
Running on 96 processors...
Finished Filling Matrix...
Elapsed Time : 0.002329, Ops : 1000000000, MFLops : 429348.346811

Python

Programas en python pueden ser enviados como tareas por lotes al cluster.

Como ejemplo el siguiente codigo en python. interpol1D.py

import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from scipy import interpolate

x = np.linspace(0, 10, num=10, endpoint=True)
y = np.cos(-x**2/9.0)

f = interpolate.interp1d(x, y)

f2 = interpolate.interp1d(x, y, kind='cubic')


xnew = np.linspace(0, 10, num=200, endpoint=True)

tck = interpolate.splrep(x, y, s=0)
f3 = interpolate.splev(xnew, tck , der=0)

plt.plot(x, y, 'o', xnew, f(xnew), '-', xnew, f2(xnew), '--', xnew, f3)
plt.title('Intepolacion 1D - metodos')
plt.legend(['data', 'linear', 'cubic','Cubic Spline'], loc='best')
plt.savefig('interpol1D.png', dpi=250, format='png')

Preparamos el script para enviar la tarea al manejador de recursos:

#!/bin/bash
#PBS -N pythonjob
#PBS -q intel
#PBS -l nodes=1
#PBS -j oe

set -x
cd $PBS_O_WORKDIR

echo Inicio: `date` > tiempo.log
start=`date +%s`

python interpol1D.py

echo Final : `date` >> tiempo.log
end=`date +%s`
echo Tiempo ejecución : $((end-start)) seg. >> tiempo.log

Para ejecutar la tarea escribimos:

$ qsub submitjob.sh

El resultado de la operación correcta de esta tarea debe producir tres archivos, una imagen png interpol1D.png un archivo tiempo.log y submitjob.o#### siendo #### el numero del JobID que nos asigno el manejador de tareas.