我的电脑同时配备了英特尔GPU和NVIDIA GPU。后者功能更强大,是执行繁重任务时的首选设备。我需要一种方法来以编程方式确定要使用哪个设备。
我知道很难知道哪种设备最适合特定任务。我需要的是(以编程方式)使用下面列出的变量进行合格的猜测。
您如何对这两款设备进行排名? Intel HD Graphics 4400
左侧,GeForce GT 750M
位于右侧。
GlobalMemoryCacheLineSize 64 vs 128
GlobalMemoryCacheSize 2097152 vs 32768
GlobalMemorySize 1837105152 vs 4294967296
HostUnifiedMemory true vs false
Image2DMaxHeight 16384 vs 32768
Image2DMaxWidth 16384 vs 32768
Image3DMaxDepth 2048 vs 4096
Image3DMaxHeight 2048 vs 4096
Image3DMaxWidth 2048 vs 4096
LocalMemorySize 65536 vs 49152
MaxClockFrequency 400 vs 1085
MaxComputeUnits 20 vs 2
MaxConstantArguments 8 vs 9
MaxMemoryAllocationSize 459276288 vs 1073741824
MaxParameterSize 1024 vs 4352
MaxReadImageArguments 128 vs 256
MaxSamplers 16 vs 32
MaxWorkGroupSize 512 vs 1024
MaxWorkItemSizes [512, 512, 512] vs [1024, 1024, 64]
MaxWriteImageArguments 8 vs 16
MemoryBaseAddressAlignment 1024 vs 4096
OpenCLCVersion 1.2 vs 1.1
ProfilingTimerResolution 80 vs 1000
VendorId 32902 vs 4318
显然,还有数百种其他设备需要考虑。我需要一个通用的公式!
答案 0 :(得分:2)
您无法使用简单的公式从该参数计算索引。
首先让我假设您可以信任所收集的数据,当然如果您为MaxComputeUnits
读取2,但实际上它是80,那么您无能为力(除非您拥有自己的所有卡片数据库)他们的规格)。
如果您不知道必须执行的任务,您怎么能猜到?它可能是高度并行的(然后更多的单元可能更好)或原始的暴力计算(然后更高的时钟频率或更大的缓存可能更好)。至于正常线程的CPU数量不是您必须考虑并行任务的唯一因素。只需提及一些你必须考虑的事情:
简而言之:您无法以可靠的方式计算索引,因为因素太多并且它们之间存在很强的相关性(例如,高并行度可能会因为缓存较小或内存访问速度慢而导致特定指令,如果支持,即使所有其他参数都很差,也可能给你带来很好的表现。
如果您需要原始比较,您甚至可以简单地执行MaxComputeUnits * MaxClockFrequency
(对于许多应用程序甚至可能已经足够)但是如果您需要更准确的索引,那么不要认为这将是一项简单的任务并且你会得到像(a + b / 2)^2
这样的通用公式,但事实并非如此,结果将非常具体到你必须完成的任务。
编写一个小测试(尽可能与您的任务相似,查看this post on SO)并使用多张卡运行,并使用足够大的统计您可以从一组未知参数中推断索引。算法可能变得非常复杂,关于这个主题的文献很多,所以我甚至不会在这里重复它们。我将从Wikipedia article开始,总结其他更具体的论文。如果您需要一个示例,您可以阅读Exploring the Multiple-GPU Design Space。
请记住,您添加到研究中的更多变量更多的结果质量将不稳定,使用的参数越少,结果就越准确。为了更好地支持外推:
MaxGroupSize
可能不那么相关)。这个阶段非常重要,应该使用统计工具做出决策(例如,您可以计算p值)。还有许多其他需要考虑的事项,一本关于数据挖掘的好书可以帮助你写出1000多个单词。
答案 1 :(得分:2)
正如@Adriano所指出的那样,有许多事情要考虑......太多事情。 但我可以想到一些事情(以及可以做的更简单的事情)来帮助你(不是完全解决你的问题):
首先,您需要哪个版本的OCL(与性能无关)。但是如果你使用OCL 1.2的某些功能......那么问题就解决了
您通常可以(并且粗略地)将您的算法分类为以下两种类别之一:内存有界或计算有界。如果它受内存限制(主机和设备之间有很多传输)可能,最有趣的信息将是具有主机统一内存的设备。如果没有,最强大的处理器最有可能会更有趣。
但最有可能的是,选择哪种类别的应用程序并不容易。 在这种情况下,你可以做一个小的基准。粗略地说,这个基准测试会在虚拟计算上测试不同大小的数据(如果你的应用必须处理它),这些计算或多或少地与你的应用程序所需的计算量相匹配(在你完成内核开发之后由你估算)。您可以记录数据量太大的点,以便取消功能最强大但通过PCIe连接的设备。
在GPU上编程时,另一个非常重要的事情是GPU占用率。越高越好。 NVIDIA提供Excel file,根据某些输入计算占用率。基于这些概念,您可以或多或少地重现两个GPU的占用率计算(其他供应商可能需要进行一些调整),并选择最高的一个。
当然,您需要知道这些输入的值。其中一些是基于您的代码,因此您可以在手前计算它们。其中一些与GPU的规格有关。您可以像以前一样查询其中的一些,对于其他一些人,您可能需要在一些谷歌搜索后对某些文件中的值进行硬编码(但至少您不需要手上有这些GPU来测试它们)。最后但同样重要的是,不要忘记OCL提供的clGetKernelWorkGroupInfo()
可以为您提供一些信息,例如特定内核所需的本地或私有内存量。
关于本地内存的信息请注意标准中的注释:
如果是本地内存大小,则为内核的任何指针参数 用__local地址限定符声明,未指定,它 假设大小为0.
因此,这意味着如果您首先从主机端动态计算大小,则此信息可能无用。解决这个问题的方法可能是使用内核在JIT中编译的事实。这里的想法是在我解释here时调用clBuildProgram()
时使用预处理器选项-D。这会给你类似的东西:
#define SIZE
__mykernel(args){
local myLocalMem[SIZE];
....
}
毕竟是blabla。我猜你担心这个,因为你可能想把你的应用程序发送给一些用户而不知道他们有什么硬件。是否非常不方便(在安装时或者可能在提供命令或按钮之后)简单地使用虚拟生成的数据运行应用程序来测量哪个设备执行得更好并只是将其记录在配置文件中?
有时,根据您的具体问题(可能不涉及许多同步),您不必选择。有时,你可以简单地在两个设备之间拆分工作并使用两个......
答案 2 :(得分:0)
到目前为止,我很喜欢所有的解决方案。如果自动选择最佳设备非常重要,那就是如何做到这一点(根据您的使用需求对值进行加权并获得最高分)。
另外,更简单的是,只需要使用第一个 GPU设备,但也可以让用户查看兼容设备列表并进行更改(无论是立即还是在下次运行)。
这种替代方案是合理的,因为大多数系统只有一个GPU。
答案 3 :(得分:0)
为什么猜?在当天的硬件上动态选择:在“最佳”GPU上运行您希望运行的代码,并在每个可用GPU上运行少量示例数据。无论哪个先完成:在剩下的计算中使用它。