[英]What is the fastest way to prepare data for Vector256 in c#
我正在尝试在我的 function 中使用 SIMD 来提高性能,但似乎在 memory 的数据准备过程中我损失了更多。 我有什么:
public class SubProp
{
public double subProp1, subProp2;
<few functions>
}
public class MyClass
{
public subProp prop1, prop2;
<lots of other props>
}
public void DoSomeMath(List<MyClass> data)
{
int cnt = data.Count;
for(int i = 0; i < cnt; i++)
{
SubProp Prop1 = data[i].prop1;
SubProp Prop2 = data[i].prop2
for(int j = i + 1; j < cnt; j++)
{
SubProp Prop3 = data[j].prop1;
SubProp Prop4 = data[j].prop2;
//these substructions suppose to be optimized with SIMD
double res1 = Prop4.subProp2 - Prop3.subProp2;
double res2 = Prop1.subProp1 - Prop2.subProp1;
double res3 = Prop4.subProp1 - Prop3.subProp1;
double res4 = Prop1.subProp2 - Prop2.subProp2;
double res5 = Prop4.subProp1 - Prop2.subProp1;
double res6 = Prop4.subProp2 - Prop2.subProp2;
<some more math with res<n> variables and logical functions on results>
}
}
}
我已经尝试过的:
在循环内构建 4 个双打的跨度(非常慢)
在循环外分配 3 个 Span(左、右用于减法,第 3 个用于结果),并在循环内用数字填充它们(非常慢)
使用常规 arrays 而不是 Spans (确实看到任何大的区别)
我错过了什么吗? 某种快速的方法以正确的顺序在 memory 中设置数据,或者在这种情况下甚至不可能使用 SIMD 获得更好的性能?
PS 关于我在这里如何使用 Vector256 的一点解释:
var lSide, rSide //prepared arrays or spans
int vectorSize = 256 / 8 / 8;
fixed (double* lptr = lSide)
{
fixed (double* rptr = rSide)
{
for (i = 0; i < array.Length - vectorSize; i += vectorSize) {
var lVec = Avx2.LoadVector256(lptr);
var rVec = Avx2.LoadVector256(rptr);
resVector = Avx2.Subtract(lVec, rVec);
.....
}
}
}
PSS似乎我无法在memory中一一放置class的2个字段的字段:
[StructLayout(LayoutKind.Explicit)]
public sealed class SubProp
{
[FieldOffset(0)] public double subProp1;
[FieldOffset(8)] public double subProp2;
public double Sum() //just simple function for the test
{
return subProp1 + subProp2;
}
}
[StructLayout(LayoutKind.Explicit)]
public sealed class MyClass
{
[FieldOffset(0)] public SubProp prop1;
[FieldOffset(16)] public SubProp prop2;
}
MyClass testObj = new MyClass
{
prop1 = new SubProp
{
subProp1 = 10,
subProp2 = 20
},
prop2 = new SubPorp
{
subProp1 = 30,
subProp2 = 40
}
};
fixed(double* ptr = &testObj.prop1.subProp1)
{
for(int i=0; i<4; i=i+1)
{
Console.WriteLine(*(ptr+i));
}
}
输出是:
10
20
0
<garbage>
我有三个想法来优化您的代码:
1.:以下两个操作:
double res1 = data[i].prop2.subProp2 - data[j].prop1.subProp1;
double res2 = data[j].prop1.subProp1 - data[i].prop2.subProp2;
也可以写成:
double res1 = data[i].prop2.subProp2 - data[j].prop1.subProp1;
double res2 = res1 * -1; // or double res2 = -res1; Thanks to Peter Cordes for that hint...
可能的情况:
a = 5,b = 3:a - b = 2 和 b - a = -2
a = 3,b = 0:a - b = 3 和 b - a = -3
a = 0,b = 0:a - b = 0 和 b - a = 0
a = 3,b = -2:a - b = 5 和 b - a = -5
虽然我必须承认,我不知道这是否更快......
2.:您可以使用 Parallel.For 而不是 for 循环。 如果您不在下一次迭代中使用一次迭代的结果,这将是可能的。
3.:您正在多次访问您的属性。 根据您执行此操作的频率,在本地存储它们可能会有好处。 特别是那些由 i 计数器访问的。
for(int i = 0; i < cnt; i++)
{
SubProp dataIProp1 = data[i].prop1;
SubProp dataIProp2 = data[i].prop2;
for(int j = i + 1; j < cnt; j++)
{
//these substructions suppose to be optimized with SIMD
double res1 = dataIProp2.subProp2 - data[j].prop1.subProp1;
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.