我正在尝试使用 Alea 来加速我正在开发的程序,但我需要一些帮助。
我需要做的是对存储在两个数组中的值进行大量位计数和按位运算。
对于我的第一个数组的每个元素,我必须对我的第二个数组的每个元素进行按位 & 运算,然后计算 & 结果中设置为 1 的位。
如果结果大于/等于某个值,我需要退出内部 for 并转到我的第一个数组的下一个元素。
第一个数组通常很大,有数百万个元素,第二个数组通常少于 200.000 个元素。
尝试并行执行所有这些操作,这是我的代码:
[GpuManaged]
private long[] Check(long[] arr1, long[] arr2, int limit)
{
Gpu.FreeAllImplicitMemory(true);
var gpu = Gpu.Default;
long[] result = new long[arr1.Length];
gpu.For(0, arr1.Length, i =>
{
bool found = false;
long b = arr1[i];
for (int i2 = 0; i2 < arr2.Length; i2++)
{
if (LibDevice.__nv_popcll(b & arr2[i2]) >= limit)
{
found = true;
break;
}
}
if (!found)
{
result[i] = b;
}
});
return result;
}
这按预期工作,但比我在四核 CPU 上并行运行的版本快一点。
我当然在这里遗漏了一些东西,这是我第一次尝试编写 GPU 代码。
顺便说一句,我的 NVIDIA 是 GeForce GT 740M。
编辑
下面的代码比前面的代码快 2 倍,至少在我的 PC 上是这样。非常感谢 Michael Randall 为我指明了正确的方向。
private static int[] CheckWithKernel(Gpu gpu, int[] arr1, int[] arr2, int limit)
{
var lp = new LaunchParam(16, 256);
var result = new int[arr1.Length];
try
{
using (var dArr1 = gpu.AllocateDevice(arr1))
using (var dArr2 = gpu.AllocateDevice(arr2))
using (var dResult = gpu.AllocateDevice<int>(arr1.Length))
{
gpu.Launch(Kernel, lp, arr1.Length, arr2.Length, dArr1.Ptr, dArr2.Ptr, dResult.Ptr, limit);
Gpu.Copy(dResult, result);
return result;
}
}
finally
{
Gpu.Free(arr1);
Gpu.Free(arr2);
Gpu.Free(result);
}
}
private static void Kernel(int a1, int a2, deviceptr<int> arr1, deviceptr<int> arr2, deviceptr<int> arr3, int limit)
{
var iinit = blockIdx.x * blockDim.x + threadIdx.x;
var istep = gridDim.x * blockDim.x;
for (var i = iinit; i < a1; i += istep)
{
bool found = false;
int b = arr1[i];
for (var j = 0; j < a2; j++)
{
if (LibDevice.__nv_popcll(b & arr2[j]) >= limit)
{
found = true;
break;
}
}
if (!found)
{
arr3[i] = b;
}
}
}