Кафедра ЕОМ
Звіт
з лабораторної роботи № 3
з дисципліни: “Алгоритми та методи обчислень” Варіант № 7
Мета роботи: ознайомитися з використанням потокового графу алгоритму при паралельному програмуванні
Вхідні дані
с = 565 b = 566 a = 561
Лістинг програми:
#include <stdio.h>
#include <stdlib.h>
#include <x86intrin.h> // Linux
#include <math.h>
#include <time.h>
#define A
565
#define B
566
#define C
561
#pragma GCC push_options
#pragma GCC optimize ("no-unroll-loops")
#define REPEAT_COUNT 1000000
#define REPEATOR(count, code) \
for (unsigned int indexIteration = (count); indexIteration--;){ code; }
#define TWO_VALUES_SELECTOR(variable, firstValue, secondValue) \ (variable) = indexIteration % 2 ? (firstValue) : (secondValue);
double getCurrentTime(){ clock_t time = clock(); if (time != (clock_t)-1) {
return ((double)time / (double)CLOCKS_PER_SEC);
}
return 0.; // else
}
#pragma GCC push_options
#pragma GCC target ("no-sse2")
// attribute (( target ("no-sse2"))) void run_native(double * const dArr){
double * const dAC = dArr; double * const dA = &dAC[0]; double * const dC = &dAC[1]; double * const dB = &dArr[2];
double * const dResult = &dArr[4]; double * const dX1 = &dResult[1]; double * const dX2 = &dResult[0];
REPEATOR(REPEAT_COUNT, TWO_VALUES_SELECTOR(*dA, 4., A);
TWO_VALUES_SELECTOR(*dB, 3., B);
TWO_VALUES_SELECTOR(*dC, 1., C);
double vD = sqrt((*dB)*(*dB) - 4.*(*dA)*(*dC));
(*dX1) = (-(*dB) + vD) / (2.*(*dA));
(*dX2) = (-(*dB) - vD) / (2.*(*dA));
)
}
#pragma GCC pop_options
void run_SSE2(double * const dArr){ double * const dAC = dArr; double * const dA = &dAC[0]; double * const dC = &dAC[1]; double * const dB = &dArr[2];
double * const dResult = &dArr[4]; double * const dX1 = &dResult[1]; double * const dX2 = &dResult[0];
m128d r zero_zero, r c_a, r uORb_b, r 2cORbOR2a_2a, r zero_bb, r sqrtDiscriminant_zero, r_result;
r zero_zero = _mm_set_pd(0., 0.); // init
REPEATOR(REPEAT_COUNT, TWO_VALUES_SELECTOR(*dA, 4., A);
TWO_VALUES_SELECTOR(*dB, 3., B);
TWO_VALUES_SELECTOR(*dC, 1., C);
r c_a = _mm_load_pd(dAC);
// r uORb_b = _mm_load_pd1(dB); r uORb_b = _mm_load1_pd(dB);
// b b
r uORb_b = _mm_unpacklo_pd(r uORb_b, r uORb_b);
// (etap 1)
r 2cORbOR2a_2a = _mm_add_pd(r c_a, r c_a);
// b 2c
r_result = _mm_unpackhi_pd(r 2cORbOR2a_2a, r uORb_b);
// b 2a
r 2cORbOR2a_2a = _mm_unpacklo_pd(r 2cORbOR2a_2a, r uORb_b);
// bb 4ac (etap 2)
r_result = _mm_mul_pd(r_result, r 2cORbOR2a_2a);
r zero_bb = _mm_unpackhi_pd(r_result, r zero_zero);
// zero Discriminant (etap 3)
r_result = _mm_sub_sd(r zero_bb, r_result);
// zero sqrtDiscriminant (etap 4)
r_result = _mm_sqrt_sd(r_result, r_result);
r sqrtDiscriminant_zero = _mm_shuffle_pd(r_result, r_result, 1);
// sqrtDiscriminant -sqrtDiscriminant (etap 5)
r_result = _mm_sub_sd(r sqrtDiscriminant_zero, r_result);
// (etap 6)
r_result = _mm_sub_pd(r_result, r uORb_b);
// 2a 2a
r 2cORbOR2a_2a = _mm_unpacklo_pd(r 2cORbOR2a_2a, r 2cORbOR2a_2a);
// (etap 7)
r_result = _mm_div_pd(r_result, r 2cORbOR2a_2a);
_mm_store_pd(dResult, r_result);
)
}
void printResult(char * const title, double * const dArr, unsigned int runTime){ double * const dAC = dArr;
double * const dA = &dAC[0]; double * const dC = &dAC[1]; double * const dB = &dArr[2]; double * const dResult = &dArr[4]; double * const dX1 = &dResult[1]; double * const dX2 = &dResult[0];
printf("%s:\r\n", title);
printf("%fx^2 + %fx + %f = 0;\r\n", *dA, *dB, *dC); printf("x1 = %1.0f; x2 = %1.0f;\r\n", *dX1, *dX2); printf("run time: %dns\r\n\r\n", runTime);
}
int main() {
double * const dArr = (double *)_mm_malloc(6 * sizeof(double), 16);
double * const dAC = dArr; double * const dA = &dAC[0]; double * const dC = &dAC[1]; double * const dB = &dArr[2];
double * const dResult = &dArr[4]; double * const dX1 = &dResult[1]; double * const dX2 = &dResult[0];
double startTime, endTime;
// native (only x86, if auto vectorization by compiler is off) startTime = getCurrentTime();
run_native(dArr);
endTime = getCurrentTime(); printResult("x86",
dArr,
(unsigned int)((endTime - startTime) * (1000000000 / REPEAT_COUNT)));
// SSE2
startTime = getCurrentTime(); run_SSE2(dArr);
endTime = getCurrentTime(); printResult("SSE2",
dArr,
(unsigned int)((endTime - startTime) * (1000000000 / REPEAT_COUNT)));
_mm_free(dArr);
printf("Press any key to continue . . ."); getchar();
return 0;
}
#pragma GCC pop_options Скріншот виконання програми:
/
Висновок
- ознайомився з використанням потокового графу