尝试使用 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, FSharpOption1 lengthOpt)
at Alea.ImplicitMemoryTrackerEntry.cdd2cd00c052408bcdbf03958f14266ca(FSharpFunc2 c600c458623dca7db199a0e417603dff4, Object cd5116337150ebaa6de788dacd82516fa) at Alea.ImplicitMemoryTrackerEntry.c6a75c171c9cccafb084beba315394985(FSharpFunc2 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, IEnumerable1 source) at Alea.Kernel.LaunchRaw(LaunchParam lp, FSharpOption1 instanceOpt, FSharpList1 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, Action1 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[] 只在内核代码中使用。