尝试使用 Alea GPU 查找大素数
Trying to find large prime numbers with Alea GPU
当我尝试使用Alea GPU 查找第100,000 个素数时出现异常。如果我试图找到一个较小的素数,该算法工作正常,例如第 10,000 个质数。
我正在使用 Alea v3.0.4、NVIDIA GTX 970、Cuda 9.2 驱动程序。
我是 GPU 编程新手。任何帮助将不胜感激。
long[] primeNumber = new long[1]; // nth prime number to find
int n = 100000; // find the 100,000th prime number
var worker = Gpu.Default; // GTX 970 CUDA v9.2 drivers
long count = 0;
worker.LongFor(count, n, x =>
{
long a = 2;
while (count < n)
{
long b = 2;
long prime = 1;
while (b * b <= a)
{
if (a % b == 0)
{
prime = 0;
break;
}
b++;
}
if (prime > 0)
{
count++;
}
a++;
}
primeNumber[0] = (a - 1);
}
);
异常详情如下:
System.Exception occurred HResult=0x80131500 Message=[CUDAError]
CUDA_ERROR_LAUNCH_FAILED Source=Alea StackTrace: at
Alea.CUDAInterop.cuSafeCall@2939.Invoke(String message) at
Alea.CUDAInterop.cuSafeCall(cudaError_enum result) at
A.cf5aded17df9f7cc4c132234dda010fa7.Copy@918-22.Invoke(Unit _arg9)
at Alea.Memory.Copy(FSharpOption1 streamOpt, Memory src, IntPtr
srcOffset, Memory dst, IntPtr dstOffset, FSharpOption
1 lengthOpt)
at
Alea.ImplicitMemoryTrackerEntry.cdd2cd00c052408bcdbf03958f14266ca(FSharpFunc2
c600c458623dca7db199a0e417603dff4, Object
cd5116337150ebaa6de788dacd82516fa) at
Alea.ImplicitMemoryTrackerEntry.c6a75c171c9cccafb084beba315394985(FSharpFunc
2
c600c458623dca7db199a0e417603dff4, Object
cd5116337150ebaa6de788dacd82516fa) at
Alea.ImplicitMemoryTracker.HostReadWriteBarrier(Object instance) at
Alea.GlobalImplicitMemoryTracker.HostReadWriteBarrier(Object instance)
at A.cf5aded17df9f7cc4c132234dda010fa7.clo@2359-624.Invoke(Object
arg00) at
Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc2 action,
IEnumerable
1 source) at Alea.Kernel.LaunchRaw(LaunchParam lp,
FSharpOption1 instanceOpt, FSharpList
1 args) at
Alea.Parallel.Device.DeviceFor.For(Gpu gpu, Int64 fromInclusive, Int64
toExclusive, Action1 op) at Alea.Parallel.GpuExtension.LongFor(Gpu
gpu, Int64 fromInclusive, Int64 toExclusive, Action
1 op) at
TestingGPU.Program.Execute(Int32 t) in
C:\Users..\source\repos\TestingGPU\TestingGPU\Program.cs:line 148
at TestingGPU.Program.Main(String[] args)
工作解决方案:
static void Main(string[] args)
{
var devices = Device.Devices;
foreach (var device in devices)
{
Console.WriteLine(device.ToString());
}
while (true)
{
Console.WriteLine("Enter a number to check if it is a prime number:");
string line = Console.ReadLine();
long checkIfPrime = Convert.ToInt64(line);
Stopwatch sw = new Stopwatch();
sw.Start();
bool GPUisPrime = GPUIsItPrime(checkIfPrime+1);
sw.Stop();
Stopwatch sw2 = new Stopwatch();
sw2.Start();
bool CPUisPrime = CPUIsItPrime(checkIfPrime+1);
sw2.Stop();
Console.WriteLine($"GPU: is {checkIfPrime} prime? {GPUisPrime} Time Elapsed: {sw.ElapsedMilliseconds.ToString()}");
Console.WriteLine($"CPU: is {checkIfPrime} prime? {CPUisPrime} Time Elapsed: {sw2.ElapsedMilliseconds.ToString()}");
}
}
[GpuManaged]
private static bool GPUIsItPrime(long n)
{
//Sieve of Eratosthenes Algorithm
bool[] isComposite = new bool[n];
var worker = Gpu.Default;
worker.LongFor(2, n, i =>
{
if (!(isComposite[i]))
{
for (long j = 2; (j * i) < isComposite.Length; j++)
{
isComposite[j * i] = true;
}
}
});
return !isComposite[n-1];
}
private static bool CPUIsItPrime(long n)
{
//Sieve of Eratosthenes Algorithm
bool[] isComposite = new bool[n];
for (int i = 2; i < n; i++)
{
if (!isComposite[i])
{
for (long j = 2; (j * i) < n; j++)
{
isComposite[j * i] = true;
}
}
}
return !isComposite[n-1];
}
您的代码看起来不正确。在这里给定一个并行 for 循环方法 (LongFor),Alea 将生成 "n" 个线程,索引 "x" 用于标识线程号是什么。因此,例如一个简单的例子,例如 For(0, n, x => a[x] = x);使用 "x" 以 { 0, 1, 2, ...., n - 1} 初始化 a[]。但是,您的内核代码没有在代码的任何地方使用 "x" 。因此,您 运行 次相同的代码 "n" 次,完全没有区别。那么为什么 运行 在 GPU 上呢?我想你想要做的是在线程 "x" 中计算 "x" 是否是质数。有了结果,设置 bool prime[x] = true 或 false。然后,之后,在内核中添加一个同步调用,然后使用单个线程(例如 x == 0)进行测试以遍历 prime[] 并从数组中选择最大的素数。否则,GPU 上的 n 线程会为 'primeNumber[0] = (a - 1);' 发生很多冲突。我无法想象您将如何获得正确的结果。最后,您可能想确保使用 Alea 调用 prime[] 永远不会复制 to/from GPU。但是,我不知道你如何在 Alea 中做到这一点。编译器可能足够聪明,知道 prime[] 只在内核代码中使用。
当我尝试使用Alea GPU 查找第100,000 个素数时出现异常。如果我试图找到一个较小的素数,该算法工作正常,例如第 10,000 个质数。
我正在使用 Alea v3.0.4、NVIDIA GTX 970、Cuda 9.2 驱动程序。
我是 GPU 编程新手。任何帮助将不胜感激。
long[] primeNumber = new long[1]; // nth prime number to find
int n = 100000; // find the 100,000th prime number
var worker = Gpu.Default; // GTX 970 CUDA v9.2 drivers
long count = 0;
worker.LongFor(count, n, x =>
{
long a = 2;
while (count < n)
{
long b = 2;
long prime = 1;
while (b * b <= a)
{
if (a % b == 0)
{
prime = 0;
break;
}
b++;
}
if (prime > 0)
{
count++;
}
a++;
}
primeNumber[0] = (a - 1);
}
);
异常详情如下:
System.Exception occurred HResult=0x80131500 Message=[CUDAError] CUDA_ERROR_LAUNCH_FAILED Source=Alea StackTrace: at Alea.CUDAInterop.cuSafeCall@2939.Invoke(String message) at Alea.CUDAInterop.cuSafeCall(cudaError_enum result) at A.cf5aded17df9f7cc4c132234dda010fa7.Copy@918-22.Invoke(Unit _arg9)
at Alea.Memory.Copy(FSharpOption1 streamOpt, Memory src, IntPtr srcOffset, Memory dst, IntPtr dstOffset, FSharpOption
1 lengthOpt)
at Alea.ImplicitMemoryTrackerEntry.cdd2cd00c052408bcdbf03958f14266ca(FSharpFunc2 c600c458623dca7db199a0e417603dff4, Object cd5116337150ebaa6de788dacd82516fa) at Alea.ImplicitMemoryTrackerEntry.c6a75c171c9cccafb084beba315394985(FSharpFunc
2 c600c458623dca7db199a0e417603dff4, Object cd5116337150ebaa6de788dacd82516fa) at Alea.ImplicitMemoryTracker.HostReadWriteBarrier(Object instance) at Alea.GlobalImplicitMemoryTracker.HostReadWriteBarrier(Object instance) at A.cf5aded17df9f7cc4c132234dda010fa7.clo@2359-624.Invoke(Object arg00) at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc2 action, IEnumerable
1 source) at Alea.Kernel.LaunchRaw(LaunchParam lp, FSharpOption1 instanceOpt, FSharpList
1 args) at Alea.Parallel.Device.DeviceFor.For(Gpu gpu, Int64 fromInclusive, Int64 toExclusive, Action1 op) at Alea.Parallel.GpuExtension.LongFor(Gpu gpu, Int64 fromInclusive, Int64 toExclusive, Action
1 op) at TestingGPU.Program.Execute(Int32 t) in C:\Users..\source\repos\TestingGPU\TestingGPU\Program.cs:line 148
at TestingGPU.Program.Main(String[] args)
工作解决方案:
static void Main(string[] args)
{
var devices = Device.Devices;
foreach (var device in devices)
{
Console.WriteLine(device.ToString());
}
while (true)
{
Console.WriteLine("Enter a number to check if it is a prime number:");
string line = Console.ReadLine();
long checkIfPrime = Convert.ToInt64(line);
Stopwatch sw = new Stopwatch();
sw.Start();
bool GPUisPrime = GPUIsItPrime(checkIfPrime+1);
sw.Stop();
Stopwatch sw2 = new Stopwatch();
sw2.Start();
bool CPUisPrime = CPUIsItPrime(checkIfPrime+1);
sw2.Stop();
Console.WriteLine($"GPU: is {checkIfPrime} prime? {GPUisPrime} Time Elapsed: {sw.ElapsedMilliseconds.ToString()}");
Console.WriteLine($"CPU: is {checkIfPrime} prime? {CPUisPrime} Time Elapsed: {sw2.ElapsedMilliseconds.ToString()}");
}
}
[GpuManaged]
private static bool GPUIsItPrime(long n)
{
//Sieve of Eratosthenes Algorithm
bool[] isComposite = new bool[n];
var worker = Gpu.Default;
worker.LongFor(2, n, i =>
{
if (!(isComposite[i]))
{
for (long j = 2; (j * i) < isComposite.Length; j++)
{
isComposite[j * i] = true;
}
}
});
return !isComposite[n-1];
}
private static bool CPUIsItPrime(long n)
{
//Sieve of Eratosthenes Algorithm
bool[] isComposite = new bool[n];
for (int i = 2; i < n; i++)
{
if (!isComposite[i])
{
for (long j = 2; (j * i) < n; j++)
{
isComposite[j * i] = true;
}
}
}
return !isComposite[n-1];
}
您的代码看起来不正确。在这里给定一个并行 for 循环方法 (LongFor),Alea 将生成 "n" 个线程,索引 "x" 用于标识线程号是什么。因此,例如一个简单的例子,例如 For(0, n, x => a[x] = x);使用 "x" 以 { 0, 1, 2, ...., n - 1} 初始化 a[]。但是,您的内核代码没有在代码的任何地方使用 "x" 。因此,您 运行 次相同的代码 "n" 次,完全没有区别。那么为什么 运行 在 GPU 上呢?我想你想要做的是在线程 "x" 中计算 "x" 是否是质数。有了结果,设置 bool prime[x] = true 或 false。然后,之后,在内核中添加一个同步调用,然后使用单个线程(例如 x == 0)进行测试以遍历 prime[] 并从数组中选择最大的素数。否则,GPU 上的 n 线程会为 'primeNumber[0] = (a - 1);' 发生很多冲突。我无法想象您将如何获得正确的结果。最后,您可能想确保使用 Alea 调用 prime[] 永远不会复制 to/from GPU。但是,我不知道你如何在 Alea 中做到这一点。编译器可能足够聪明,知道 prime[] 只在内核代码中使用。