From 7487290ceab7d6a8d5dd5e8bb6750947a10ccd8c Mon Sep 17 00:00:00 2001 From: redf1sh Date: Sat, 3 Oct 2020 21:35:46 +0300 Subject: [PATCH 1/9] Added solution for second openMP task --- OpenMP2/src/main.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/OpenMP2/src/main.cpp b/OpenMP2/src/main.cpp index 8dab215..8130cbf 100644 --- a/OpenMP2/src/main.cpp +++ b/OpenMP2/src/main.cpp @@ -3,9 +3,67 @@ #include #include +double calc3(uint32_t x_last, uint32_t num_threads) +{ + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + double res = 0.0; + uint32_t i; + + double* res_buffer = (double*)calloc(x_last, sizeof(double)); + + #pragma omp parallel for num_threads( num_threads) + for( i = x_last; i > 0; i--) + { + res_buffer[ i - 1] = 1.0 / i; + } + + for ( i = x_last; i > 0; i--) + res += res_buffer[ i - 1]; + + return res; +} + + +double calc2(uint32_t x_last, uint32_t num_threads) +{ + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + double res = 0.0; + uint32_t i; + + #pragma omp parallel for reduction(+:res) num_threads( num_threads) + for( i = x_last; i > 0; i--) + { + res += 1.0 / i; + } + + return res; +} + + double calc(uint32_t x_last, uint32_t num_threads) { - return 0; + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + double res = 0.0; + uint32_t i; + + double* res_buffer = (double*)calloc(num_threads, sizeof(double)); + + #pragma omp parallel for num_threads( num_threads) + for( i = x_last; i > 0; i--) + { + res_buffer[ omp_get_thread_num()] += 1.0 / i; + } + + for (int i = num_threads; i >= 0; i--) + res += res_buffer[ i]; + + return res; } int main(int argc, char** argv) @@ -38,7 +96,7 @@ int main(int argc, char** argv) uint32_t x_last = 0, num_threads = 0; input >> x_last >> num_threads; // Calculation - double res = calc(x_last, num_threads); + double res = calc3(x_last, num_threads); // Write result output << std::setprecision(15) << res << std::endl; From 85dc91fec3ee4b37ca38ee8470c7071320b41fb5 Mon Sep 17 00:00:00 2001 From: redf1sh Date: Fri, 9 Oct 2020 02:02:38 +0300 Subject: [PATCH 2/9] Added solution for third openMP task --- OpenMP3/src/main.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/OpenMP3/src/main.cpp b/OpenMP3/src/main.cpp index 416ee06..e64b96e 100644 --- a/OpenMP3/src/main.cpp +++ b/OpenMP3/src/main.cpp @@ -9,9 +9,71 @@ double func(double x) return sin(x); } +double calc_reduce(double x0, double x1, double dx, uint32_t num_threads) +{ + + if ( x1 == x0) + return 0; + + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + int count = ( int)floor( ( x1 - x0) / dx); + double res = 0.0; + + + /* Подсчет 2 "хвостиков" */ + res += ( func( x0) + func( count)) * dx / 2; + + /* sum = [f(0) + f(x1)] * dx / 2 + (f(1) + f(2) + ... + f(x1-1)) * dx */ + /* Основной ход метода трапеций */ + #pragma for reduce(+:res) num_threads( num_threads) + for ( int i = 1; i <= count; i++) + { + res += func( i * dx); + } + + res *= dx; + res += + (func( dx * ( count - 1)) + func( x1))/2 * ( (x1 - x0) - (dx * ( count - 1))); + + + return res; +} + + double calc(double x0, double x1, double dx, uint32_t num_threads) { - return 0; + + if ( x1 == x0) + return 0; + + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + int count = ( int)floor( ( x1 - x0) / dx); + double* res_buffer = ( double*)calloc( ( count + 1), sizeof( double)); + double res = 0.0; + + /* sum = [f(0) + f(x1)] * dx / 2 + (f(1) + f(2) + ... + f(x1-1)) * dx */ + /* Основной ход метода трапеций */ + #pragma omp parallel for num_threads( num_threads) + for ( int i = 0; i <= count; i++) + { + res_buffer[i] = func( i * dx); + } + + + /* Сложение результатов */ + for( int i = 1; i < count; i++) + res += res_buffer[i]; + + res *= dx; + + /* Подсчет 2 "хвостиков" */ + res += (res_buffer[0] + res_buffer[count]) * dx / 2 + + ( func( dx * ( count - 1)) + func( x1))/2 * ( (x1 - x0) - (dx * ( count - 1))); + + return res; } int main(int argc, char** argv) From 123eb8dc818846b4a478a10a72fb7d9752c1be5e Mon Sep 17 00:00:00 2001 From: redf1sh Date: Fri, 16 Oct 2020 22:45:04 +0300 Subject: [PATCH 3/9] Added solution for OpenMP4 and game 'Life' --- OpenMP4/src/main.cpp | 70 +++++++++++++++++++- OpenMP5/src/main.cpp | 152 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 218 insertions(+), 4 deletions(-) diff --git a/OpenMP4/src/main.cpp b/OpenMP4/src/main.cpp index 036d8e3..7f87d13 100644 --- a/OpenMP4/src/main.cpp +++ b/OpenMP4/src/main.cpp @@ -2,10 +2,78 @@ #include #include #include +#include + +void fact(int n){ + int i; + mpz_t p; + + mpz_init_set_ui(p,1); /* p = 1 */ + + for (i=1; i <= n ; ++i){ + mpz_mul_ui(p,p,i); /* p = p * i */ + } + printf ("%d! = ", n); + +} + +#if 0 +/** + * Осуществляет принцип "разделяй и властвуй", где превращает список множителей в бинарное дерево + * и перемножает их по 2. + * + * Рекурсивный алгоритм. + */ +double pod_tree_rec( int l, int r) +{ + if( l > r) + return 1; + + if( l == r) + return l; + + if( ( r - l) == 1) + return (double)(l * r); + + int m = (l + r) / 2; + + return (pod_tree_rec( l, m) * pod_tree_rec( m + 1, r)); +} + +double tree_factorial( int n) +{ + if ( ( n == 0)) + return 1; + + if ( ( n == 2) || ( n == 1)) + return n; + + return ( pod_tree_rec( 2, n)); +} + +#endif double calc(uint32_t x_last, uint32_t num_threads) { - return 0; + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + //double res = 1.0; + mpz_t res; + double *factorial_array = (double*)calloc( x_last + 1, sizeof(double)); + factorial_array[0] = 1; + + #pragma omp parallel for num_threads( num_threads) + for( uint32_t i = 1; i < x_last; i++) + factorial_array[i] = tree_factorial( i); + + #pragma omp parallel for reduction(+:res) num_threads( num_threads) + for( uint32_t i = 1; i < x_last - 1; i++) + { + res += 1.0 / factorial_array[i]; + } + + return res; } int main(int argc, char** argv) diff --git a/OpenMP5/src/main.cpp b/OpenMP5/src/main.cpp index 607b3e2..54181d4 100644 --- a/OpenMP5/src/main.cpp +++ b/OpenMP5/src/main.cpp @@ -3,9 +3,153 @@ #include #include -void calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_threads, uint8_t* inputFrame, uint8_t* outputFrame) +#define DEAD '0' +#define ALIVE '1' + +/** + * Конвертирует массив в 2D для более удобной работы + * + * WARNING Массив удаляется из вызывающей функции + */ +uint8_t** ConvertFrom1Dto2D( uint32_t xSize, uint32_t ySize, uint8_t* input_frame) +{ + uint8_t** temp_frame = (uint8_t**)calloc( ySize, sizeof(uint8_t*)); + for ( uint32_t i = 0; i < xSize; i++) + { + temp_frame[i] = (uint8_t*)calloc( ySize, sizeof(uint8_t)); + } + + /* x - столбцы, y - строки */ + for ( uint32_t i = 0; i < ySize; i++) + for ( uint32_t j = 0; j < xSize; j++) + temp_frame[i][j] = input_frame[i * ySize + j]; + return ( temp_frame); +} + +/** + * Переводит матрицу в линейный массив + */ +uint8_t* ConvertFrom2Dto1D( uint32_t xSize, uint32_t ySize, uint8_t** input_frame) +{ + + uint8_t* temp_frame = (uint8_t*)calloc( ySize * xSize, sizeof(uint8_t)); + + for ( uint32_t i = 0; i < ySize; i++) + for( uint32_t j = 0; j < xSize; j++) + temp_frame[i * xSize + j] = input_frame[i][j]; + + return ( temp_frame); +} + +/** + * Вычисляет количество соседей возле указанной точки (x, y) + */ +int NumOfNeighbours( uint32_t xSize, uint32_t ySize, uint32_t x, uint32_t y, uint8_t** input_frame) { + int neighbours_num = 0; + xSize--; + ySize--; + /* Необходимо вокруг посмотреть 8 клеток, если там, кто-то есть, то количество соседей увеличиваем на 1 */ + + /* Левый верхний угол */ + if ( ( x >= 1) && ( y >= 1)) + if ( input_frame[x - 1][y - 1] == ALIVE) + neighbours_num++; + + /* Верхний средний */ + if ( x >= 1) + if ( input_frame[x - 1][y] == ALIVE) + neighbours_num++; + + /* Правый сверху */ + if ( ( x >= 1) && ( y <= ( ySize - 1))) + if ( input_frame[x - 1][y + 1] == ALIVE) + neighbours_num++; + + /* Слева средний */ + if ( y >= 1) + if ( input_frame[x][y - 1] == ALIVE) + neighbours_num++; + + /* Справа средний */ + if ( y <= ( ySize - 1)) + if ( input_frame[x][y + 1] == ALIVE) + neighbours_num++; + /* Слева нижний */ + if ( ( x <= ( xSize - 1)) && ( y >= 1)) + if ( input_frame[x + 1][y - 1] == ALIVE) + neighbours_num++; + + /* Нижний средний */ + if ( x <= ( xSize - 1)) + if ( input_frame[x + 1][y] == ALIVE) + neighbours_num++; + + /* Справа нижний */ + if ( ( y <= ( ySize - 1)) && ( x <= (xSize - 1))) + if ( input_frame[x + 1][y + 1] == ALIVE) + neighbours_num++; + + return ( neighbours_num); +} + + +uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_threads, uint8_t* inputFrame) +{ + if (iterations == 0) + { + return inputFrame; + } + + + omp_set_dynamic( 0); + omp_set_num_threads( num_threads); + + /* Для каждой ячейки необходимо проверить соседние и посчитать количество соседей */ + uint8_t** temp_frame = ConvertFrom1Dto2D( xSize, ySize, inputFrame); + + uint8_t** result_frame = (uint8_t**)calloc( xSize, sizeof(uint8_t*)); + for ( uint32_t i = 0; i < xSize; i++) + { + result_frame[i] = (uint8_t*)calloc( ySize, sizeof(uint8_t)); + } + + //#pragma omp parallel for num_threads( num_threads) + for ( uint32_t k = 0; k < iterations; k++) + { + for ( uint32_t i = 0; i < xSize; i++) + { + for ( uint32_t j = 0; j < ySize; j++) + { + /* В пустой клетке, рядом с которой есть ровно 3 соседа, зарождается жизнь */ + if ( ( NumOfNeighbours( xSize, ySize, i, j, temp_frame) == 3) && (temp_frame[i][j] == DEAD)) + result_frame[i][j] = ALIVE; + else + /* Если у живой клетки 2 или 3 соседа, то она продолжает жить */ + if ( ( ( NumOfNeighbours( xSize, ySize, i, j, temp_frame) == 2) || ( NumOfNeighbours( xSize, ySize, i, j, temp_frame) == 3)) && (temp_frame[i][j] == ALIVE)) + result_frame[i][j] = ALIVE; + else + result_frame[i][j] = DEAD; + } + } + + temp_frame = result_frame; + } + + + return ( ConvertFrom2Dto1D( xSize, ySize, result_frame)); + +/* + for ( uint32_t i = 0; i < xSize; i++) + { + free( temp_frame[i]); + free( result_frame[i]); + } + + free( temp_frame); + free( result_frame); + */ } int main(int argc, char** argv) @@ -47,8 +191,9 @@ int main(int argc, char** argv) } } + // Calculation - calc(xSize, ySize, iterations, num_threads, inputFrame, outputFrame); + outputFrame = calc(xSize, ySize, iterations, num_threads, inputFrame); // Write result for (uint32_t y = 0; y < ySize; y++) @@ -59,10 +204,11 @@ int main(int argc, char** argv) } output << "\n"; } - +#if 0 // Prepare to exit delete outputFrame; delete inputFrame; +#endif output.close(); input.close(); return 0; From c9447ae3819df2c35a442ee04e6509aecb7697c0 Mon Sep 17 00:00:00 2001 From: redf1sh Date: Thu, 22 Oct 2020 20:59:57 +0300 Subject: [PATCH 4/9] Added solutions for 4th and 5th openMP task --- OpenMP4/src/main.cpp | 77 ++++------------ OpenMP5/src/main.cpp | 207 ++++++++++++++++++++++++++++--------------- 2 files changed, 154 insertions(+), 130 deletions(-) diff --git a/OpenMP4/src/main.cpp b/OpenMP4/src/main.cpp index 7f87d13..386128a 100644 --- a/OpenMP4/src/main.cpp +++ b/OpenMP4/src/main.cpp @@ -5,74 +5,29 @@ #include -void fact(int n){ - int i; - mpz_t p; - mpz_init_set_ui(p,1); /* p = 1 */ - - for (i=1; i <= n ; ++i){ - mpz_mul_ui(p,p,i); /* p = p * i */ - } - printf ("%d! = ", n); - -} - -#if 0 -/** - * Осуществляет принцип "разделяй и властвуй", где превращает список множителей в бинарное дерево - * и перемножает их по 2. - * - * Рекурсивный алгоритм. - */ -double pod_tree_rec( int l, int r) -{ - if( l > r) - return 1; - - if( l == r) - return l; - - if( ( r - l) == 1) - return (double)(l * r); - - int m = (l + r) / 2; - - return (pod_tree_rec( l, m) * pod_tree_rec( m + 1, r)); -} - -double tree_factorial( int n) +double fact_calculate( int i) { - if ( ( n == 0)) - return 1; - - if ( ( n == 2) || ( n == 1)) - return n; - - return ( pod_tree_rec( 2, n)); + static double res = 1.0; + res *= i; + return ( res); } +double calc(uint32_t x_last, uint32_t num_threads) { + double *factorials = (double *) calloc(x_last, sizeof(double)); -#endif -double calc(uint32_t x_last, uint32_t num_threads) -{ - omp_set_dynamic( 0); - omp_set_num_threads( num_threads); - - //double res = 1.0; - mpz_t res; - double *factorial_array = (double*)calloc( x_last + 1, sizeof(double)); - factorial_array[0] = 1; - - #pragma omp parallel for num_threads( num_threads) - for( uint32_t i = 1; i < x_last; i++) - factorial_array[i] = tree_factorial( i); + factorials[0] = 1; + for (int i = 1; i <= (int)x_last; i++) { + factorials[i] = fact_calculate( i); + } - #pragma omp parallel for reduction(+:res) num_threads( num_threads) - for( uint32_t i = 1; i < x_last - 1; i++) + double res = 0; + #pragma omp parallel for num_threads(num_threads) reduction(+:res) + for (int i = (int)(x_last - 1); i >= 0; i--) { - res += 1.0 / factorial_array[i]; + res += 1 / factorials[i]; } - + + free( factorials); return res; } diff --git a/OpenMP5/src/main.cpp b/OpenMP5/src/main.cpp index 6cfd948..da81ad9 100644 --- a/OpenMP5/src/main.cpp +++ b/OpenMP5/src/main.cpp @@ -3,8 +3,69 @@ #include #include -#define DEAD '0' -#define ALIVE '1' +/* Константы для игрового поля */ +#define DEAD 0 +#define ALIVE 1 + +/* Флаги для включения и отключения функций */ +#define ENABLED 1 +#define DISABLED 0 + +/* Включение режима отладочной печати */ +#define DEBUG_PRINT_INIT DISABLED + +/* Макрос отладочной печати */ +#define DEBUG_PRINT( sequence) do{ if( DEBUG_PRINT_INIT) (sequence);} while(0); + +/* Распространненый цикл */ +#define FOR_ALL_ARRAY\ + for ( uint32_t i = 0; i < xSize; i++)\ + for( uint32_t j = 0; j < ySize; j++)\ + +/* Заполнение массива 0 */ +#define SET_ARRAY_ZERO( array)\ + FOR_ALL_ARRAY\ + ( array)[i][j] = 0; + +/* Копирование одного массива в другой */ +#define COPY_ARRAY( src, dst)\ + FOR_ALL_ARRAY\ + ( dst)[i][j] = ( src)[i][j]; + +/** + * Выполняет циклический сдвиг по координатам. + * + * Функция void, так как нам необходимо вернуть 2 значения. + */ +void CycleShift( uint32_t xSize_t, uint32_t ySize_t, int* x, int* y) +{ + int xSize = xSize_t; + int ySize = ySize_t; + + /* Если x за пределами поля, тогда выполняем циклический сдвиг по x*/ + if ( !( ( *x <= xSize) && ( *x >= 0))) + { + if ( *x < 0) + *x = xSize; + else + if ( *x >= xSize) + *x = 0; + } + + /* Если y за пределами поля, тогда выполняем циклический сдвиг по y */ + if( !(( *y <= ySize) && ( *y >= 0))) + { + if ( *y < 0) + *y = ySize; + else + if ( *y >= ySize) + *y = 0; + + } + + /* Иначе выполняем циклический сдвиг в зависимости от того, на сколько отличаются координаты от границы */ + + } /** * Конвертирует массив в 2D для более удобной работы @@ -13,7 +74,7 @@ */ uint8_t** ConvertFrom1Dto2D( uint32_t xSize, uint32_t ySize, uint8_t* input_frame) { - uint8_t** temp_frame = (uint8_t**)calloc( ySize, sizeof(uint8_t*)); + uint8_t** temp_frame = (uint8_t**)calloc( xSize, sizeof(uint8_t*)); for ( uint32_t i = 0; i < xSize; i++) { temp_frame[i] = (uint8_t*)calloc( ySize, sizeof(uint8_t)); @@ -26,6 +87,23 @@ uint8_t** ConvertFrom1Dto2D( uint32_t xSize, uint32_t ySize, uint8_t* input_fram return ( temp_frame); } +/** + * Функция для отладки. Рисует промежуточный результат + */ +void DrawField( uint32_t xSize, uint32_t ySize, uint8_t** field) +{ + printf("\n"); + for ( uint32_t i = 0; i < xSize; i++) + { + for ( uint32_t j = 0; j < ySize; j++) + { + printf("%d ", field[i][j]); + } + printf("\n"); + } + printf("\n"); +} + /** * Переводит матрицу в линейный массив */ @@ -47,66 +125,40 @@ uint8_t* ConvertFrom2Dto1D( uint32_t xSize, uint32_t ySize, uint8_t** input_fram int NumOfNeighbours( uint32_t xSize, uint32_t ySize, uint32_t x, uint32_t y, uint8_t** input_frame) { int neighbours_num = 0; + xSize--; ySize--; + /* Необходимо вокруг посмотреть 8 клеток, если там, кто-то есть, то количество соседей увеличиваем на 1 */ + for ( int i = -1; i <= 1; i++) + { + for ( int j = -1; j <= 1; j++) + { + int x_shifted = x + i, + y_shifted = y + j; - /* Левый верхний угол */ - if ( ( x >= 1) && ( y >= 1)) - if ( input_frame[x - 1][y - 1] == ALIVE) - neighbours_num++; - - /* Верхний средний */ - if ( x >= 1) - if ( input_frame[x - 1][y] == ALIVE) - neighbours_num++; - - /* Правый сверху */ - if ( ( x >= 1) && ( y <= ( ySize - 1))) - if ( input_frame[x - 1][y + 1] == ALIVE) - neighbours_num++; - - /* Слева средний */ - if ( y >= 1) - if ( input_frame[x][y - 1] == ALIVE) - neighbours_num++; - - /* Справа средний */ - if ( y <= ( ySize - 1)) - if ( input_frame[x][y + 1] == ALIVE) - neighbours_num++; - - /* Слева нижний */ - if ( ( x <= ( xSize - 1)) && ( y >= 1)) - if ( input_frame[x + 1][y - 1] == ALIVE) - neighbours_num++; - - /* Нижний средний */ - if ( x <= ( xSize - 1)) - if ( input_frame[x + 1][y] == ALIVE) - neighbours_num++; - - /* Справа нижний */ - if ( ( y <= ( ySize - 1)) && ( x <= (xSize - 1))) - if ( input_frame[x + 1][y + 1] == ALIVE) - neighbours_num++; + CycleShift( xSize, ySize, &x_shifted, &y_shifted); + if ( !( ( i == 0) && ( j == 0))) + { + if ( ( input_frame[x_shifted][y_shifted] == ALIVE)) + { + neighbours_num++; + DEBUG_PRINT( printf("\t [%d, %d] -> [%d, %d]\n", i, j, x_shifted, y_shifted)) + } + } + } + } + return ( neighbours_num); } uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_threads, uint8_t* inputFrame) { - if (iterations == 0) - { - return inputFrame; - } - - omp_set_dynamic( 0); omp_set_num_threads( num_threads); - /* Для каждой ячейки необходимо проверить соседние и посчитать количество соседей */ uint8_t** temp_frame = ConvertFrom1Dto2D( xSize, ySize, inputFrame); uint8_t** result_frame = (uint8_t**)calloc( xSize, sizeof(uint8_t*)); @@ -115,30 +167,47 @@ uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_ result_frame[i] = (uint8_t*)calloc( ySize, sizeof(uint8_t)); } - //#pragma omp parallel for num_threads( num_threads) - for ( uint32_t k = 0; k < iterations; k++) + if( iterations == 0) + result_frame = temp_frame; + else { - for ( uint32_t i = 0; i < xSize; i++) + /* Для каждой ячейки необходимо проверить соседние и посчитать количество соседей */ + for ( uint32_t k = 0; k < iterations; k++) { - for ( uint32_t j = 0; j < ySize; j++) + DEBUG_PRINT( printf("Iteration: %d\n", k)) + + #pragma omp parallel for num_threads( num_threads) + for ( uint32_t i = 0; i < xSize; i++) { - /* В пустой клетке, рядом с которой есть ровно 3 соседа, зарождается жизнь */ - if ( ( NumOfNeighbours( xSize, ySize, i, j, temp_frame) == 3) && (temp_frame[i][j] == DEAD)) - result_frame[i][j] = ALIVE; - else - /* Если у живой клетки 2 или 3 соседа, то она продолжает жить */ - if ( ( ( NumOfNeighbours( xSize, ySize, i, j, temp_frame) == 2) || ( NumOfNeighbours( xSize, ySize, i, j, temp_frame) == 3)) && (temp_frame[i][j] == ALIVE)) - result_frame[i][j] = ALIVE; - else - result_frame[i][j] = DEAD; + #pragma omp parallel for num_threads( num_threads) + for ( uint32_t j = 0; j < ySize; j++) + { + int neighbour_num = NumOfNeighbours( xSize, ySize, i, j, temp_frame); + + DEBUG_PRINT( printf( "neighbour num: %d [%d, %d]\n", neighbour_num, i ,j)) + /* В пустой клетке, рядом с которой есть ровно 3 соседа, зарождается жизнь */ + if ( ( neighbour_num == 3) && (temp_frame[i][j] == DEAD)) + result_frame[i][j] = ALIVE; + else + /* Если у живой клетки 2 или 3 соседа, то она продолжает жить */ + if ( ( ( neighbour_num == 2) || ( neighbour_num == 3)) && (temp_frame[i][j] == ALIVE)) + result_frame[i][j] = ALIVE; + else + result_frame[i][j] = DEAD; + } } + + DEBUG_PRINT( DrawField( xSize, ySize, result_frame)) + #pragma omp parallel for num_threads( num_threads) + COPY_ARRAY( result_frame, temp_frame); + #pragma omp parallel for num_threads( num_threads) + SET_ARRAY_ZERO( result_frame); + DEBUG_PRINT( DrawField( xSize, ySize, temp_frame)) } - temp_frame = result_frame; - } - - return ( ConvertFrom2Dto1D( xSize, ySize, result_frame)); + } + return ( ConvertFrom2Dto1D( xSize, ySize, temp_frame)); /* for ( uint32_t i = 0; i < xSize; i++) @@ -149,7 +218,7 @@ uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_ free( temp_frame); free( result_frame); - */ +*/ } int main(int argc, char** argv) @@ -206,11 +275,11 @@ int main(int argc, char** argv) } output << "\n"; } -#if 0 + // Prepare to exit delete outputFrame; delete inputFrame; -#endif + output.close(); input.close(); return 0; From 58ca5bfa7a2cb815c8a53800a6738f3aa53de2ab Mon Sep 17 00:00:00 2001 From: redf1sh Date: Fri, 30 Oct 2020 19:27:27 +0300 Subject: [PATCH 5/9] Fixed memory leaks in the 5th problem --- OpenMP5/src/main.cpp | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/OpenMP5/src/main.cpp b/OpenMP5/src/main.cpp index da81ad9..9282277 100644 --- a/OpenMP5/src/main.cpp +++ b/OpenMP5/src/main.cpp @@ -107,16 +107,12 @@ void DrawField( uint32_t xSize, uint32_t ySize, uint8_t** field) /** * Переводит матрицу в линейный массив */ -uint8_t* ConvertFrom2Dto1D( uint32_t xSize, uint32_t ySize, uint8_t** input_frame) +inline void ConvertFrom2Dto1D( uint32_t xSize, uint32_t ySize, uint8_t** input_frame, uint8_t* output_frame) { - uint8_t* temp_frame = (uint8_t*)calloc( ySize * xSize, sizeof(uint8_t)); - for ( uint32_t i = 0; i < ySize; i++) for( uint32_t j = 0; j < xSize; j++) - temp_frame[i * xSize + j] = input_frame[i][j]; - - return ( temp_frame); + output_frame[i * xSize + j] = input_frame[i][j]; } /** @@ -143,7 +139,6 @@ int NumOfNeighbours( uint32_t xSize, uint32_t ySize, uint32_t x, uint32_t y, uin if ( ( input_frame[x_shifted][y_shifted] == ALIVE)) { neighbours_num++; - DEBUG_PRINT( printf("\t [%d, %d] -> [%d, %d]\n", i, j, x_shifted, y_shifted)) } } } @@ -154,7 +149,7 @@ int NumOfNeighbours( uint32_t xSize, uint32_t ySize, uint32_t x, uint32_t y, uin } -uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_threads, uint8_t* inputFrame) +void calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_threads, uint8_t* inputFrame, uint8_t* outputFrame) { omp_set_dynamic( 0); omp_set_num_threads( num_threads); @@ -167,15 +162,9 @@ uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_ result_frame[i] = (uint8_t*)calloc( ySize, sizeof(uint8_t)); } - if( iterations == 0) - result_frame = temp_frame; - else - { - /* Для каждой ячейки необходимо проверить соседние и посчитать количество соседей */ - for ( uint32_t k = 0; k < iterations; k++) - { - DEBUG_PRINT( printf("Iteration: %d\n", k)) - + /* Для каждой ячейки необходимо проверить соседние и посчитать количество соседей */ + for ( uint32_t k = 0; k < iterations; k++) + { #pragma omp parallel for num_threads( num_threads) for ( uint32_t i = 0; i < xSize; i++) { @@ -184,8 +173,7 @@ uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_ { int neighbour_num = NumOfNeighbours( xSize, ySize, i, j, temp_frame); - DEBUG_PRINT( printf( "neighbour num: %d [%d, %d]\n", neighbour_num, i ,j)) - /* В пустой клетке, рядом с которой есть ровно 3 соседа, зарождается жизнь */ + /* В пустой клетке, рядом с которой есть ровно 3 соседа, зарождается жизнь */ if ( ( neighbour_num == 3) && (temp_frame[i][j] == DEAD)) result_frame[i][j] = ALIVE; else @@ -196,20 +184,15 @@ uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_ result_frame[i][j] = DEAD; } } - - DEBUG_PRINT( DrawField( xSize, ySize, result_frame)) + #pragma omp parallel for num_threads( num_threads) COPY_ARRAY( result_frame, temp_frame); - #pragma omp parallel for num_threads( num_threads) - SET_ARRAY_ZERO( result_frame); - DEBUG_PRINT( DrawField( xSize, ySize, temp_frame)) } - } - return ( ConvertFrom2Dto1D( xSize, ySize, temp_frame)); - -/* + ConvertFrom2Dto1D( xSize, ySize, temp_frame, outputFrame); + + #pragma omp parallel for num_threads( num_threads) for ( uint32_t i = 0; i < xSize; i++) { free( temp_frame[i]); @@ -218,7 +201,7 @@ uint8_t* calc(uint32_t xSize, uint32_t ySize, uint32_t iterations, uint32_t num_ free( temp_frame); free( result_frame); -*/ + } int main(int argc, char** argv) @@ -263,7 +246,7 @@ int main(int argc, char** argv) // Calculation - outputFrame = calc(xSize, ySize, iterations, num_threads, inputFrame); + calc(xSize, ySize, iterations, num_threads, inputFrame, outputFrame); // Write result for (uint32_t y = 0; y < ySize; y++) From 720129abdeea08c42e38c13d6725381cfd9ef989 Mon Sep 17 00:00:00 2001 From: redf1sh Date: Thu, 5 Nov 2020 02:55:12 +0300 Subject: [PATCH 6/9] Added solution for 1-3 tasks of loops --- Loop1/my-hostfile | 1 + Loop1/run.sh | 2 +- Loop1/src/main.cpp | 72 ++++++++++++++++++++++++++++++++++++++++------ Loop2/my-hostfile | 1 + Loop2/run.sh | 2 +- Loop2/src/main.cpp | 65 +++++++++++++++++++++++++++++++++++++---- Loop3/my-hostfile | 1 + Loop3/run.sh | 2 +- Loop3/src/main.cpp | 68 +++++++++++++++++++++++++++++++++++++++---- 9 files changed, 193 insertions(+), 21 deletions(-) create mode 100644 Loop1/my-hostfile create mode 100644 Loop2/my-hostfile create mode 100644 Loop3/my-hostfile diff --git a/Loop1/my-hostfile b/Loop1/my-hostfile new file mode 100644 index 0000000..05e311e --- /dev/null +++ b/Loop1/my-hostfile @@ -0,0 +1 @@ +localhost slots=16 diff --git a/Loop1/run.sh b/Loop1/run.sh index 067a411..43d2c30 100755 --- a/Loop1/run.sh +++ b/Loop1/run.sh @@ -31,7 +31,7 @@ for test_dir in $tests_dir/*; do printf "\n[TEST $test]\n" echo "mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt" START=$(date +%s%N) - mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt + mpiexec -np $proc --hostfile my-hostfile $exe $test_dir/input.txt $build/$test.txt END=$(date +%s%N) DIFF=$((($END - $START)/1000000)) if [ ! $? -eq 0 ]; then diff --git a/Loop1/src/main.cpp b/Loop1/src/main.cpp index 318f940..48ff836 100644 --- a/Loop1/src/main.cpp +++ b/Loop1/src/main.cpp @@ -5,30 +5,82 @@ #include #include + +/** + * Функция, которая высчитывает границы + */ +void calcIterations( int* leftBorder, int* rightBorder, int rank, double sizeOfBlock, int length) +{ + *leftBorder = rank * sizeOfBlock; + + /* Если справа хватает элементов, то проблем нет, просто выделяем их */ + if ( (length - *leftBorder) >= sizeOfBlock) + { + *rightBorder = *leftBorder + sizeOfBlock - 1; + } else + /* Если справа не хватает элементов (например последний блок), то присваиваем правую границу */ + { + *rightBorder = length - 1; + } +} + +/* Вектор зависимости (0, 0), нам без разницы как разбивать. Разобьем на size блоков по столбцам или строкам */ void calc(double* arr, uint32_t ySize, uint32_t xSize, int rank, int size) { - if (rank == 0 && size > 0) - { - for (uint32_t y = 0; y < ySize; y++) + if ( rank != 0) { - for (uint32_t x = 0; x < xSize; x++) - { - arr[y*xSize + x] = sin(0.00001*arr[y*xSize + x]); - } + arr = new double[ySize * xSize]; } - } + + double* bufArr = new double[ySize * xSize](); + double* reduceArr = new double[ySize * xSize](); + + /* Передадим всем процессам изначальный массив arr */ + MPI_Bcast( arr, xSize * ySize, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + /* Найдем границы для каждого процесса */ + int yLeftBorder = 0, + yRightBorder = 0; + + int ySizeOfBlock = (int)ceil( (float)ySize / size); + + calcIterations( &yLeftBorder, &yRightBorder, rank, ySizeOfBlock, (int)ySize); + + for (int y = yLeftBorder; y <= yRightBorder; y++) + { + for (uint32_t x = 0; x < xSize; x++) + { + bufArr[y*xSize + x] = sin(0.00001*arr[y*xSize + x]); + } + } + + /* В каждой области имеем посчитанное значение, теперь надо их просто сложить в 0 процессе */ + MPI_Reduce( bufArr, reduceArr, (int)(xSize * ySize), MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + + if( rank == 0) + { + memcpy( arr, reduceArr, sizeof(double) * xSize * ySize); + } + + delete bufArr; + delete reduceArr; + } int main(int argc, char** argv) { + int rank = 0, size = 0, buf = 0; uint32_t ySize = 0, xSize = 0; double* arr = 0; MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); + + if (rank == 0) { // Check arguments @@ -72,6 +124,10 @@ int main(int argc, char** argv) } } + /* Разошлём всем процессам xSize и ySize */ + MPI_Bcast( &xSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &ySize, 1, MPI_INT, 0, MPI_COMM_WORLD); + calc(arr, ySize, xSize, rank, size); if (rank == 0) diff --git a/Loop2/my-hostfile b/Loop2/my-hostfile new file mode 100644 index 0000000..05e311e --- /dev/null +++ b/Loop2/my-hostfile @@ -0,0 +1 @@ +localhost slots=16 diff --git a/Loop2/run.sh b/Loop2/run.sh index 067a411..43d2c30 100755 --- a/Loop2/run.sh +++ b/Loop2/run.sh @@ -31,7 +31,7 @@ for test_dir in $tests_dir/*; do printf "\n[TEST $test]\n" echo "mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt" START=$(date +%s%N) - mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt + mpiexec -np $proc --hostfile my-hostfile $exe $test_dir/input.txt $build/$test.txt END=$(date +%s%N) DIFF=$((($END - $START)/1000000)) if [ ! $? -eq 0 ]; then diff --git a/Loop2/src/main.cpp b/Loop2/src/main.cpp index 51ea220..0f4e7e0 100644 --- a/Loop2/src/main.cpp +++ b/Loop2/src/main.cpp @@ -5,18 +5,69 @@ #include #include +/** + * Функция, которая высчитывает границы + */ +void calcIterations( int* leftBorder, int* rightBorder, int rank, double sizeOfBlock, int length) +{ + *leftBorder = rank * sizeOfBlock; + + /* Если справа хватает элементов, то проблем нет, просто выделяем их */ + if ( (length - *leftBorder) >= sizeOfBlock) + { + *rightBorder = *leftBorder + sizeOfBlock - 1; + } else + /* Если справа не хватает элементов (например последний блок), то присваиваем правую границу */ + { + *rightBorder = length - 1; + } +} + +/* Вектор зависимости (-1, 3) (>, <) - Это антизависимость (значения сначала используются, а потом вычисляются). Можно распараллелить при условии резервировании данных */ void calc(double* arr, uint32_t ySize, uint32_t xSize, int rank, int size) { - if (rank == 0 && size > 0) - { - for (uint32_t y = 0; y < ySize - 1; y++) + double* bufArr = new double[ySize * xSize](); + double* reduceArr = new double[ySize * xSize](); + + if ( rank != 0) + { + arr = new double[ySize * xSize]; + } + + /* Передадим всем процессам изначальный массив arr */ + MPI_Bcast( arr, xSize * ySize, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + /* Найдем границы для каждого процесса */ + int yLeftBorder = 0, + yRightBorder = 0; + + int ySizeOfBlock = (int)ceil( (float)(ySize - 1) / size); + + calcIterations( &yLeftBorder, &yRightBorder, rank, ySizeOfBlock, (int)(ySize - 1)); + + for (int y = yLeftBorder; y <= yRightBorder; y++) { for (uint32_t x = 3; x < xSize; x++) { - arr[y*xSize + x] = sin(0.00001*arr[(y + 1)*xSize + x - 3]); + bufArr[y*xSize + x] = sin(0.00001*arr[(y + 1)*xSize + x - 3]); } } - } + + /* В каждой области имеем посчитанное значение, теперь надо их просто сложить в 0 процессе */ + MPI_Reduce( bufArr, reduceArr, (int)(xSize * ySize), MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + + for (int i = 0; i < (int)ySize; i++) + for ( int j = 0; j < (int)xSize; j++) + if ( reduceArr[i*xSize + j] == 0) + reduceArr[i*xSize + j] = arr[i*xSize + j]; + + if( rank == 0) + { + memcpy( arr, reduceArr, sizeof(double) * xSize * ySize); + } + + delete bufArr; + delete reduceArr; } int main(int argc, char** argv) @@ -72,6 +123,10 @@ int main(int argc, char** argv) } } + /* Разошлём всем процессам xSize и ySize */ + MPI_Bcast( &xSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &ySize, 1, MPI_INT, 0, MPI_COMM_WORLD); + calc(arr, ySize, xSize, rank, size); if (rank == 0) diff --git a/Loop3/my-hostfile b/Loop3/my-hostfile new file mode 100644 index 0000000..05e311e --- /dev/null +++ b/Loop3/my-hostfile @@ -0,0 +1 @@ +localhost slots=16 diff --git a/Loop3/run.sh b/Loop3/run.sh index 067a411..43d2c30 100755 --- a/Loop3/run.sh +++ b/Loop3/run.sh @@ -31,7 +31,7 @@ for test_dir in $tests_dir/*; do printf "\n[TEST $test]\n" echo "mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt" START=$(date +%s%N) - mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt + mpiexec -np $proc --hostfile my-hostfile $exe $test_dir/input.txt $build/$test.txt END=$(date +%s%N) DIFF=$((($END - $START)/1000000)) if [ ! $? -eq 0 ]; then diff --git a/Loop3/src/main.cpp b/Loop3/src/main.cpp index 43cce1f..7f79ae1 100644 --- a/Loop3/src/main.cpp +++ b/Loop3/src/main.cpp @@ -5,18 +5,72 @@ #include #include +/** + * Функция, которая высчитывает границы + */ +void calcIterations( int* leftBorder, int* rightBorder, int rank, double sizeOfBlock, int length) +{ + *leftBorder = rank * sizeOfBlock; + + /* Если справа хватает элементов, то проблем нет, просто выделяем их */ + if ( (length - *leftBorder) >= sizeOfBlock) + { + *rightBorder = *leftBorder + sizeOfBlock - 1; + } else + /* Если справа не хватает элементов (например последний блок), то присваиваем правую границу */ + { + *rightBorder = length - 1; + } +} + +/* Здесь вектор зависимости (+4, 0) (>, =) - истинная зависимость, значения сначала вычисляются, + * а затем используются. Можно распараллелить только по внутреннему циклу */ + void calc(double* arr, uint32_t ySize, uint32_t xSize, int rank, int size) { - if (rank == 0 && size > 0) - { + double* bufArr = new double[ySize * xSize](); + double* reduceArr = new double[ySize * xSize](); + + if ( rank != 0) + { + arr = new double[ySize * xSize]; + } + + /* Передадим всем процессам изначальный массив arr */ + MPI_Bcast( arr, xSize * ySize, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + /* Найдем границы для каждого процесса */ + int xLeftBorder = 0, + xRightBorder = 0; + + int xSizeOfBlock = (int)ceil( (float)xSize / size); + + calcIterations( &xLeftBorder, &xRightBorder, rank, xSizeOfBlock, (int)xSize); + for (uint32_t y = 4; y < ySize; y++) { - for (uint32_t x = 0; x < xSize; x++) + for (int x = xLeftBorder; x <= xRightBorder; x++) { - arr[y*xSize + x] = sin(arr[(y - 4)*xSize + x]); + bufArr[y*xSize + x] = sin(arr[(y - 4)*xSize + x]); + arr[y*xSize + x] = bufArr[y*xSize + x]; } } - } + + /* В каждой области имеем посчитанное значение, теперь надо их просто сложить в 0 процессе */ + MPI_Reduce( bufArr, reduceArr, (int)(xSize * ySize), MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + + for (int i = 0; i < 4; i++) + for ( int j = 0; j < (int)xSize; j++) + reduceArr[i*xSize + j] = arr[i*xSize + j]; + + if( rank == 0) + { + memcpy( arr, reduceArr, sizeof(double) * xSize * ySize); + } + + delete bufArr; + delete reduceArr; + } int main(int argc, char** argv) @@ -72,6 +126,10 @@ int main(int argc, char** argv) } } + /* Разошлём всем процессам xSize и ySize */ + MPI_Bcast( &xSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &ySize, 1, MPI_INT, 0, MPI_COMM_WORLD); + calc(arr, ySize, xSize, rank, size); if (rank == 0) From a212537e7480c41a825f406cb20bb15344735c1f Mon Sep 17 00:00:00 2001 From: redf1sh Date: Thu, 12 Nov 2020 21:01:50 +0300 Subject: [PATCH 7/9] Added solution for 4th loop task --- Loop4/my-hostfile | 1 + Loop4/run.sh | 2 +- Loop4/src/main.cpp | 171 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 Loop4/my-hostfile diff --git a/Loop4/my-hostfile b/Loop4/my-hostfile new file mode 100644 index 0000000..05e311e --- /dev/null +++ b/Loop4/my-hostfile @@ -0,0 +1 @@ +localhost slots=16 diff --git a/Loop4/run.sh b/Loop4/run.sh index 067a411..43d2c30 100755 --- a/Loop4/run.sh +++ b/Loop4/run.sh @@ -31,7 +31,7 @@ for test_dir in $tests_dir/*; do printf "\n[TEST $test]\n" echo "mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt" START=$(date +%s%N) - mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt + mpiexec -np $proc --hostfile my-hostfile $exe $test_dir/input.txt $build/$test.txt END=$(date +%s%N) DIFF=$((($END - $START)/1000000)) if [ ! $? -eq 0 ]; then diff --git a/Loop4/src/main.cpp b/Loop4/src/main.cpp index d958d54..4001637 100644 --- a/Loop4/src/main.cpp +++ b/Loop4/src/main.cpp @@ -4,18 +4,170 @@ #include #include #include +#include +/** + * Функция, которая высчитывает границы + */ +void calcIterations( int* leftBorder, int* rightBorder, int rank, double sizeOfBlock, int length) +{ + *leftBorder = rank * sizeOfBlock; + + /* Если справа хватает элементов, то проблем нет, просто выделяем их */ + if ( (length - *leftBorder) >= sizeOfBlock) + { + *rightBorder = *leftBorder + sizeOfBlock - 1; + } else + /* Если справа не хватает элементов (например последний блок), то присваиваем правую границу */ + { + *rightBorder = length - 1; + } +} + +/** + * Функция, которая сдвигает массив обратно по оси x + */ +void BackShiftArray3D( double* arr, double* shifted_arr, int xSize, int ySize, int zSize) +{ + int lenX = 2 * xSize - 1; + for ( int z = 0; z < zSize; z++) + { + for ( int y = 0; y < ySize; y++) + { + for ( int x = 0; x < xSize; x++) + { + arr[z*xSize*ySize + y*xSize + x] = shifted_arr[z*lenX*ySize + y*lenX + (ySize - y + x - 1)]; + } + } + } + +} + +/** + * Функция, которая выполняет сдвиг массив "послойно" в направлении оси x + * + * WARNING: Массив удаляется из вызывающей функции + */ +double* ShiftArray3D( double* arr, int xSize, int ySize, int zSize) +{ + int lenX = 2*xSize - 1; + /* Массив для сдвига должен быть в 2 раза больше по оси x*/ + double* shifted_arr = new double[lenX * ySize * zSize]; + + /* Заполним массив значениями -2, так как изначальная заполненность положительными числами, а значения + * синуса лежат на отрезке [-1; 1] */ + for ( int z = 0; z < zSize; z++) + { + for ( int y = 0; y < ySize; y++) + { + for (int x = 0; x < lenX; x++) + { + shifted_arr[z*lenX*ySize + y*lenX + x] = -2; + } + } + } + + /* Сдвигаем массив по оси x */ + for ( int z = 0; z < zSize; z++) + { + for ( int y = 0; y < ySize; y++) + { + for (int x = 0; x < lenX; x++) + { + if( x < xSize) + { + shifted_arr[z*lenX*ySize + y*lenX + (ySize - y + x - 1)] = arr[z*xSize*ySize + y*xSize + x]; + } + } + } + } + + return ( shifted_arr); +} + +/* Здесь вектор расстояний (1, -1, -1) (<, >, >). Т.к. первый символ < - то это истинная зависимость */ void calc(double* arr, uint32_t zSize, uint32_t ySize, uint32_t xSize, int rank, int size) { - if (rank == 0 && size > 0) { + int lenX = 2 * xSize - 1; + double* bufArr = new double[ySize * lenX * zSize](); + double* reduceArr = new double[ySize * lenX * zSize](); + + /* Сначала рассылаем изначальный массив, а потом сдвигаем его, иначе нам потребуется в 3 раза больше операций */ + if ( rank != 0) + { + arr = new double[ySize * xSize * zSize]; + } + + /* Передадим всем процессам изначальный массив arr */ + MPI_Bcast( arr, xSize * ySize * zSize, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + /* Сдвинем массив по y и x */ + double* shifted_arr = ShiftArray3D( arr, xSize, ySize, zSize); + + /* Так как мы сдвинули массив, что у него нет зависимости по x, то мы можем + * разрезать на слои наш параллелепипед, со сдвинутыми слоями на отдельные части + * и посчитать в отдельных потоках */ + + /* Найдем границы для каждого процесса */ + int xLeftBorder = 0, + xRightBorder = 0; + + int xSizeOfBlock = (int)ceil( (float)lenX / size); + + calcIterations( &xLeftBorder, &xRightBorder, rank, xSizeOfBlock, lenX); + + /* Распараллелим по x */ for (uint32_t z = 1; z < zSize; z++) { - for (uint32_t y = 0; y < ySize - 1; y++) { - for (uint32_t x = 0; x < xSize - 1; x++) { - arr[z*ySize*xSize + y*xSize + x] = sin(arr[(z - 1)*ySize*xSize + (y + 1)*xSize + x + 1]); - } - } + for (uint32_t y = 0; y < ySize - 1; y++) { + for (int x = xLeftBorder; x <= xRightBorder; x++) + { + if ( (shifted_arr[(z - 1)*ySize*lenX + (y + 1)*lenX + x] != -2) && (shifted_arr[z*ySize*lenX + y*lenX + x] != -2)) + { + bufArr[z*ySize*lenX + y*lenX + x] = sin(shifted_arr[(z - 1)*ySize*lenX + (y + 1)*lenX + x]); + shifted_arr[z*ySize*lenX + y*lenX+ x] = bufArr[z*ySize*lenX + y*lenX + x]; + } + } + } } - } + + /* В каждой области имеем посчитанное значение, теперь надо их просто сложить в 0 процессе */ + MPI_Reduce( bufArr, reduceArr, (int)(lenX * ySize * zSize), MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + + /* Возвращаем обратно к виду правильного параллелепипеда */ + delete bufArr; + bufArr = new double[ySize * xSize * zSize](); + + BackShiftArray3D( bufArr, reduceArr, xSize, ySize, zSize); + + /* Там где не было вычислений записываем предыдущие невычесленные значения */ + for (uint32_t z = 0; z < zSize; z++) + /* Первый срез z = 0 */ + if ( z == 0) + for ( int y = 0; y < (int)ySize; y++) + for ( int x = 0; x < (int)xSize; x++) + bufArr[z*ySize*xSize + y*xSize + x] = arr[z*ySize*xSize + y*xSize + x]; + else + for ( int y = 0; y < (int)ySize; y++) + /* Правый столбец в срезе по z */ + if ( y < (int)(ySize - 1)) + for ( int x = xSize - 1; x < (int)xSize; x++) + bufArr[z*ySize*xSize + y*xSize + x] = arr[z*ySize*xSize + y*xSize + x]; + else + /* Последняя строка в срезе по z */ + for ( int x = 0; x < (int)xSize ; x++) + bufArr[z*ySize*xSize + y*xSize + x] = arr[z*ySize*xSize + y*xSize + x]; + + if( rank == 0) + { + memcpy( arr, bufArr, sizeof(double) * xSize * ySize * zSize); + } + + delete bufArr; + delete reduceArr; + delete shifted_arr; + + if ( rank != 0) + delete arr; } int main(int argc, char** argv) @@ -69,7 +221,12 @@ int main(int argc, char** argv) return 1; } } + /* Разошлём всем процессам xSize, ySize и zSize*/ + MPI_Bcast( &xSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &ySize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &zSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + calc(arr, zSize, ySize, xSize, rank, size); if (rank == 0) From 024bf4e5006c85263b44dbc13dc373b72df5df5f Mon Sep 17 00:00:00 2001 From: redf1sh Date: Fri, 27 Nov 2020 19:14:31 +0300 Subject: [PATCH 8/9] Added solution for 2nd comp task --- CompMath2/my-hostfile | 1 + CompMath2/run.sh | 2 +- CompMath2/src/main.cpp | 155 +++++++++++++++++++++++++++++++---------- 3 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 CompMath2/my-hostfile diff --git a/CompMath2/my-hostfile b/CompMath2/my-hostfile new file mode 100644 index 0000000..05e311e --- /dev/null +++ b/CompMath2/my-hostfile @@ -0,0 +1 @@ +localhost slots=16 diff --git a/CompMath2/run.sh b/CompMath2/run.sh index 028530d..a91d30d 100755 --- a/CompMath2/run.sh +++ b/CompMath2/run.sh @@ -31,7 +31,7 @@ for test_dir in $tests_dir/*; do printf "\n[TEST $test]\n" echo "mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt" START=$(date +%s%N) - mpiexec -np $proc $exe $test_dir/input.txt $build/$test.txt + mpiexec -np $proc --hostfile my-hostfile $exe $test_dir/input.txt $build/$test.txt END=$(date +%s%N) DIFF=$((($END - $START)/1000000)) if [ ! $? -eq 0 ]; then diff --git a/CompMath2/src/main.cpp b/CompMath2/src/main.cpp index 5c4527a..fa81c52 100644 --- a/CompMath2/src/main.cpp +++ b/CompMath2/src/main.cpp @@ -5,64 +5,142 @@ #include #include +/** + * Функция, которая высчитывает границы + */ +void calcIterations( int* leftBorder, int* rightBorder, int rank, double sizeOfBlock, int length) +{ + *leftBorder = rank * sizeOfBlock + 1; + + /* Если справа хватает элементов, то проблем нет, просто выделяем их */ + if ( (length - *leftBorder) >= sizeOfBlock) + { + *rightBorder = *leftBorder + sizeOfBlock - 1; + } else + /* Если справа не хватает элементов (например последний блок), то присваиваем правую границу */ + { + *rightBorder = length - 1; + } +} + +/** + * Функция для отладки. Печатаем фрейм + */ +void printFrame(double* frame, uint32_t ySize, uint32_t xSize) +{ + for (uint32_t y = 0; y < ySize; y++) + { + for (uint32_t x = 0; x < xSize; x++) + { + printf("%f ", frame[y*xSize + x]); + } + printf("\n"); + } + printf("\n"); +} + void calc(double* frame, uint32_t ySize, uint32_t xSize, double delta, int rank, int size) { - if (rank == 0 && size > 0) - { - double diff = 0; - double* tmpFrame = new double[ySize * xSize]; + double* tmpFrame = new double[ySize * xSize](); + + /* Приходится создать ещё один, так как + * MPI_Reduce не поддерживает send = recv + */ + double* recvFrame = new double[ySize * xSize](); + + double diff = 100; + double diff_part = 0; + + if (rank != 0) + { + frame = new double[ySize * xSize](); + } + + MPI_Bcast(frame, xSize*ySize, MPI_DOUBLE, 0, MPI_COMM_WORLD); + // Prepare tmpFrame for (uint32_t y = 0; y < ySize; y++) { - tmpFrame[y*xSize] = frame[y*xSize]; - tmpFrame[y*xSize + xSize - 1] = frame[y*xSize + xSize - 1]; + tmpFrame[y*xSize] = frame[y*xSize]; + tmpFrame[y*xSize + xSize - 1] = frame[y*xSize + xSize - 1]; } for (uint32_t x = 1; x < xSize - 1; x++) { - tmpFrame[x] = frame[x]; - tmpFrame[(ySize - 1)*xSize + x] = frame[(ySize - 1)*xSize + x]; - } - // Calculate first iteration - for (uint32_t y = 1; y < ySize - 1; y++) - { - for (uint32_t x = 1; x < xSize - 1; x++) - { - tmpFrame[y*xSize + x] = (frame[(y + 1)*xSize + x] + frame[(y - 1)*xSize + x] +\ - frame[y*xSize + x + 1] + frame[y*xSize + x - 1])/4.0; - diff += std::abs(tmpFrame[y*xSize + x] - frame[y*xSize + x]); - } + tmpFrame[x] = frame[x]; + tmpFrame[(ySize - 1)*xSize + x] = frame[(ySize - 1)*xSize + x]; } + /* Для каждого процесса расчитаем его "область действия" */ + /* Найдем границы для каждого процесса */ + int xLeftBorder = 0, + xRightBorder = 0; + + int xSizeOfBlock = (int)ceil( (float)(xSize - 2) / size); + + calcIterations( &xLeftBorder, &xRightBorder, rank, xSizeOfBlock, xSize - 1); + double* currFrame = tmpFrame; double* nextFrame = frame; + uint32_t iteration = 1; + // Calculate frames while (diff > delta) { - diff = 0; - for (uint32_t y = 1; y < ySize - 1; y++) - { - for (uint32_t x = 1; x < xSize - 1; x++) - { - nextFrame[y*xSize + x] = (currFrame[(y + 1)*xSize + x] + currFrame[(y - 1)*xSize + x] +\ + diff = 0; + diff_part = 0; + + std::fill(nextFrame, nextFrame + ySize*xSize, 0); + std::fill(recvFrame, recvFrame + ySize*xSize, 0); + + for (uint32_t y = 0; y < ySize; y++) + { + nextFrame[y*xSize] = currFrame[y*xSize]; + nextFrame[y*xSize + xSize - 1] = currFrame[y*xSize + xSize - 1]; + } + + for (uint32_t x = 1; x < xSize - 1; x++) + { + nextFrame[x] = currFrame[x]; + nextFrame[(ySize - 1)*xSize + x] = currFrame[(ySize - 1)*xSize + x]; + } + + for (uint32_t y = 1; y < ySize - 1; y++) + { + for (int x = xLeftBorder; x <= xRightBorder; x++) + { + nextFrame[y*xSize + x] = (currFrame[(y + 1)*xSize + x] + currFrame[(y - 1)*xSize + x] +\ currFrame[y*xSize + x + 1] + currFrame[y*xSize + x - 1])/4.0; - diff += std::abs(nextFrame[y*xSize + x] - currFrame[y*xSize + x]); - } - } - std::swap(currFrame, nextFrame); - iteration++; + diff_part += std::abs(nextFrame[y*xSize + x] - currFrame[y*xSize + x]); + } + } + + MPI_Allreduce( nextFrame, recvFrame, xSize * ySize, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce( &diff_part, &diff, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + + for (uint32_t y = 0; y < ySize; y++) + { + recvFrame[y*xSize] = currFrame[y*xSize]; + recvFrame[y*xSize + xSize - 1] = currFrame[y*xSize + xSize - 1]; + } + + for (uint32_t x = 1; x < xSize - 1; x++) + { + recvFrame[x] = currFrame[x]; + recvFrame[(ySize - 1)*xSize + x] = currFrame[(ySize - 1)*xSize + x]; + } + + memcpy(currFrame, recvFrame, xSize*ySize*sizeof(double)); + iteration++; } - // Copy result from tmp - if (iteration % 2 == 1) + if( rank == 0) { - for (uint32_t i = 0; i < xSize*ySize; i++) - { - frame[i] = tmpFrame[i]; - } + memcpy(frame, recvFrame, xSize*ySize*sizeof(double)); } + delete tmpFrame; - } + } int main(int argc, char** argv) @@ -119,6 +197,11 @@ int main(int argc, char** argv) } } + /* Разошлём всем процессам xSize, ySize и zSize*/ + MPI_Bcast( &xSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &ySize, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast( &delta, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + calc(frame, ySize, xSize, delta, rank, size); if (rank == 0) From 78a9c87c26ad8bafc36798410000fd9983aecea7 Mon Sep 17 00:00:00 2001 From: redf1sh Date: Fri, 27 Nov 2020 21:08:19 +0300 Subject: [PATCH 9/9] Fixed memory leaks --- CompMath2/src/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CompMath2/src/main.cpp b/CompMath2/src/main.cpp index fa81c52..86eb21c 100644 --- a/CompMath2/src/main.cpp +++ b/CompMath2/src/main.cpp @@ -140,6 +140,12 @@ void calc(double* frame, uint32_t ySize, uint32_t xSize, double delta, int rank, } delete tmpFrame; + delete recvFrame; + if (rank != 0) + { + delete frame; + } + }