如何在C#中对浮点数数组进行对齐?

4

我想在C#中将一个浮点数数组对齐到16字节边界。

我知道的一种技术是钉住数组: http://meekmaak.blogspot.ca/2010/06/c-memory-aligned-array-wrapper-for-fast.html

我不喜欢钉住内存的想法。我担心它可能会影响垃圾回收的性能。

还有其他技术吗?我正在考虑创建一个16字节结构,分配一个由此结构组成的数组,然后将该数组转换为浮点数数组。

[StructLayout(LayoutKind.Explicit)]
public struct Float4 {
    [FieldOffset(0)]  public float X;
    [FieldOffset(4)]  public float Y;
    [FieldOffset(8)]  public float Z;
    [FieldOffset(12)] public float W;
}  

我不确定下一步该怎么做(不同类型数组之间的转换),以及最好的方法是什么?


那个结构对我来说看起来像是4字节对齐。使用FieldOffset似乎毫无意义。你认为编译器会以什么方式布局呢?你链接的代码看起来很合理。我不认为你会在托管类型上取得任何进展。为什么.NET会将你的结构体对齐到16字节边界上呢?本机代码在这里表现得非常好。 - David Heffernan
顺便提一下:C#不是C++。在C#中,将byte[]强制转换为float[]的想法并不像那样起作用。此外,StructLayout属性不能固定结构体... - user2819245
你为什么要尝试将其对齐到16B边界? - Nishmaster
1个回答

1

根据你所做的事情,使用具有明确布局结构可能是有意义的,其中至少包括一个 longdouble 与你的 float 变量叠加(我认为验证器会允许这样做,但我不确定),或者使用一些手动管理的内存。如果一个包含约22,000个浮点数的数组将分配在大对象堆上;我记得一个包含2,000个浮点数的数组也将按照同样的方式对齐,但我不知道这种处理是否适用于64位系统,或者是否适用于包含双精度数的结构体数组。如果你的数组不足以“属于”大对象堆,则可能需要分配一个大数组,并手动将其分配给各种消费者。

在某些版本的.NET上,可能可以分配带有三个额外元素的数组,并使用一个接受float引用的DLL,报告其地址的位2-3,并在数组中移动浮点数以确保正确对齐(例如,如果您想要256个值的数组,则分配259个,如果DLL报告arr[0]位于地址0x12345ABC处,则使用数组槽#1-#256)。这种方法的困难在于GC可能会不时地移动事物,因此可能必须定期将元素向上或向下移动以纠正它们的对齐方式。此外,我不知道是否可能强制执行marshaller进行真正的“按引用传递”,而不是替换“按值结果传递”[后者传递临时缓冲区的地址,而不是数组元素]。据我了解,某些版本的.NET容易进行这种替换。

个人感到困惑的是,为什么.NET没有大力调整大多数对象的缓存线对齐。 盲目使对象填充到下一个16字节倍数最多会浪费额外60%的空间(最坏情况是将20字节对象填充到32字节); 添加一些特殊情况逻辑以处理12、20和24字节的对象可以将最坏情况的开销降低到14%。 由于大多数对象用法都需要先访问其类型引用,在同一缓存行中有前几个字节的字段数据似乎会提高性能。


添加 long 或 double 通常只会导致对齐在 8 字节边界上,对吗? - cdiggins
@cdiggins:是的。我猜可能会这样,但是一个由2000个或更多double组成的数组将被分配到大对象堆上。LOH分配可以满足要求;我不知道为什么没有明确请求它的方法。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接