与天真计算相比,FMA性能

FMA performance compared to naive calculation

本文关键字:FMA 性能 天真 计算      更新时间:2023-10-16

我试图将浮点计算中的FMA性能(math.h中的fma())与朴素的乘法和加法进行比较。测试很简单。我将对大的迭代次数重复相同的计算。为了进行精确的检查,我必须做到两件事。

  1. 计数时间中不应包含其他计算
  2. 单纯的乘法和加法不应优化为FMA
  3. 不应优化迭代。即迭代应该按照我的意图进行

为了实现上述目标,我做了以下事情:

  1. 函数是内联的,并且只包括所需的计算
  2. 使用g++-O0选项不优化乘法。(但当我查看转储文件时,它似乎为两者生成了几乎相同的代码)
  3. 使用volatile

但结果显示,与简单的乘法和加法相比,fma()几乎没有差异,甚至更慢这是我想要的结果吗(即,它们在速度方面并没有真正的不同)还是我做错了什么

规格

  • Ubuntu 14.04.2
  • G++4.8.2
  • Intel(R)Core(TM)i7-4770(3.4GHz,8MB L3缓存)

我的代码

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <chrono>
using namespace std;
using namespace chrono;
inline double rand_gen() {
    return static_cast<double>(rand()) / RAND_MAX;
}
volatile double a, b, c;
inline void pure_fma_func() {
    fma(a, b, c);
}
inline void non_fma_func() {
    a * b + c;
}

int main() {
    int n = 100000000;
    a = rand_gen();
    b = rand_gen();
    c = rand_gen();
    auto t1 = system_clock::now();
    for (int i = 0; i < n; i++) {
        non_fma_func();
    }
    auto t2 = system_clock::now();
    for (int i = 0; i < n; i++) {
        pure_fma_func();
    }
    auto t3 = system_clock::now();
    cout << "non fma" << endl;
    cout << duration_cast<microseconds>(t2 - t1).count() / 1000.0 << "ms" << endl;
    cout << "fma" << endl;
    cout << duration_cast<microseconds>(t3 - t2).count() / 1000.0 << "ms" << endl;
}

是的,你做的事情完全错了。至少两个多岁的年轻人。但让我们保持简单。

Used g++ -O0 option not to optimize the multiplication

这使得您的整个结果完全无关。有趣的事实是:在任何一种情况下,函数调用的成本都可能大于计算的成本。

从根本上讲,没有启用优化的基准测试结果是完全没有意义的。你不能只是关掉它们,抱着最好的希望。它们绝对必须启用。

其次,FMA与常规的乘法和加法是一个复杂的情况——在延迟与吞吐量以及其他问题上,乘法和加法可能是赢家。

简而言之,你的基准测试根本不是一个基准测试,它只是一堆随机指令,产生了毫无意义的垃圾。

如果你想要一个准确的基准,你必须准确地再现实际的使用情况——完全。包括周围的代码,编译器的优化,整个shebang。