Главная ЭВМ и системы » Файлы » Методички » ЭВМ и системы [ Добавить материал ]

Векторизация с помощью SSE/SSE2

Операции с матрицами хорошо векторизуются, следовательно, мы можем использовать SIMD-расширения процессоров, а именно – SSE (MMX не позволяет работать с плавающей запятой). Но для использования SSE инструкций нам необходимо явно указывать их, поэтому код основной расчетной функции придется переделать.

Все арифметические SSE инструкции оперируют над векторами, длина которых зависит от типа данных: для float n=4, для double n=2. Будем оперировать типом float, поскольку для него прирост производительности заметнее.

Будем использовать ленточную схему распараллеливания, а вернее – просто оригинальный алгоритм умножения. Отличие в данном случае состоит в том, что мы просто уменьшим количество шагов при вычислении каждого элемента во внутреннем цикле в 4 раза – по числу элементов, параллельно обрабатываемых в SSE-инструкции.

На каждом шаге теперь мы будем брать по 4 элемента строки матрицы, по 4 элемента вектора и перемножать их одной командой SSE, а затем – складывать одной командой сразу 4 пары элементов. Все, что останется сделать в конце цикла – это сложить 4 частичных суммы явно. Для этого в SSE3 есть специальная команда «горизонтального» сложения, а вот в SSE2, к сожалению, ее нет, поэтому в приведенном ниже примере приходится явно перегружать вектор из 4 компонент в массив, а потом – складывать элементы массива.



Code
void SerialResultCalculationSSE(float* pMatrix, float* pVector, float* pResult,int Size)
{
    __m128 row0;
    __m128 row1;
    __m128 row2;
    __m128 res4;
    float* res_4;
    float res=0;
    res_4 = (float *)_aligned_malloc(4*sizeof(float), 16);

    int i,j,k; // Переменные цикла

    for (i=0; i < Size; i++)
    {
        res4=_mm_setzero_ps();
        for (j=0; j < Size; j=j+4)
        {
            row1 = _mm_load_ps(&pVector[j]); //загрузка вектора
            row0 = _mm_load_ps(&pMatrix[Size*(i)+j] ); //загрузка строки матрицы
            row2 = _mm_mul_ps(row0, row1);//перемножение
            res4 = _mm_add_ps(row2, res4); // накопление 4-х сумм
        }

        _mm_store_ps(&res_4[0], res4); // переброс в массив
        pResult[i] = res_4[0] + res_4[1] + res_4[2] + res_4[3]; // окончательное формирование элемента
    }
}
Похожие материалы:

Добавил: mauzer (20.06.2010) | Категория: ЭВМ и системы
Просмотров: 4540 | Загрузок: 0 | Рейтинг: 5.0/1 |
Теги: SSE
Комментарии (0)

Имя *:
Email *:
Код *: