繁体   English   中英

在 c# 中为 Vector256 准备数据的最快方法是什么

[英]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>
    }
  }
}

我已经尝试过的:

  1. 在循环内构建 4 个双打的跨度(非常慢)

  2. 在循环外分配 3 个 Span(左、右用于减法,第 3 个用于结果),并在循环内用数字填充它们(非常慢)

  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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM