更新:之前提到的 Span 问题已在 .net core 2.1 发布版中得到解决(目前处于预览状态)。这实际上使 Span 向量比数组向量更快...
注意:我在“Intel Xeon E5-1660 v4”上进行了测试,CPU-Z告诉我它支持“MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、EM64T、VT-x、AES、AVX、AVX2、FMA3、RSX”指令,所以应该没问题...
在回答一个基于向量的问题后,我想尝试实现一些 BLAS 函数。我发现像点积这样的读取/求和函数效果很好,但是当我写回到数组时效果不佳 - 比非 SIMD 好一点,但几乎没有改善。
那么我是做错了什么,还是 JIT 需要更多工作?
例如(假设 x.Length = y.Length,不为空等等):
public static void daxpy(double alpha, double[] x, double[] y)
{
for (var i = 0; i < x.Length; ++i)
y[i] = y[i] + x[i] * alpha;
}
以矢量形式表示为:
public static void daxpy(double alpha, double[] x, double[] y)
{
var i = 0;
if (Vector.IsHardwareAccelerated)
{
var length = x.Length + 1 - Vector<double>.Count;
for (; i < length; i += Vector<double>.Count)
{
var valpha = new Vector<double>(alpha);
var vx = new Vector<double>(x, i);
var vy = new Vector<double>(y, i);
(vy + vx * valpha).CopyTo(y, i);
}
}
for (; i < x.Length; ++i)
y[i] = y[i] + x[i] * alpha;
}
今天在.NET Core 2.0中尝试使用Span(包括naive和Vector格式)。
public static void daxpy(double alpha, Span<double> x, Span<double> y)
{
for (var i = 0; i < x.Length; ++i)
y[i] += x[i] * alpha;
}
和向量
public static void daxpy(double alpha, Span<double> x, Span<double> y)
{
if (Vector.IsHardwareAccelerated)
{
var vx = x.NonPortableCast<double, Vector<double>>();
var vy = y.NonPortableCast<double, Vector<double>>();
var valpha = new Vector<double>(alpha);
for (var i = 0; i < vx.Length; ++i)
vy[i] += vx[i] * valpha;
x = x.Slice(Vector<double>.Count * vx.Length);
y = y.Slice(Vector<double>.Count * vy.Length);
}
for (var i = 0; i < x.Length; ++i)
y[i] += x[i] * alpha;
}
所以所有这些的相对时间如下:
Naive 1.0
Vector 0.8
Span Naive 2.5 ==> Update: Span Naive 1.1
Span Vector 0.9 ==> Update: Span Vector 0.6
我做错了什么吗?我想不出更简单的例子,所以我认为没有问题。
IL
吗? - TigranSpan
,但是在阅读文档时,我注意到它是一个值类型。在您的情况下,您将其按值传递到函数中,该函数会在Span<T>
类型上调用副本。 - TigranVector<double>
- 这是一个STL类型,而不是.NET。 - Dai