Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 11.04.2013, 20:31   #1
Icy_Wind
Новичок
Джуниор
 
Регистрация: 11.04.2013
Сообщений: 3
По умолчанию Умножение матриц.Производительность.OpenMP(C+ +)

набросал алгоритм для умножения небольших матриц (500 на 500). Требуется:
-любые советы по улучшению его производительности (именно для небольших матриц)
-данный алгоритм очень хочется загнать в функцию, чтобы потом использовать его для блочного умножения больших матриц. Ещё очень хочется в этой функции использовать OpenMp...но директивы openmp внутри самой функции ухудшают производительность в двое (всё тестируется на одном потоке). Теперь сам вопрос - как правильно вынести нижеизложенный код перемножения в функцию и использовать OpenMp в этой самой функции.
Код:
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <iostream>
#include <omp.h>

using namespace std;


int main(int argc, char **argv)
{
	int threads = atoi(argv[2]);
	int n = atoi(argv[1]);
	

//Задание 2
	struct timeval StartTime;
    struct timeval EndTime;
	
	double* result = new double[n*n];
	double* A = new double[n*n];
	double* B = new double[n*n];

	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			result[i*n+j] = 0;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			A[i*n+j] = i+1;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			B[i*n+j] = 1.0/(j+1);
	int i,k;
	double *indres,*indA,*indB,*ind1B,*ind2B,*ind3B,*ind4B,*ind5B,*ind6B,*ind7B,*ind8B,*ind9B;
	gettimeofday(&StartTime,NULL);

#pragma omp parallel num_threads(threads) private(i,k,indres,indA,indB,ind1B,ind2B,ind3B,ind4B,ind5B,ind6B,ind7B,ind8B,ind9B) shared(result,A,B)
	{
#pragma omp for schedule(dynamic,25)
		for ( i = 0; i < n; i++)
	{
		indB = B;
		ind1B = B+n;
		ind2B = ind1B+n;
		ind3B = ind2B+n;
		ind4B = ind3B+n;
		ind5B = ind4B+n;
		ind6B = ind5B+n;
		ind7B = ind6B+n;
		ind8B = ind7B+n;
		ind9B = ind8B+n;
		indA = A+i*n;
		for(k =0; k < n; k+=10)
		{
			double *endres = result+(i+1)*n;
			for ( indres = result+i*n; indres < endres; indB+=5, ind1B+=5,ind2B+=5,ind3B+=5,ind4B+=5,ind5B+=5,ind6B+=5,ind7B+=5,ind8B+=5,ind9B+=5 ,indres+=5 )
			{
				indres[0] += indA[k] * indB[0];
				indres[1] += indA[k] * indB[1];
				indres[2] += indA[k] * indB[2];
				indres[3] += indA[k] * indB[3];
				indres[4] += indA[k] * indB[4];
				
				indres[0] += indA[k+1] * ind1B[0];
				indres[1] += indA[k+1] * ind1B[1];
				indres[2] += indA[k+1] * ind1B[2];
				indres[3] += indA[k+1] * ind1B[3];
				indres[4] += indA[k+1] * ind1B[4];
				
				indres[0] += indA[k+2] * ind2B[0];
				indres[1] += indA[k+2] * ind2B[1];
				indres[2] += indA[k+2] * ind2B[2];
				indres[3] += indA[k+2] * ind2B[3];
				indres[4] += indA[k+2] * ind2B[4];
				
				indres[0] += indA[k+3] * ind3B[0];
				indres[1] += indA[k+3] * ind3B[1];
				indres[2] += indA[k+3] * ind3B[2];
				indres[3] += indA[k+3] * ind3B[3];
				indres[4] += indA[k+3] * ind3B[4];
				
				indres[0] += indA[k+4] * ind4B[0];
				indres[1] += indA[k+4] * ind4B[1];
				indres[2] += indA[k+4] * ind4B[2];
				indres[3] += indA[k+4] * ind4B[3];
				indres[4] += indA[k+4] * ind4B[4];
				//
				indres[0] += indA[k+5] * ind5B[0];
				indres[1] += indA[k+5] * ind5B[1];
				indres[2] += indA[k+5] * ind5B[2];
				indres[3] += indA[k+5] * ind5B[3];
				indres[4] += indA[k+5] * ind5B[4];
				
				indres[0] += indA[k+6] * ind6B[0];
				indres[1] += indA[k+6] * ind6B[1];
				indres[2] += indA[k+6] * ind6B[2];
				indres[3] += indA[k+6] * ind6B[3];
				indres[4] += indA[k+6] * ind6B[4];
				
				indres[0] += indA[k+7] * ind7B[0];
				indres[1] += indA[k+7] * ind7B[1];
				indres[2] += indA[k+7] * ind7B[2];
				indres[3] += indA[k+7] * ind7B[3];
				indres[4] += indA[k+7] * ind7B[4];
				
				indres[0] += indA[k+8] * ind8B[0];
				indres[1] += indA[k+8] * ind8B[1];
				indres[2] += indA[k+8] * ind8B[2];
				indres[3] += indA[k+8] * ind8B[3];
				indres[4] += indA[k+8] * ind8B[4];
				
				indres[0] += indA[k+9] * ind9B[0];
				indres[1] += indA[k+9] * ind9B[1];
				indres[2] += indA[k+9] * ind9B[2];
				indres[3] += indA[k+9] * ind9B[3];
				indres[4] += indA[k+9] * ind9B[4];
			}
			indB+=9*n;
			ind1B+=9*n;
			ind2B+=9*n;
			ind3B+=9*n;
			ind4B+=9*n;
			
			ind5B+=9*n;
			ind6B+=9*n;
			ind7B+=9*n;
			ind8B+=9*n;
			ind9B+=9*n;
		}
	}
	}
	gettimeofday(&EndTime,NULL);
	double time = (EndTime.tv_sec - StartTime.tv_sec) + (EndTime.tv_usec-StartTime.tv_usec)/1000000.0;

	cout<<"Time - "<<fixed<<time<<" sec"<<endl;

	cout<<"Perfomance - "<<fixed<<2*((double)n/time)*((double)n*(double)n/1000000.0)<<" MegaFlops\n";
	cout<<fixed<<result[0];
	cout<<fixed<<"\t"<<result[n-1]<<endl;
	cout<<fixed<<result[(n-1)*n];
	cout<<fixed<<"\t"<<result[(n-1)*n+n-1]<<endl;
	cout<<"Threads count = "<<threads<<endl;
	
	    delete[] result;
	    delete[] A;
	    delete[] B;
//Задание 2
    return 0;		
}
Icy_Wind вне форума Ответить с цитированием
Старый 11.04.2013, 21:57   #2
kineziz
Форумчанин
 
Регистрация: 22.12.2011
Сообщений: 378
По умолчанию

indB - ind9B можно запихнуть в 1 переменную.
Так же этот большой цикл можно сократить еще одним вложенным циклом.

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

Вообщем код ужасный (извините, но это правда)
Большинство хороших программистов делают свою работу не потому, что ожидают оплаты или признания, а потому что получают удовольствие от программирования.

Последний раз редактировалось kineziz; 11.04.2013 в 21:59.
kineziz вне форума Ответить с цитированием
Старый 12.04.2013, 03:07   #3
Icy_Wind
Новичок
Джуниор
 
Регистрация: 11.04.2013
Сообщений: 3
По умолчанию

Цитата:
indB - ind9B можно запихнуть в 1 переменную.
в массив indB[10]? пробовал...и наблюдал большое падение производительности.
Цитата:
Если матрицы будут большие, то программу можно разбить на потоки. Первый поток обрабатывает первую часть, а второй - вторую.
да...матрицы будут ОЧЕНЬ большими) 16000 на 16000. Я буду из перемножать блочным алгоритмом через MPI. То, что написано - пока только кирпичик.
Цитата:
Если нужно максимально оптимизировать производительность, то можно умножение заменить побитовым сдвигом.
Очень интересно...я думал, умножение двух случайных чисел этим заменить нельзя...пойду искать инфу))
Цитата:
Вообщем код ужасный
я понимаю) но это же не я так пишу. Я бы сам такую ересь с трудом бы читал)) а компилятору нравится, когда так пишут...каждая строчка этого кода записана после многократных сравнений того, как будет лучше "с ней" или "без неё"
Цитата:
Так же этот большой цикл можно сократить еще одним вложенным циклом.
Аналогично предыдущему ответу...изначально цикл был ОЧЕНЬ свёрнут...мне, наоборот, пришлось его раскрывать

А можете помочь с заменой умножения на побитовые сдвиги?

Последний раз редактировалось Icy_Wind; 12.04.2013 в 03:15.
Icy_Wind вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Умножение 2-х матриц Lifefine Общие вопросы Delphi 7 23.03.2011 09:54
умножение матриц затерявшисьвдебрях Помощь студентам 0 25.01.2011 22:13
умножение матриц Rusya_00 Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 1 06.01.2011 23:51
умножение матриц Mila Volkova Помощь студентам 3 25.12.2010 14:17
Умножение матриц Си Slame Помощь студентам 4 16.12.2010 14:34