基于 SIMD 的算法实现的复杂性比较
Posted
技术标签:
【中文标题】基于 SIMD 的算法实现的复杂性比较【英文标题】:Complexity comparision of SIMD based algorithm implemenation [closed] 【发布时间】:2017-07-03 18:08:36 【问题描述】:我只是想知道,用 SSE3 和 CUDA 两种不同的 SIMD 实现的算法的复杂性测量方法是什么。通常我们将算法复杂度与 Big-O 表示法进行比较。有没有这样的方法可以将运行时改进与 SIMD 进行比较?
如果有人问如果你在 GPU 上运行一个算法会改进多少。你能从理论上测量它吗?无需在 CPU 和 GPU 上运行基准测试。 ?
注意:我了解 Big-O 是什么。所以,我只想知道 SSE3 与 CUDA 或基于 CPU 的相同算法的实现相比如何执行,而无需原始基准测试
【问题讨论】:
【参考方案1】:Big-O 表示法在大多数情况下不适用于 CPU 指令。
指令属于低级硬件的领域,计算机的不洁肉体。计算机科学并不关心这些粗略的概念。
(实际上,“计算机科学”这个词用词不当。有一句广为流传的名言“计算机科学与计算机无关,就像天文学与望远镜有关。”这句话被误认为是 Edsger Dijkstra,但实际上它来自 Michael R. Fellows,请在此处阅读:https://en.wikiquote.org/wiki/Computer_science)
无论如何,如果您坚持认为算法是由 CPU 指令执行的,并且如果您还坚持推理指令的运行时复杂性,那么您必须考虑内存访问。
您需要首先提出一些在 SSE3 和 CUDA 之间可比较的“工作单元”,然后您需要设置一些机制以便您可以测量
SSE3 的内存访问次数如何随着工作量的增加而增加,以及
相对于相同的工作量,CUDA 的内存访问次数如何增加。
这将很难实现,我的猜测是结果将是相当线性的,这意味着无论哪一个访问更多或更少的内存访问,访问次数都会相对于在这两种情况下都有工作要做。
【讨论】:
所以如果我问你,如果你在 GPU 上运行一个算法会改进多少。你能从理论上测量它吗?无需在 CPU 和 GPU 上运行基准测试。 ? 算法不会根据您运行它们的位置而改进。别介意你的问题的不幸措辞,它甚至比这更深:算法的运行时复杂性不会随着你运行它的位置而提高。 我可以理解大哦,我们无法衡量它。没关系,那么当我们将一个基于 SIMD 或 GPU 的实现转移到时,我们将如何证明它在理论上会在 cpu 上的串行执行时运行得更快。即使我们可以证明我们正在并行执行,如何在没有原始基准的情况下表示两种不同类型的 SIMD 实现的性能比较。谢谢 对。我很高兴我们得到了很大的帮助。因此,您只想知道 SSE3 与 CUDA 相比的性能如何。这是一项技术探索,而不是科学探索。所以,答案是:我不知道除了原始基准之外的任何方法。您可以阅读制造商的技术手册并尝试根据他们的描述进行推理,但我不会太重视。 “所以,您只想知道 SSE3 与基于 CUDA/CPU 的实现相比的性能如何”- 是的,我只是在寻找这个问题的答案。并感谢您的解释。【参考方案2】:Big-O 通常表示算法如何随着所考虑的项目数 N 的增长而扩展。
因此,对于 O(N) 算法,如果您有 10 倍的数据,您预计大约 10 倍的运行时间。如果您有一个 O(n log₂ n) 算法,那么 10 倍的数据可以为您提供大约 33 倍的工作量。
粗略地说,CUDA 和 GPU 可以跨 p 核并行化操作。完成的总工作然后由W=pt
给出,其中 p 是核心数量,t
是每个核心操作的时间复杂度。例如,您可以使用 √N 个处理器对 N 个项目进行排序,每个处理器执行 O(√N log N) 个工作。该算法的总时间复杂度仍然是O(N log N),但该算法被认为是“工作效率高”,因为它的总时间复杂度与最佳相同(或小于)已知的串行算法。所以 Big-O 分析可以告诉你一些关于算法如何在并行环境中运行的信息。
但是,它不是您要寻找的工具。 Big-O 用于讨论算法如何扩展:它无法告诉我们算法将如何在不同的硬件上执行。
对于性能的理论方法,您需要研究Amdahl's law 和Gustafson's law,它们提供了简单的度量标准,说明当程序资源增加时我们可以预期程序的改进程度。他们都归结为承认速度的总体提高是我们可以加速的程序部分和我们可以加速的数量的函数。
你能做得更好吗?是的。您可以使用更复杂的模型来确定您的代码在不同环境中的执行情况,查看roofline model (alternative link) 可能会帮助您入门。
除此之外,您的问题过于具体,无法在此处得到很好的回答。运行基准测试可能是您个人的最佳选择。
【讨论】:
【参考方案3】:一些答案(也许还有您的问题)反映了对 Big-O 的基本误解。 O(f(n))
只是数学函数的分类。它与运行时间或其他任何东西先验无关。 The definition of big-O 说得很清楚。
当然,有了正确的数学机制,你所问的肯定是可能的。
要在算法上下文中使用 big-O,您必须首先描述您要分类的函数。一个经典的例子是排序算法。这里经常使用的函数是比较次数f(n)
需要对给定长度n
的列表进行排序。当我们(相当不准确地)说排序算法是O(n log n)
时,我们通常是说当n
足够大时,排序所需的比较次数以K n log(n)
为上限,其中K
是一些正数常数。
你也可以在run time的上下文中使用big-O,但是你还必须规定一个正式的机器模型。这是对真实机器的数学精确抽象。其中有很多。对于许多不涉及并行处理的目的,使用Word RAM 或Real RAM,但还有其他选项。
当我们说“算法是 O(g(n))
”时,我们真正的意思是,大多数时候,“在大小为 n
的输入上运行算法所需的字 RAM 时钟周期数以 @ 为上限987654335@ 表示某个常量 K
,因为 n
足够大。
也就是说,有了抽象机模型,big-O 分类的函数就是抽象机的时钟周期数作为输入大小的函数。
对于 SIMD 计算,PRAM 是一种常用的抽象机器模型。与所有抽象机器模型一样,它简化了假设。例如,内存大小和处理器数量都是无限的。它还允许使用不同的策略来解决处理器之间的内存争用。与 Word RAM 一样,在 PRAM 上运行的算法的 big-O 性能是关于相对于输入大小所需的时钟周期数的陈述。
There has been some work on abstract models of GPUs 允许大 O 逼近描述算法性能的有用函数。它仍然是一个研究课题。
因此,在不同架构上比较顺序与并行性能或并行性能的问题是选择正确的抽象模型,为每个模型描述一个实现您感兴趣的算法的程序,然后比较数字的大 O 描述每个所需的时钟周期。
【讨论】:
【参考方案4】:使用 SIMD/SSE3 不会改变 Big-O 复杂性,因为它执行常数(最多 16 个)操作。
O(Function(N)/Const) === O(Function(N))
CUDA 也是如此,尽管有数千个内核在工作(如果我们忽略不同的内存访问模型并且 CUDA 实现不使用其他算法)
【讨论】:
所以如果我问你,如果你在 GPU 上运行一个算法会改进多少。你能从理论上测量它吗?无需在 CPU 和 GPU 上运行基准测试。 ? 我们可以预期,当输入大小发生变化时,两种实现时间都会以类似的方式变化(直到发生其他因素)以上是关于基于 SIMD 的算法实现的复杂性比较的主要内容,如果未能解决你的问题,请参考以下文章