Mono.Simd и перемножение матриц
От: Saidai no  
Дата: 01.05.10 21:18
Оценка:
Доброго времени суток!
Пытаюсь соптимизировать умножение небольшой (40*40) матрицы из float на вектор.
Понятно, что с развернутым в одну строку массивом (и развернутым циклом) получается немного быстрее, чем какие-то извращения с jagged (код под катом):
  Скрытый текст
public static void Main()
{
    int N = 40;
    int T = 1000000;
    long start, stop;
    double elapsed;
    var A = new float[N*N];
    var B = new float[N];
    for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j++)
        A[i*N+j] = Math.Abs(i-j);
    for (int i = 0; i < N; i++)
        B[i] = i;

    var C = new float[N];
    start = DateTime.Now.Ticks;
    
    for (int l = 0; l < T; l++)
    for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j+=4)
    {
        C[i] += A[i*N+j] * B[j];
        C[i] += A[i*N+j+1] *B[j+1];
        C[i] += A[i*N+j+2] *B[j+2];
        C[i] += A[i*N+j+3] *B[j+3];
    }
    stop = DateTime.Now.Ticks;
    elapsed = (stop - start) / 1000.0 / 10000;
    Console.WriteLine("Single line unfolded:  " + elapsed + " seconds");
}




А вот реализация Mono.Simd относительно предыдущего варианта дает всего порядка 10% ускорения (код под катом, запускать под Mono, добавить reference на Mono.Simd.dll). Мб я что-то делаю не так? С SIMD на Intel знаком только в общих чертах.
  Скрытый текст
public static void Main()
{
    int N = 40;
    int T = 1000000;
    long start, stop;
    double elapsed;

    start = DateTime.Now.Ticks;
    var n = N/4;
    var A = new Vector4f[N*n];
    var B = new Vector4f[n];
            
    for (int i = 0; i < N; i++)
    for (int j = 0; j < n; j++)
    {
        A[i*n+j][0] = Math.Abs(i-j*4);
        A[i*n+j][1] = Math.Abs(i-j*4-1);
        A[i*n+j][2] = Math.Abs(i-j*4-2);
        A[i*n+j][3] = Math.Abs(i-j*4-3);
    }

    for (int i = 0; i < n; i++)
    {
        B[i][0] = i*4;
        B[i][1] = i*4+1;
        B[i][2] = i*4+2;
        B[i][3] = i*4+3;
    }

    var C = new Vector4f[n];
    start = DateTime.Now.Ticks;

    for (int l = 0; l < T; l++)
    {
        var v = new Vector4f[N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < n; j++)
                v[i] += A[i*n+j]*B[j];
        }
        // HorzontalAdd(a,b) := { a[0]+a[1], a[2]+a[3], b[0]+b[1], b[2]+b[3] }, вроде как одна инструкция SSE3
        for (int i = 0; i<N; i+=4)
            C[i>>2] = VectorOperations.HorizontalAdd(VectorOperations.HorizontalAdd(v[i],v[i+1]),VectorOperations.HorizontalAdd(v[i+2],v[i+3]));
    }

    stop = DateTime.Now.Ticks;
    elapsed = (stop - start) / 1000.0 / 10000;
    Console.WriteLine("SIMD:  " + elapsed + " seconds");
}




P.S. OS — Mac OS X; с unmanaged-вставками я не знаю стоит ли возиться, не выйдет ли маршалинг этой матрицы с вектором дороже, чем само умножение.
Скорость нужна, т.к. эти умножения (правда, с разными матрицами и разными векторами) программой будут проводиться почти подряд и в огромном числе.
CPU поддерживает вплоть до SSSE3.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.