我被要求测量一个在多 CPU 系统上求解微分方程的 Fortran 程序的性能。我的雇主坚持要求我测量 FLOP/s(每秒浮动操作数)并将结果与​​基准进行比较(林帕克)但我不相信这是正确的方法,只是因为没有人能给我解释什么是 FLOP。

我对 FLOP 到底是什么做了一些研究,得到了一些非常矛盾的答案。我得到的最受欢迎的答案之一是“1 FLOP = 加法和乘法运算”。真的吗?如果是这样,那么从物理上来说,这到底意味着什么?

无论我最终使用什么方法,它都必须是可扩展的。代码的某些版本解决了具有数百万个未知数的系统,并且需要几天的时间才能执行。

在我的案例中,还有哪些其他有效的衡量性能的方法(我的案例摘要是“fortran 代码在数百个 CPU 上反复进行数天的大量算术计算)”?

有帮助吗?

解决方案

这是表现一个相当不错的措施,只要你明白到底是什么措施。

FLOPS是,顾名思义每秒浮点运算,正是构成FLOP可能通过CPU而有所不同。 (有些CPU的可以执行加法和乘法的一个操作,别人做不到的,例如)。这意味着,作为一个性能指标,它是相当接近的硬件,这意味着1)你必须知道你的硬件来计算给定结构的理想FLOPS,你必须知道你的算法和实现弄清楚如何许多浮点OPS它实际上包含。

在任何情况下,它是研究如何以及你利用CPU的有用工具。如果你知道在FLOPS CPU的理论峰值性能,你可以工作,你如何有效地利用CPU的浮点单元,这往往是硬有效地利用之一。它运行FLOPS的CPU能的30%的程序,具有优化的余地。其中一个在70%下运行时可能不会,除非你改变基本算法得到更有效。对于像你这样的数学算法重,这是相当多衡量业绩的标准方式。你可以简单地衡量一个程序需要多长时间来运行,但疯狂变化取决于CPU。但是,如果你的程序有一个50%的CPU利用率(相对于峰值FLOPS计数),这是一个较为恒定的值(它仍然会完全不同的CPU架构之间各不相同,但它是一个很多比执行时间更加一致)。

但知道“我的CPU是能够X GFLOPS的,而我实际上只实现了吞吐量的,比方说,那20%”是的非常的高性能软件有价值的信息。这意味着什么的其他的比浮点OPS是抱着你回来,并防止FP单位的工作效率。而且,由于FP单位构成了大部分工作,这意味着你的软件有问题。

这很容易衡量“我的程序在X分钟运行一次”,如果你觉得这是不能接受的话,当然,你可以去“我不知道如果我能砍30%认为”,但你不知道的知道的,如果这是不可能的,除非你的工作到底有多少工作正在做,而且正是CPU能在高峰期。多少时间,你想花这个优化,如果你甚至不知道CPU是否是从根本上能够运行每秒更多的指令?

这是非常容易防止CPU的FP单元被有效地利用,通过具有浮点操作之间存在太多的相关性,或通过具有分支太多或类似预防有效的调度。如果这是阻碍你实现回来了,你的需要的知道这一点。你需要知道,“我没有得到的FP吞吐量应该是可能的,所以我的代码清楚其他地区的,阻止时可用的CPU是准备发行一个浮点指令。”

为什么你需要其他的方法来衡量绩效?出了什么问题只是工作了FLOPS算作你的上司叫你? ;)

其他提示

我想补充几点:

  • 分配 很特别。由于大多数处理器可以在单个周期内执行加法、比较或乘法,因此这些都被计为一次触发器。但除法总是需要更长的时间。多长时间取决于处理器,但 HPC 社区中有一种事实上的标准,将一次除法计算为 4 次失败。

  • 如果处理器有一个 乘加融合 在一条指令中执行乘法和加法的指令——通常是 A += B * C——算作 2 次操作。

  • 始终要小心区分 单精度 人字拖和 双精度触发器. 。能够处理这么多单精度千兆浮点运算的处理器可能只能处理那么多双精度千兆浮点运算的一小部分。AMD Athlon 和 Phenom 处理器执行的双精度触发器数量通常是单精度处理器的一半。ATI Firestream 处理器的双精度触发器执行次数通常是单精度触发器的 1/5。如果有人试图向您出售处理器或软件包,而他们只是引用失败结果而没有说明是哪一个,那么您应该打电话给他们。

  • 术语兆浮点运算、千兆浮点运算、万亿次浮点运算等。都是常用的。这些是指以下因素 1000, 不是 1024. 。例如,1 megaflop = 1,000,000 flop/sec,而不是 1,048,576。正如磁盘驱动器大小一样,这方面也存在一些混乱。

“比较基准的结果”,做什么呢?

FLOPS意味着你需要

1)每作业的一些单位触发器。

2)时为工作单元。

让我们假设你有通过一些循环就重复1000一些输入文件。循环是工作的一个方便的单位。它被执行1000次。这需要一个小时。

在环具有一些添加和乘法和几个划分和平方根。你可以指望增加,乘,除。您可以在源算上这,找+,*,/和。你可以找到编译器输出的汇编语言,并有指望他们了。您可能会得到不同的数字。哪一个是正确的?问问你的老板。

您可以指望的平方根,但你不知道它的确会以成倍的条款和补充。所以,你必须做一些事情,如基准乘法与平方得到的平方根需要多长时间感。

现在你知道在你的循环中的FLOPS。你知道运行它1000倍的时间。你知道FLOPS每秒。

那你看LINPACK和发现你慢。怎么办?你的程序是不是LINPACK,而且它比LINPACK慢。赔率是非常好的,你的代码会比较慢。除非你的代码编写,并在相同数量的年LINPACK优化,你会更慢。

这里的其他部分。您的处理器有一些定义FLOPS的评价对各种基准。你的算法是不是那些基准之一,所以你达不到基准。这是坏?或者这是不是一个基准的明显的后果?

什么是可行的结果会是什么?

针对一些基准的代码基础测量,只是要告诉你,你的算法是不是基准算法。这是一个定局,你会是不同的;通常较慢。

显然,针对LINPACK测量的结果将是:(a)你是不同的,并且因此(b)中需要优化。

在对的亲自做测量是唯一真正有价值的的。不是一些假设的指令组合,而是你自己的指令组合。衡量自己的表现。做出改变。看看你的表现 - 与自己相比 - 变得更好或更坏

FLOPS并不重要。重要的是每个工作单元的时间。因为你没有运行的基准,硬件设计人员预计你永远也符合硬件的设计参数。

LINPACK无所谓。重要的是你的代码库和你正在做改变性能的变化。

在我看来,老问题和老问题,如果流行的话,答案并不完全好。

“FLOP”是浮点数学运算。“FLOPS”可以指以下两种情况之一:

  • “FLOP”的简单复数形式(即“手术 X 需要 50 次 FLOP”)
  • 速度 第一种意义上的 FLOP 数(即每秒浮点数学运算)

如果上下文不清楚,则通常将前者写为“FLOPs”,将后者写为“FLOP/s”来消除歧义。

所谓 FLOP 是为了将其与其他类型的 CPU 操作区分开来, ,例如整数数学运算、逻辑运算、按位运算、内存运算和分支运算,它们具有不同的成本(读作“花费不同的时间长度”)。

“FLOP 计数”的实践可以追溯到科学计算的早期阶段,相对而言,当时的 FLOP 非常昂贵,每个 FLOP 需要许多 CPU 周期。例如,80387 数学协处理器执行一次乘法需要大约 300 个周期。那是在流水线技术出现之前,CPU 时钟速度和内存速度之间的鸿沟还没有真正出现之前:内存操作只需要一两个周期,并且分支(“决策”)同样便宜。那时,如果您可以消除一次 FLOP,而有利于十几个内存访问,那么您就取得了收益。如果你能消除一个 FLOP,而有利于十几个分支,那么你就获得了收益。所以, 在过去,对 FLOP 进行计数是有意义的,而不必太担心内存引用和分支,因为 FLOP 强烈主导执行时间 因为相对于其他类型的操作而言,它们单独而言非常昂贵。

最近,情况发生了逆转。FLOP 已经变得非常便宜——任何现代英特尔 每个周期可以执行大约两次 FLOP(尽管除法仍然相对昂贵)——并且内存访问和分支相对昂贵得多:L1 缓存命中可能需要 3 或 4 个周期,从主内存中读取则需要 150-200 个周期。鉴于这种反转, 不再存在这样的情况:消除 FLOP 以支持内存访问会带来收益;事实上,这不太可能。同样,“只做”一次失败通常比决定是否做要便宜,即使它是多余的。这与25年前的情况几乎完全相反。

不幸的是,盲数 FLOP 计数作为算法优点的绝对衡量标准的做法一直持续到其保质期之后。 现代科学计算更多地涉及内存带宽管理 - 试图保留执行单元 FLOP 不断地输入数据——而不是减少 FLOP 的数量。参考 林帕克 (基本上已被淘汰 拉帕克 20 年前)让我怀疑你的雇主可能是一个非常老派的人,他们没有认识到建立绩效期望不再只是计算失败的问题这一事实。如果求解器具有更有利的内存访问模式和数据布局,则执行两倍次数的 FLOP 的求解器仍可能比另一个求解器快二十倍。

这一切的结果就是 计算密集型软件的性能评估变得比以前复杂得多. 。FLOP 变得便宜的事实因大量的 变化性 内存操作和分支的成本。当谈到评估时 算法, ,简单的 FLOP 计数根本无法再提供总体性能预期。

也许所谓的“绩效预期和评估”提供了一种更好的思考方式。 屋顶线模型, ,这远非完美,但它的优点是让你 同时考虑浮点和内存带宽问题之间的权衡, ,提供信息更丰富、更有洞察力的“2D 图片”,可以比较性能测量和性能预期。

值得一看。

一个FLOPS是,如你所说,每秒一个浮点运算。作为一个例子,如果你把恰好一个秒的操作(如加,减,乘或除的两个值并返回结果)时,性能仅仅是1 FLOPS。最近的CPU将很容易实现几个亿次,每秒即数十亿次浮点运算。

我只是想让它尽可能快地运行,这需要找出它在哪里花费了时间,特别是如果有可以避免的函数调用。

我通过简单的方法来做到这一点,只需在它运行时中断几次,然后看看它在做什么。以下是我发现的一些事情:

  • 大多数时候它是在计算导数和/或雅可比行列式的过程中。大部分时间可以用于数学函数调用,例如 exp(), log(), , 和 sqrt(). 。通常这些都是用相同的参数重复的,并且可以被记住。(大幅加速。)

  • 大部分时间都花在计算导数上太多次,因为积分容差比必要的更严格。(快点)

  • 如果由于方程被认为是刚性的而使用隐式积分算法(例如 DLSODE Gear),那么很可能并非如此,并且可以使用诸如 Runge-Kutta 之类的算法。(德沃克)。(还是更快)

  • 如果模型是线性的(DGPADM),则可能可以使用矩阵指数算法。这对于性能和精度来说都是一个巨大的胜利,并且不受刚度的影响。(更快)

  • 在调用堆栈的较高层,可能会使用略有不同的参数重复执行相同的积分,以便确定解相对于这些参数的前向或中心差分梯度。如果微分方程本身是可微的,则可以通过分析或通过用灵敏度方程增强方程来获得这些梯度。这不仅更快,而且更精确,这可以加快堆栈中更高层的速度。

您可以将堆栈的每个级别视为寻找优化内容的机会,并且加速将会复合。然后,当您使用多CPU时,假设它是可并行的,那么它应该提供自己的乘法因子。

回到失败的话题。你可以尝试 最大化 FLOPs / second, ,但它也可能更有用 最小化 FLOPs / run, ,通过在堆栈的各个级别进行优化。无论如何,只要 测量 他们几乎什么也没告诉你。

您的雇主是正确的。结果 来衡量Fortran程序的有效性的唯一途径(或任何其他程序的,顺便说一句)是测试靠在标准基准,如果存在的话。

和,约FLOPS,它代表“浮动每秒点操作” - 请参见定义在维基百科。

我不认为测量FLOPS将是非常有用的。

FLOPS的数量来实现的会告诉你多忙你的算法是保持CPU,但不会告诉你本身是你的算法如何执行。

您可能会发现两种不同的算法,其使得所述处理器执行相同数目的FLOPS但一个提供了一半的时间所需的结果。

我想你会更好看更“高层次”的统计,例如每单位解决的时间微分方程的数量(即,毕竟,你的算法的目的)。

在另一方面,测量达到FLOPS的数量可能会帮助你提高你的算法,因为它会告诉你为什么那么忙你保持CPU。

scroll top