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..86eb21c 100644 --- a/CompMath2/src/main.cpp +++ b/CompMath2/src/main.cpp @@ -5,64 +5,148 @@ #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; - } + delete recvFrame; + if (rank != 0) + { + delete frame; + } + + } int main(int argc, char** argv) @@ -119,6 +203,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) 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) 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) 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; 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) diff --git a/OpenMP4/src/main.cpp b/OpenMP4/src/main.cpp index 036d8e3..386128a 100644 --- a/OpenMP4/src/main.cpp +++ b/OpenMP4/src/main.cpp @@ -2,10 +2,33 @@ #include #include #include +#include -double calc(uint32_t x_last, uint32_t num_threads) + + +double fact_calculate( int i) { - return 0; + 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)); + + factorials[0] = 1; + for (int i = 1; i <= (int)x_last; i++) { + factorials[i] = fact_calculate( 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 / factorials[i]; + } + + free( factorials); + return res; } int main(int argc, char** argv) diff --git a/OpenMP5/src/main.cpp b/OpenMP5/src/main.cpp index bf042c5..9282277 100644 --- a/OpenMP5/src/main.cpp +++ b/OpenMP5/src/main.cpp @@ -3,9 +3,205 @@ #include #include +/* Константы для игрового поля */ +#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 для более удобной работы + * + * WARNING Массив удаляется из вызывающей функции + */ +uint8_t** ConvertFrom1Dto2D( uint32_t xSize, uint32_t ySize, uint8_t* input_frame) +{ + 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)); + } + + /* 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); +} + +/** + * Функция для отладки. Рисует промежуточный результат + */ +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"); +} + +/** + * Переводит матрицу в линейный массив + */ +inline void ConvertFrom2Dto1D( uint32_t xSize, uint32_t ySize, uint8_t** input_frame, uint8_t* output_frame) +{ + + for ( uint32_t i = 0; i < ySize; i++) + for( uint32_t j = 0; j < xSize; j++) + output_frame[i * xSize + j] = input_frame[i][j]; +} + +/** + * Вычисляет количество соседей возле указанной точки (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 */ + for ( int i = -1; i <= 1; i++) + { + for ( int j = -1; j <= 1; j++) + { + int x_shifted = x + i, + y_shifted = y + j; + + CycleShift( xSize, ySize, &x_shifted, &y_shifted); + if ( !( ( i == 0) && ( j == 0))) + { + if ( ( input_frame[x_shifted][y_shifted] == ALIVE)) + { + neighbours_num++; + } + } + } + } + + + return ( neighbours_num); +} + + 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); + + 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)); + } + + /* Для каждой ячейки необходимо проверить соседние и посчитать количество соседей */ + for ( uint32_t k = 0; k < iterations; k++) + { + #pragma omp parallel for num_threads( num_threads) + for ( uint32_t i = 0; i < xSize; i++) + { + #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); + + /* В пустой клетке, рядом с которой есть ровно 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; + } + } + + #pragma omp parallel for num_threads( num_threads) + COPY_ARRAY( result_frame, 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]); + free( result_frame[i]); + } + + free( temp_frame); + free( result_frame); + } int main(int argc, char** argv) @@ -48,6 +244,7 @@ int main(int argc, char** argv) } } + // Calculation calc(xSize, ySize, iterations, num_threads, inputFrame, outputFrame); @@ -65,6 +262,7 @@ int main(int argc, char** argv) // Prepare to exit delete outputFrame; delete inputFrame; + output.close(); input.close(); return 0;