acm-header
登录

ACM通信

BLOG@CACM

高性能计算:计算性能与人类生产力的对比


乔尔·亚当斯

乔尔·亚当斯,加尔文学院

在过去的十年里,我参加过几次超级计算会议(SC),包括上个月在新奥尔良举行的SC14。我在今年的会议上听到的一个主题是对旧权衡的新变化:效率和性能

这种古老的权衡可以追溯到第一批高级语言出现的时候。当创建一个新的软件时,人们可以选择这样写:

  • 汇编语言,它让程序员通过使用特定于机器的优化来提高运行时性能;或
  • 一种高级语言,它让程序员减少了编写软件所需的时间,以及将软件移植到不同架构所需的时间。

因为汇编版本的软件运行速度更快,所以它最好性能比高级版本。因为人类可以更快地开发高级版本,并且需要更少的移植/维护工作,所以它允许人类做更多的工作富有成效的比汇编版,如果性能差异不是太大。假设你是一名在国家实验室工作的科学家,那里每隔几年就会安装一台新的超级计算机,你会愿意使用一种高级语言,并为此付出性能上的代价,而不是使用汇编语言,并不得不为每台新的超级计算机重写软件。只要与高级语言相关的性能损失不是太大,以更高的生产率换取较低的性能是可以接受的。

(为了避免读者认为这是古老的历史,今天的编译器可以为我们解决这个问题,考虑一下后藤一成的工作,他手工优化的汇编版本基本线性代数子程序用于Intel和AMD x86架构的BLAS库的运行速度通常比编译版本至少快20%。20%的性能差距已经足够大了,直到几年前加速器开始主导超级计算领域时,大多数超级计算机都包括了Goto版本的BLAS。)

让我们跳到今天:顶级超级计算机是分布式节点的异构系统,每个节点都包含多核处理器和加速器。这些加速器可能是通用图形处理单元(gpu)或协同处理器(如英特尔的Xeon Phi)。为了有效地使用这些超级计算机中的硬件,软件开发人员经常使用MPI + X,地点:

  • MPI消息传递接口,该库是将进程分发到节点并让这些进程彼此通信的实际标准。
  • X是下列一项或多项:
    • OpenMP,一个用于为多核cpu编写多线程进程的库,其设计目的是相对容易地向遗留代码添加并行性。
    • CUDA这是一种语言和库,程序员可以利用Nvidia gpu编写和调优代码。
    • OpenCL这个库允许程序员编写和调优将在每个节点的核心上运行的代码:CPU核心、协处理器核心或GPU核心,无论供应商是什么。
    • OpenACC,一个用于编写类似于OpenMP的代码的库,但它将利用加速器的核心。

在选择X在美国,人们必须做出生产力和性能的权衡决定。下面的概述略过了许多细节,但希望它能让读者对其中涉及的一些权衡有一个高级的理解。

CUDA

CUDA允许软件开发者为占据加速器市场主导地位的英伟达gpu编写高效的代码。它是最成熟的加速器技术,在互联网上有大量可用的文档和示例。

然而,为了在给定的Nvidia GPU上最大化软件性能,一个人的CUDA代码必须针对该设备进行调整。特别地,程序员必须明确地组织GPU线程,把积木组织成一个网格,将数据从计算机的主存移动到GPU的内存中,然后返回,将数据放在GPU的内存中(较大但较慢)全局内存或者its(更小但更快)共享内存等等。指定所有这些参数的最佳方法取决于给定GPU的特性,这意味着一个人的代码可能必须针对每一代Nvidia设备进行调整,至少要获得最大性能。

我在SC14上遇到的人都很喜欢CUDA在英伟达gpu上的表现,但是他们并不喜欢第一次创建和调整程序的工作,也不喜欢将程序移植到新机器上时重新调整程序的工作。他们认为这种工作的每一分钟都是生产力的损失。

OpenCL

OpenCL允许软件开发人员为CPU核心、协处理器核心或GPU核心编写高效的代码,而不仅仅是Nvidia的GPU核心。然而,为了实现这种灵活性,OpenCL程序要比CUDA程序复杂得多。它们也需要类似的调优,因为程序员必须显式地组织工作项(线程)工作组(块),把工作小组组织成一个索引空间(网格),将数据从计算机的主存储器移动到加速器的存储器,然后返回,将数据放在(大但慢)全局内存或者(小而快)本地内存等等。

与CUDA一样,一个人的代码可能需要在每次移植到一个新的架构时重新调整。在正面比较中,CUDA通常比OpenCL更快,至少在Nvidia设备上,两者可以直接比较,这使得优化在OpenCL中至少和在CUDA中一样重要。

如上所述,OpenCL程序比CUDA程序更复杂。这种增加的复杂性会增加OpenCL软件开发和维护的时间开销,从而进一步降低工作效率。

OpenACC

OpenACC试图通过(i)使编写将在加速器上运行的代码变得更容易,(ii)使将代码移植到新体系结构的任务变得像重新编译代码一样简单,从而提高人们的工作效率。例如,要利用GPU,可以分配代码给工人(线程),把工人组织成帮派(块),并将可服从SIMD执行的工作代码块指定为向量块。但是,可以为每个选项指定值,也可以让编译器选择值。OpenACC还为加速器上通常需要的一些并行模式提供内置支持,比如缩减模式。

SC14的研究人员报告说,他们在2013年和2014年夏天比较了OpenACC和CUDA或OpenCL的性能,虽然OpenACC在2013年有很大的性能损失,但在2014年夏天,这种损失已经大大减少(但仍然显著)。有趣的是,我听一个研究人员说,在2013年,他写一个OpenACC程序的时间是他写一个CUDA版本的50%,但他的CUDA版本运行速度比他的OpenACC版本快50%。在2014年,OpenACC编译器已经改进到CUDA版本比OpenACC版本快不到25%。像Cray和Portland Group International这样的编译器供应商在提高OpenACC的性能方面有着商业利益,因此OpenACC和其他技术之间的性能差距在未来可能会继续缩小。

OpenMP

OpenMP在传统上是一个易于在多核cpu上用于隐式多线程的库。然而,OpenMP 4规范增加了用于运行代码的指令目标设备(加速器),在加速器上可以确定线程要完成的工作,将这些线程组织成团队(模块的抽象)并将团队组织成一个联盟(网格或其他特定于设备的映射的抽象)。OpenMP还提供了一个simd用于标记易于向量化的循环代码的指令。在OpenACC中,这些抽象到硬件的确切映射可以留给编译器,也可以显式指定。

在写这篇文章的时候,编译器作者仍然在实现对OpenMP 4规范的支持,所以这项技术远不如OpenACC成熟,正如我们上面看到的,OpenACC在性能上落后于CUDA和OpenCL。(曾经有过OpenACC和OpenMP合并的传闻,但根据SC14的消息,这似乎不太可能。)成熟后,OpenMP有可能提供在CPU和加速器核心上利用并行性所需要的一切,使其成为平衡性能和生产力的有力候选。

封闭的思想

所有这些技术在未来都值得关注,因为它们将继续发展和成熟。虽然CUDA和OpenCL与汇编相距甚远,但为了实现最佳(甚至良好)性能,需要了解加速器的硬件细节,这使得这些技术比典型的高级语言更接近硬件。在生产力方面。OpenACC看起来很有前途,但是为了缩小性能差距,它还有很多工作要做。OpenMP似乎更有前途,但在它准备投入使用之前还有更长的路要走。

与此同时,计算机科学教育者面临着一个有趣的问题:决定在课堂上使用什么技术,让学生接触基于加速器的计算。这让我想问那些读到这里的人:

  1. 既然加速器越来越普遍,价格也越来越便宜,你用什么软件技术(或技术)来教学生编程加速器,你为什么选择它?
  2. 在你的课程中(例如,哪些课程,在什么水平),你教学生加速器和他们的编程?
  3. 我们应该使用什么样的技术来让我们的学生为未来做好最好的准备?

我期待听到你的意见!


评论


大卫Heryanto

嗨乔
这是一个非常有趣的想法,关于我们开发人员在编写程序时通常不得不选择的性能与生产力的两难选择。

只是想知道,在机器学习领域,很多库是用Python、Matlab或R实现的;我相信这些库的并行实现不会使用许多使用C/ c++ /Fortran开发的科学应用程序所使用的MPI库(例如,在Python中我们有NumbaPro或原生多处理模块等库)。

您认为这些并行处理API是否会融合或标准化,从而使这些用不同语言编写的库可以轻松地一起使用,而无需大量重新编译/重写代码?我相信这也是我们选择生产力而不是性能的情况。


乔尔·亚当斯

你好大卫,
我不是Python、Matlab或R方面的专家,但我听说Python库中的许多函数实际上是对C函数的“包装”,这些函数完成了实际工作,以获得更好的性能。因此,如果这些库具有并行功能,那么编写这些库的人可能会使用MPI/OpenMP/CUDA/…然后将该功能“包装”在一个API中,供Python程序员使用以提高工作效率。我猜运行在Beowulf集群上的Matlab和/或R功能采用了类似的方法。

还有一些像mpi4py这样的项目,它们试图提供一个类似于mpi的系统,用于在Python中编写分布式计算,以及pycuda,它提供了一个用于在Python中编写GPU计算的API。因此,另一种选择是使用软件包开发应用程序,这些软件包可以让您利用可用的硬件。如果有一种算法是用MPI或CUDA表示的,但你更喜欢Python,你可以使用适当的包将该算法“翻译”为Python。这是另一种平衡性能和生产力的方法。

就融合而言:过去只有两种硬件平台需要处理——分布式多处理器和共享内存多处理器——但加速器带来了第三种选择。在今天的超级计算机中,这三种处理器已经融合在一起,但在服务器、台式电脑、笔记本电脑等上,您仍然需要处理共享内存多处理器,其中一些还带有加速器。

openmp4的一些新功能似乎是为了弥合共享内存/加速器的鸿沟而设计的。例如,如果您的程序要执行许多可以向量化的数组操作,那么可以在这些操作之前加上#pragma omp simd。然后,如果底层硬件包含一个向量加速器单元,编译器就可以生成利用该硬件的机器码;否则,编译器将忽略#pragma并生成正常的机器码。这使我的工作效率更高,因为它将性能开发的大部分工作从我身上转移到了编译器身上。当然,我仍然必须能够识别出适合向量化的代码段;编译器不会为我做这些。

弥合分布式多处理器和共享内存多处理器之间的差距比较困难,因为专门为在共享内存多处理器上获得最大性能而编写的程序(使用或不使用加速器)通常需要进行重大修改才能在分布式多处理器上运行。

一些语言(如Erlang, Scala)试图通过鼓励开发人员让他们的进程/线程/任务只通过消息传递进行通信来弥合这一鸿沟。如果您的软件是这样设计的,那么这些组件是在同一台机器上本地运行还是在分布式机器上远程运行就不重要了。换句话说,用于通信的消息传递方法相当普遍,因为使用这种方法编写的程序既可以运行在分布式内存上,也可以运行在共享内存多处理器上;而通过共享内存(使用锁等)进行通信的程序仅限于共享内存多处理器。因此,这些语言可能被视为试图使消息传递成为并行处理的标准API。

所有这些方法都需要大量的重新编译/重写代码才能达到您想要的效果。我不想听起来很悲观,但是实现您所描述的那种互操作性似乎不太可能很快实现。Mattson、Keutzer等人的并行设计模式工作在设计并行软件时支持标准化的思维过程,但在实现和运行时级别,实现这种标准化似乎是一个巨大的挑战。


杰夫•哈蒙德

GotoBLAS2和编译后的Netlib之间的差异超过20%。在DGEMM的情况下可以达到~1000倍!但并不是只有Kazushige一人解决了这个问题。Intel (MKL), AMD (ACML), Cray (LibSci), IBM (ESSL), NVIDIA (CUBLAS)等供应商为他们的系统提供了高度优化的实现。当然,还有其他的开源项目,包括著名的ATLAS (mathematiatlas.sourceforge.net)和更新得多的BLIS (https://code.google.com/p/blis/)。

您的观点仍然是正确的,但它的提出方式可能会让读者得出这样的结论:优化BLAS是只有一个活着的人拥有的技能,编译器所缺少的优化值得用编写Fortran而不是汇编的便利来实现。我愿意给20%的时间来使用Fortran而不是汇编,但1000倍是不可接受的。


乔尔·亚当斯

这些都是好的观点,杰夫。谢谢您填写了一些遗漏的细节!


显示所有4评论

登录为完全访问
»忘记密码? *创建ACM Web帐户
Baidu
map