如何根据数组索引从数组复制到 Vector256,反之亦然?
How to copy from an array to a Vector256 and vice versa based on the array index?
假设我有一个 int[]
数组或 Vector256<int>
s。如何使用数组索引将值从一个复制到另一个?
目前我必须遍历数组索引并一一复制值:
int[] input = ...; // length divisible by Vector256<int>.Count
int[] output = new int[intput.Length];
for (int i = 0; i < input.Length; i += Vector256<int>.Count)
{
Vector256<int> v = Vector256.Create(
array[i], array[i + 1], array[i + 2], array[i + 3],
array[i + 4], array[i + 5], array[i + 6], array[i + 7]);
Vector256<int> v2 = DoSomeWork(v);
for (int j = 0; j < Vector256<int>.Count; ++j)
{
output[i + j] = v2.GetElement(i + j);
}
}
在Java SDK 16中,有一些功能可以完全满足我的需要。 C#有没有类似的功能?
int[] input = ...;
int[] output = new int[values.length];
for (int i = 0; i < input.length; i += IntVector.SPECIES_256.length()) {
IntVector v = IntVector.fromArray(IntVector.SPECIES_256, input, i);
IntVector v2 = DoSomeWork(v);
v2.intoArray(output, i);
}
您可以使用 System.Numerics
中的 Vector
。像这样:
var vector = new Vector<int>(new Span<int>(ints, i, 8));
Vector256<int> v = vector.AsVector256();
......
v2.AsVector().CopyTo(output, i);
您也可以尝试直接使用 System.Numerics.Vector
进行计算。
也可以使用 System.Runtime.Intrinsics.X86
中的 unsafe
with Avx.LoadVector256
和 Avx.Store
。像这样:
fixed (int* ptr = input)
fixed (int* ptrRes = output)
{
var vectorCount = Vector256<int>.Count;
for (int i = 0; i <= input.Length - vectorCount; i += vectorCount)
{
var v = Avx.LoadVector256(ptr + i);
....
Avx.Store(ptrRes + i, v2);
}
}
另一个解决方案。
int[] input = ...;
int[] output = new int[input.Length];
Span<Vector256<int>> inputVectors = MemoryMarshal.Cast<int, Vector256<int>>(input);
Span<Vector256<int>> outputVectors = MemoryMarshal.Cast<int, Vector256<int>>(output);
for (int i = 0; i < inputVectors.Length; i++)
outputVectors[i] = DoSomeWork(inputVectors[i]);
结果将自动在 output
数组中。
不安全版本
int[] input = ...;
int[] output = new int[input.Length];
fixed (int* inPtr = input, outPtr = output)
{
Vector256<int>* src = (Vector256<int>*)inPtr;
Vector256<int>* dst = (Vector256<int>*)outPtr;
Vector256<int>* srcEnd = src + (input.Length >> 3);
while (src < srcEnd)
{
*dst = DoSomeWork(*src);
src++;
dst++;
}
}
所有 3 种解决方案:从已接受的答案来看都是不安全的,并且上述两种解决方案的性能几乎相同。
假设我有一个 int[]
数组或 Vector256<int>
s。如何使用数组索引将值从一个复制到另一个?
目前我必须遍历数组索引并一一复制值:
int[] input = ...; // length divisible by Vector256<int>.Count
int[] output = new int[intput.Length];
for (int i = 0; i < input.Length; i += Vector256<int>.Count)
{
Vector256<int> v = Vector256.Create(
array[i], array[i + 1], array[i + 2], array[i + 3],
array[i + 4], array[i + 5], array[i + 6], array[i + 7]);
Vector256<int> v2 = DoSomeWork(v);
for (int j = 0; j < Vector256<int>.Count; ++j)
{
output[i + j] = v2.GetElement(i + j);
}
}
在Java SDK 16中,有一些功能可以完全满足我的需要。 C#有没有类似的功能?
int[] input = ...;
int[] output = new int[values.length];
for (int i = 0; i < input.length; i += IntVector.SPECIES_256.length()) {
IntVector v = IntVector.fromArray(IntVector.SPECIES_256, input, i);
IntVector v2 = DoSomeWork(v);
v2.intoArray(output, i);
}
您可以使用 System.Numerics
中的 Vector
。像这样:
var vector = new Vector<int>(new Span<int>(ints, i, 8));
Vector256<int> v = vector.AsVector256();
......
v2.AsVector().CopyTo(output, i);
您也可以尝试直接使用 System.Numerics.Vector
进行计算。
也可以使用 System.Runtime.Intrinsics.X86
中的 unsafe
with Avx.LoadVector256
和 Avx.Store
。像这样:
fixed (int* ptr = input)
fixed (int* ptrRes = output)
{
var vectorCount = Vector256<int>.Count;
for (int i = 0; i <= input.Length - vectorCount; i += vectorCount)
{
var v = Avx.LoadVector256(ptr + i);
....
Avx.Store(ptrRes + i, v2);
}
}
另一个解决方案。
int[] input = ...;
int[] output = new int[input.Length];
Span<Vector256<int>> inputVectors = MemoryMarshal.Cast<int, Vector256<int>>(input);
Span<Vector256<int>> outputVectors = MemoryMarshal.Cast<int, Vector256<int>>(output);
for (int i = 0; i < inputVectors.Length; i++)
outputVectors[i] = DoSomeWork(inputVectors[i]);
结果将自动在 output
数组中。
不安全版本
int[] input = ...;
int[] output = new int[input.Length];
fixed (int* inPtr = input, outPtr = output)
{
Vector256<int>* src = (Vector256<int>*)inPtr;
Vector256<int>* dst = (Vector256<int>*)outPtr;
Vector256<int>* srcEnd = src + (input.Length >> 3);
while (src < srcEnd)
{
*dst = DoSomeWork(*src);
src++;
dst++;
}
}
所有 3 种解决方案:从已接受的答案来看都是不安全的,并且上述两种解决方案的性能几乎相同。