Автор работы: Пользователь скрыл имя, 10 Мая 2013 в 15:04, лабораторная работа
1. Условие задачи:
Реализовать процедуру умножения квадратных матриц (размером кратным четырём):
1) без использования специальных расширений,
2) с использованием расширений SSE.
Сравнить время выполнения реализаций.
2. Условие задачи
В соответствии с вариантом задания реализовать матрично-векторную (с одинаковым размером матриц и векторов кратным четырём) процедуру с использованием расширений SSE.
Министерство образования и науки Российской Федерации
«НОВОСИБИРСКИЙ
Факультет прикладной математики и информатики
Кафедра параллельных вычислительных технологий
Лабораторная работа № 2
Выполнили: |
Тонхоноев А.А. |
студент 1 курса ФПМИ, группа ПМ-22 | |
Новосибирск
2013
Реализовать процедуру умножения квадратных матриц (размером кратным четырём):
Сравнить время выполнения реализаций.
#include <xmmintrin.h>
#include <stdio.h>
#include <conio.h>
#include <locale.h>
#include <time.h>
#include <stdlib.h>
clock_t ns1;
void time_start();
long time_stop();
float skalar(float *x, float* y, int n);
float sseskalar(float* x, float* y, int n);
void mult(float **c, float **x, float **y, int m, int n, int q);
void mult2(float **c, float **x, float **y, int m, int n, int q);
int main()
{
setlocale(LC_ALL,"Russian");
FILE *fout1=fopen("output1.txt", "w");
FILE *fout2=fopen("output2.txt", "w");
int i,j,m,n,q; long t; float z;
printf("Умножение матриц А и В возможно только когда они размеров (m x n) и (n x q)\nВведите m, n, q:\n");
scanf("%d %d %d",&m,&n,&q);
float **a=(float**)_mm_malloc(m*size
for(i=0; i<m; i++)
a[i]=(float*)_mm_malloc(n*size
for (i=0; i<m; i++) //заполнение первой матрицы элементами
for (j=0; j<n; j++)
a[i][j]=(3*i+j+1);
float **b=(float**)_mm_malloc(n*size
for(i=0; i<n; i++)
b[i]=(float*)_mm_malloc(q*size
for (i=0; i<n; ++i) //заполнение второй матрицы элементами
for (j=0; j<q; ++j)
b[i][j]=(i+1+2*j);
float **c=(float**)_mm_malloc(m*size
for(i=0; i<n; i++)
c[i]=(float*)_mm_malloc(q*size
for (i=0; i<n; ++i) //транспонирование второй матрицы
for (j=i; j<q; ++j)
if (i!=j)
{
z=b[i][j];
b[i][j]=b[j][i];
b[j][i]=z;
}
time_start();
mult(c,a,b,m,n,q); //умножение матрицы без SIMD расширений
t=time_stop();
for (i=0; i<n; ++i)
{
fprintf(fout1,"\n");
for (j=0; j<q; ++j)
fprintf(fout1,"%f ", c[i][j]);
}
printf("\nВремя: %d\n", t);
time_start();
mult2(c,a,b,m,n,q); //умножение матрицы с использованием SSE
t=time_stop();
for (i=0; i<n; ++i)
{
fprintf(fout2,"\n");
for (j=0; j<q; ++j)
fprintf(fout2, "%f ", c[i][j]);
}
printf("\nВремя: %d\n", t);
getch();
_mm_free(a);
_mm_free(b);
_mm_free(c);
return 0;
fclose(fout1);
fclose(fout2);
}
float skalar(float *x, float* y, int n) //функция скалярного умножения векторов
{
float s = 0;
for(int i=0; i<n; i++)
s += x[i]*y[i];
return s;
}
float sseskalar(float* x, float* y, int n) //функция скалярного умножения векторов с использованием SSE
{
__m128 *xx, *yy;
__m128 p,s;
xx = (__m128*)x;
yy = (__m128*)y;
s = _mm_set_ps1(0);
for(int i=0; i<n/4; i++)
{
p = _mm_mul_ps(xx[i],yy[i]);
s = _mm_add_ps(s,p);
}
p = _mm_movehl_ps(p,s);
s = _mm_add_ps(s,p);
p = _mm_shuffle_ps(s,s,1);
s = _mm_add_ss(s,p);
float sum;
_mm_store_ss(&sum,s);
return sum;
}
void mult(float **c, float **x, float **y, int m, int n, int q)
{
int i,j;
//при перемножении матриц умножаются векторы-строки первой матрицы на векторы-столбцы второй, однако вторая матрица транспонирована, значит нужно перемножать векторы-строки
for (i=0; i<m; i++)
for (j=0; j<n; j++)
c[i][j]=skalar(x[i],y[j], n);
}
void mult2(float **c, float **x, float **y, int m, int n, int q)
{
int i,j;
for (i=0; i<m; i++)
for (j=0; j<n; j++)
c[i][j]=sseskalar(x[i],y[j], n);
}
void time_start()
{
ns1=clock();
}
long time_stop()
{
return(clock()-ns1)*1000/CLOCK
}
В соответствии
с вариантом задания
(7) aAx+bBy
#include <xmmintrin.h>
#include <stdio.h>
#include <conio.h>
#include <locale.h>
#include <time.h>
#include <stdlib.h>
float sseskalar(float* x, float* y, int n) //функция скалярного умножения векторов с использованием SSE
{
__m128 *xx, *yy;
__m128 p,s;
xx = (__m128*)x;
yy = (__m128*)y;
s = _mm_set_ps1(0);
for(int i=0; i<n/4; i++)
{
p = _mm_mul_ps(xx[i],yy[i]);
s = _mm_add_ps(s,p);
}
p = _mm_movehl_ps(p,s);
s = _mm_add_ps(s,p);
p = _mm_shuffle_ps(s,s,1);
s = _mm_add_ss(s,p);
float sum;
_mm_store_ss(&sum,s);
return sum;
}
void multvector(float *c, float **x, float *y, int m, int n) //умножение матрицы на вектор
{
int i;
for (i=0; i<m; i++)
c[i]=sseskalar(x[i], y, n);
}
void multconst(float *x, float alpha, int n) //умножение вектора на скаляр
{
for (int i=0; i<n; i++)
x[i]=x[i]*alpha;
}
void addict(float *x, float *y, int n) //сложение векторов
{
for (int i=0; i<n; i++)
x[i]=x[i]+y[i];
}
void main()
{
//ax+bBy;
setlocale(LC_ALL,"Russian");
const int alpha=34.1, beta=12.4559;
FILE *fout1=fopen("output1.txt", "w");
FILE *fout2=fopen("output2.txt", "w");
int i,j,m,n; long t; float z;
printf("Введите m и n(размеры матриц, m так же задает размер вектора)\n");
scanf("%d %d",&m,&n);
float **A=(float**)_mm_malloc(m*size
for(i=0; i<m; i++)
A[i]=(float*)_mm_malloc(n*size
for (i=0; i<m; i++) //заполнение первой матрицы элементами
for (j=0; j<n; j++)
A[i][j]=(3*i+j+1)/2;
float **B=(float**)_mm_malloc(m*size
for(i=0; i<n; i++)
B[i]=(float*)_mm_malloc(n*size
for (i=0; i<m; ++i) //заполнение второй матрицы элементами
for (j=0; j<n; ++j)
B[i][j]=(i+1+2*j)/3;
float *s1=(float*)_mm_malloc(m*sizeo
float *s2=(float*)_mm_malloc(m*sizeo
float *x=(float*)_mm_malloc(m*sizeof
for (j=0; j<n; j++)
x[j]=(j+17)/15;
float *y=(float*)_mm_malloc(m*sizeof
for (j=0; j<n; j++)
y[j]=(2*j+1)/23;
multvector(s2, B, y, m, n);
multconst(x,alpha, m);
multconst(s2,beta, m);
addict(x,s2,m);
for(i=0; i<m; i++)
printf("%f ", x[i]);
getch();
_mm_free(A);
_mm_free(B);
_mm_free(s1);
_mm_free(s2);
_mm_free(x);
_mm_free(y);
}
На основании проделанной работы можно сделать вывод, что использование SIMD расширений ускоряет работу программы, однако эффективно лишь для множественных одинаковых операций над многими числами одновременно.