【问题标题】:How to call a GPU task periodically using Hybridizer如何使用 Hybridizer 定期调用 GPU 任务
【发布时间】:2020-06-30 21:37:05
【问题描述】:

我正在尝试使用混合器在 C# 中使用 GPU 进行计算。我尝试使用 Altimesh Hybridizer 将我的 GPU 代码嵌入到 .NET 库中。我们称它为 GPU_DLL。

这个库必须在另一个项目中使用,我们称之为Test_GPU_Caller。 GPU 代码使用定时器定期调用,如下代码所示:

class Program
{

    static GPU_DLL.GPU_DLL gpuDllTest = new GPU_DLL.GPU_DLL();

    static void Main(string[] args)
    {
        Timer tmr = new Timer(100);
        tmr.Elapsed += Tmr_Elapsed;
        tmr.Start();

        while (true) ;
    }
    private static void Tmr_Elapsed(object sender, ElapsedEventArgs e)
    {
        gpuDllTest.Test("GPU_DLL_CUDA.dll");
    }

}

测试功能在 .NET 库中实现,代码如下:

public class GPU_DLL
{
    [EntryPoint("run")]
    public void Run(int N, double[] a, double[] b)
    {
        Parallel.For(0, N, i => { a[i] += b[i]; });
    }

    public void Test(string dllName)
    {
        // 268 MB allocated on device -- should fit in every CUDA compatible GPU
        int N = 1024 * 1024 * 16;
        double[] acuda = new double[N];
        double[] adotnet = new double[N];

        double[] b = new double[N];

        Random rand = new Random();

        //Initialize acuda et adotnet and b by some doubles randoms, acuda and adotnet have same numbers. 
        for (int i = 0; i < N; ++i)
        {
            acuda[i] = rand.NextDouble();
            adotnet[i] = acuda[i];
            b[i] = rand.NextDouble();
        }

        cudaDeviceProp prop;
        cuda.GetDeviceProperties(out prop, 0);
        HybRunner runner = HybRunner.Cuda(dllName).SetDistrib(prop.multiProcessorCount * 16, 128);

        // create a wrapper object to call GPU methods instead of C#
        dynamic wrapped = runner.Wrap(this);

        // run the method on GPU
        wrapped.Run(N, acuda, b);

        // run .Net method
        Run(N, adotnet, b);

        // verify the results
        for (int k = 0; k < N; ++k)
        {
            if (acuda[k] != adotnet[k])
                Console.Out.WriteLine("ERROR !");
        }
        Console.Out.WriteLine("DONE");
        //Thread.Sleep(10000);
    }
}

GPU_DLL 已被首先混合并编译。当我启动程序时,我收到一个错误: System.ArgumentException:'Un élément avec la meme clé a déjà été ajouté。 (法语...)

有人知道如何使用 Hybridizer 定期调用的 GPU 代码吗?欢迎提供示例项目;)

最好的问候, 瓦伦丁

【问题讨论】:

  • 法语中的错误与您的语言环境有关。 (这是一个未捕获的系统异常)。

标签: c# hybridizer


【解决方案1】:

您面临的问题似乎与计时器在第一次调用完成之前第二次调用该函数有关。根据文档,您的计时器设置将每 100 毫秒调用一次计时器函数回调,但它不会等待上一次运行完成(在我的系统上运行它需要 1.3 秒进行第一次迭代,随后调用约 650 毫秒)。

HybRunner 不是线程安全的。另外,请注意 CUDA 上下文附加到一个线程,使用另一个线程需要另一个 CUDA 上下文。

以下是使用执行 GPU 相关任务的工作线程来解决您的问题的替代实现:

首先,声明同步组件:

    static bool workerrunning = false;
    static object started = new object();

    static Queue<object> tasks = new Queue<object>();
    static object watch = new object();

工作线程循环可能如下:

    public static void HybridLoop(object p)
    {
        lock (started)
        {
            workerrunning = true;
            Monitor.Pulse(started);
        }
        while (workerrunning)
        {
            object currenttask = null;
            // get next task
            lock (watch)
            {
                if (tasks.Count == 0)
                {
                    Monitor.Wait(watch);
                }
                if (tasks.Count != 0)
                {
                    currenttask = tasks.Dequeue();
                    // NOTE: here, we illustrate more tasks than doable => clear
                    tasks.Clear();
                }
            }

            if (currenttask != null)
            {
                gpuDllTest.Test("GPU_DLL_CUDA.dll");
            }
        }
    }

在这里,我们清除任务队列,因为它的填充速度比消耗速度快。

启动工作线程的代码:

        System.Threading.Thread hybridrunner = new System.Threading.Thread(HybridLoop);
        lock(started)
        {
            hybridrunner.Start();
            Monitor.Wait(started);
        }

一旦worker启动,就可以启动定时器了:

        System.Timers.Timer tmr = new System.Timers.Timer(100);
        tmr.Elapsed += Tmr_Elapsed;
        tmr.Start();

        Console.Out.WriteLine("Runner started - press return to stop");
        var key = Console.Read();

您的计时器计时功能只是一个任务入队:

    private static void Tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        lock (watch)
        {
            tasks.Enqueue(1);
            Monitor.Pulse(watch);
        }
    }

完成后,可以停止运行器以避免线程拖尾:

        workerrunning = false;
        lock (watch)
        {
            tmr.Stop();
            tasks.Enqueue(0);
            Monitor.Pulse(watch);
        }
        Console.Out.WriteLine("Runner stopping");

        hybridrunner.Join();

        Console.Out.WriteLine("Runner stopped");

示例执行日志:

DONE
Execution took 1026 milliseconds
DONE
Execution took 642 milliseconds
DONE
Execution took 614 milliseconds
Runner started - press return to stop
DONE
DONE
DONE

Runner stopping
DONE
Runner stopped

最后一点,您可能希望只进行一次初始化,例如 HybRunner.Cuda(),然后在同一个工作线程中执行其他任务。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 2019-01-15
    相关资源
    最近更新 更多