C++ AMP 库对 F# 有用吗?
Posted
技术标签:
【中文标题】C++ AMP 库对 F# 有用吗?【英文标题】:Is the C++ AMP library useful from F#? 【发布时间】:2012-12-24 07:04:38 【问题描述】:我正在尝试使用 F# 中的 C++ AMP 库作为使用 GPU 进行并行工作的一种方式。但是,我得到的结果似乎并不直观。
在 C++ 中,我用一个函数创建了一个库,该函数使用 AMP 对数组中的所有数字求平方:
extern "C" __declspec ( dllexport ) void _stdcall square_array(double* arr, int n)
// Create a view over the data on the CPU
array_view<double,1> dataView(n, &arr[0]);
// Run code on the GPU
parallel_for_each(dataView.extent, [=] (index<1> idx) restrict(amp)
dataView[idx] = dataView[idx] * dataView[idx];
);
// Copy data from GPU to CPU
dataView.synchronize();
(代码改编自 Igor Ostrovsky 在 MSDN 上的 blog。)
然后我编写了以下 F# 来将任务并行库 (TPL) 与 AMP 进行比较:
// Print the time needed to run the given function
let time f =
let s = new Stopwatch()
s.Start()
f ()
s.Stop()
printfn "elapsed: %d" s.ElapsedTicks
module CInterop =
[<DllImport("CPlus", CallingConvention = CallingConvention.StdCall)>]
extern void square_array(float[] array, int length)
let options = new ParallelOptions()
let size = 1000.0
let arr = [|1.0 .. size|]
// Square the number at the given index of the array
let sq i =
do arr.[i] <- arr.[i] * arr.[i]
()
// Square every number in the array using TPL
time (fun() -> Parallel.For(0, arr.Length - 1, options, new Action<int>(sq)) |> ignore)
let arr2 = [|1.0 .. size|]
// Square every number in the array using AMP
time (fun() -> CInterop.square_array(arr2, arr2.Length))
如果我将数组大小设置为 10 这样的微不足道的数字,则完成 TPL ~22K 滴答声和 AMP ~10K 滴答声。这就是我所期望的。据我了解,GPU(因此是 AMP)应该比 TPL 更适合这种情况,在这种情况下,工作被分解成非常小的部分。
但是,如果我将数组大小增加到 1000,TPL 现在需要约 30K 滴答,而 AMP 需要约 70K 滴答。从那里开始变得更糟。对于 100 万大小的数组,AMP 所需的时间几乎是 TPL 的 1000 倍。
由于我希望 GPU(即 AMP)能够更好地完成此类任务,我想知道我在这里缺少什么。
我的显卡是 1GB 的 GeForce 550 Ti,据我所知,还算不错。我知道使用 PInvoke 调用 AMP 代码会产生开销,但我希望这是一个固定成本,可以在更大的数组大小上摊销。我相信该数组是通过引用传递的(尽管我可能是错的),所以我不认为复制它会产生任何成本。
感谢大家的建议。
【问题讨论】:
您可能也对此感兴趣,registration.gputechconf.com/quicklink/5bCFSh3,S3055 - 带 F# 的动态 CUDA - .NET 上 GPU 计算的新维度 【参考方案1】:在 GPU 和 CPU 之间来回传输数据需要时间。您很可能在这里测量您的 PCI Express 总线带宽。对 1M 的浮点数求平方对于 GPU 来说是小菜一碟。
使用 Stopwach
类来衡量 AMP 的性能也不是一个好主意,因为 GPU 调用可能异步发生。在您的情况下没关系,但如果您只测量计算部分(parallel_for_each
),这将不起作用。我认为您可以为此使用 D3D11 性能计数器。
【讨论】:
谢谢斯金格。我将在 C++ 代码中添加更多计时器,以查看确切花费的时间(感谢有关性能计数器的提示)。所有人的问题:如果是带宽问题,是否有某种方法可以优化与 GPU 之间的数据传输?也就是说,如果游戏真的因此而受到性能影响,他们就不会费心使用我的 GPU,我假设他们正在做一些我没有做的事情。 @FSharpN00b 这是一个相当大的问题。一种方法是逐步将数据移动到 gpu,以便 gpu 在等待其余数据的同时做一些工作 @mydogisbox 是的,这是通过与计算重叠来隐藏数据传输的有效策略。 谢谢 mydogisbox 和 Ade。听起来好像我应该坚持 TPL,只担心在我用尽 CPU(这不太可能)之后将数据异步移动到 GPU,而不是先尝试去 GPU。感谢大家的回复。以上是关于C++ AMP 库对 F# 有用吗?的主要内容,如果未能解决你的问题,请参考以下文章
Linux系统编程(文件)———文件编程应用(配置文件修改,写结构体数组到文件),标准C库对文件的操作
Linux系统编程(文件)———文件编程应用(配置文件修改,写结构体数组到文件),标准C库对文件的操作