Доброго времени суток!
Пытаюсь соптимизировать умножение небольшой (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.