Инженерная методика адаптации приложения к гибридному кластеру с ускорителями на ПЛИС

Часть 2. Выбор модельного приложения.

С. С. Андреев, С. А. Дбар, А. О. Лацис, Е. А. Плоткина

Модельное приложение выберем то же самое, что в «Десяти простых шагах». Приведем здесь несколько модифицированную выдержку из Шага 3:

Выберем в качестве модельного приложения решение сеточного аналога двумерной задачи Дирихле для уравнения Пуассона на прямоугольной равномерной индексной сетке итерационным методом Якоби, без контроля невязки, то есть с заданием фиксированного числа итераций. Ниже приводится текст программы, реализующей этот расчет в последовательном режиме на универсальном процессоре.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dimension.h"
// Change here the number of steps, the cell geometry, etc
#define NITER 5000
#define STEPITER 1000
#define delx 0.5
#define dely 0.25
// end change here.
       int main( int argc, char **argv )
{
       int i, j, n, mx1, my1, mx, my;
       FILE *fp;
       double rdx2, rdy2, beta;
/***/
       if ( argc != 3 )
        {
         fprintf( stderr, "Usage: %s <nrows> <ncolumns>\n", argv[0] );
         return (-1);
        }
       mx = (int)atol( argv[1] );
       my = (int)atol( argv[2] );
       mx += 2;
       my += 2;
/* Here we know the array sizes, so make the arrays themselves: */
       {
        DIM2( double, f, my );
        DIM2( double, newf, my );
        DIM2( double, r, my );
        void *tmpf;
/***/
        f = (typeof(f))malloc( mx*sizeof(*f) );
          newf = (typeof(newf))malloc( mx*sizeof(*f) );
        r = (typeof(r))malloc( mx*sizeof(*r) );
        if ( (!f) || (!newf) || (!r) )
         {
          fprintf( stderr, "Cannot allocate, exiting\n" );
          return( -1 );
         }
        rdx2 = 1./delx/delx;
        rdy2 = 1./dely/dely;
        beta = 1.0/(2.0*(rdx2+rdy2)); 
        printf( "Solving task on %d by %d grid\n", mx-2, my-2 );     
        fflush( stdout );
        for ( i = 0; i < mx; i++ )
         {
          for ( j = 0; j < my; j++ )
           {
            if ( (i==0) || (j==0) || (i==(mx-1)) || (j==(my-1)) )
             newf[i][j] = f[i][j] = 1.0;
            else
             newf[i][j] = f[i][j] = 0.0;
            r[i][j] = 0.0;        
           }
         }    
        mx1 = mx - 1;
        my1 = my - 1; 
/* Iteration loop: */
        for ( n = 0; n < NITER; n++ )
         {
           if ( !(n%STEPITER) ) printf( "Iteration %d\n", n );
/* Step of calculation starts here: */
           for ( i = 1; i < mx1; i++ )
            {
             for ( j = 1; j < my1; j++ )
              {
               newf[i][j] = ((f[i-1][j]+f[i+1][j])*rdx2
                       +(f[i][j-1]+f[i][j+1])*rdy2-r[i][j])*beta;
              }
            }
/* swap the halves: */
	      tmpf = newf;      
          newf = f;
	     f = (typeof(f))tmpf;
         }    
        fp = fopen("output_seq.dat", "w" );
        for ( i = 1; i < (mx-1); i++ )
         {
          fwrite( &(f[i][1]), my-2, sizeof(f[0][0]), fp );
         } 
       fclose( fp );    
       }     
       return 0;
}

Несколько кратких пояснений.

Температура нормализована к диапазону от 0.0 до 1.0. Уравнение решается с правой частью, представленной массивом r, который в данном расчете заполняется нулями, но в пересчете значений температуры, тем не менее, участвует.

Имеются два указателя, f и newf, которые указывают на два разных массива значений температуры, меняясь ролями на каждой итерации (если на текущей итерации f указывает на первый массив значений температуры, а newf – на второй, то на следующей итерации будет наоборот). При этом тот массив значений температуры, на которую на данной итерации указывает f, играет роль «старых» значений, а тот, на которую указывает newf, роль «новых».

В остальном программа вполне тривиальна. Отныне она является для нас руководством к действию. Естественно, мы будем стремиться к параллельной, а затем — и гибридно-параллельной, реализации в точности тех вычислений, которые представлены приведенной выше последовательной программой.

◄ Часть 1 Часть 3 ►
 
 
 
 
 
 
 
 
  Тел. +7(499)220-79-72; E-mail: inform@kiam.ru