计算浮点指令

Posted

技术标签:

【中文标题】计算浮点指令【英文标题】:Count floating-point instructions 【发布时间】:2014-06-02 17:36:49 【问题描述】:

我正在尝试在我的一个程序中计算浮点运算的数量,我认为perf 可能是我正在寻找的工具(有其他选择吗?),但我无法将其限制在某个范围内功能/代码块。举个例子:

#include <complex>
#include <cstdlib>
#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type myrand()

        return static_cast <T> (std::rand()) / static_cast <T> (RAND_MAX);


template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, std::complex<typename T::value_type>>::type myrand()

        typedef typename T::value_type S;

        return std::complex<S>(
                static_cast <S> (std::rand()) / static_cast <S> (RAND_MAX),
                static_cast <S> (std::rand()) / static_cast <S> (RAND_MAX)
        );


int main()

    auto const a = myrand<Type>();
    auto const b = myrand<Type>();

    // count here
    auto const c = a * b;
    // stop counting here

    // prevent compiler from optimizing away c
    std::cout << c << "\n";

    return 0;

myrand() 函数只返回一个随机数,如果类型 T 是复数,则返回一个随机复数。我没有将 double 硬编码到程序中,因为它们会被编译器优化掉。

您可以使用c++ -std=c++0x -DType=double bench.cpp 编译文件(我们称之为bench.cpp)。

现在我想计算浮点运算的数量,这可以在我的处理器(Nehalem 架构,x86_64,其中浮点使用标量 SSE 完成)上完成,事件 r8010(参见英特尔手册 3B,第19.5)。这可以通过

perf stat -e r8010 ./a.out

并按预期工作;但是它会计算 uops 的总数(是否有一张表格告诉 movsd 例如有多少 uops?)并且 我只对乘法的数字感兴趣 (见上面的例子)。

如何做到这一点?

【问题讨论】:

【参考方案1】:

我终于找到了一种方法,虽然没有使用perf,而是使用了相应的perf API。首先必须定义一个perf_event_open 函数,它实际上是一个系统调用:

#include <cstdlib> // stdlib.h for C
#include <cstdio> // stdio.h for C
#include <cstring> // string.h for C
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>

long perf_event_open(
    perf_event_attr* hw_event,
    pid_t pid,
    int cpu,
    int group_fd,
    unsigned long flags
) 
    int ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
    return ret;

接下来,选择想要计算的事件:

perf_event_attr attr;

// select what we want to count
std::memset(&attr, 0, sizeof(perf_event_attr));
attr.size = sizeof(perf_event_attr);
attr.type = PERF_TYPE_HARDWARE;
attr.config = PERF_COUNT_HW_INSTRUCTIONS;
attr.disabled = 1;
attr.exclude_kernel = 1; // do not count the instruction the kernel executes
attr.exclude_hv = 1;

// open a file descriptor
int fd = perf_event_open(&attr, 0, -1, -1, 0);

if (fd == -1)

    // handle error

在这种情况下,我想简单地计算指令的数量。通过将相应的行替换为

,可以在我的处理器(Nehalem)上计算浮点指令
attr.type = PERF_TYPE_RAW;
attr.config = 0x8010; // Event Number = 10H, Umask Value = 80H

通过将类型设置为 RAW,基本上可以计算处理器提供的每个事件;数字0x8010 指定了哪一个。 请注意,此数字高度依赖于处理器!您可以通过选择正确的小节在英特尔手册 3B 第 2 部分第 19 章中找到正确的数字。

然后可以通过将代码包含在其中来测量代码

// reset and enable the counter
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

// perform computation that should be measured here

// disable and read out the counter
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
long long count;
read(fd, &count, sizeof(long long));
// count now has the (approximated) result

// close the file descriptor
close(fd);

【讨论】:

你真的必须在阅读之前禁用计数器吗? 对于浮点指令,这可能无关紧要。我修改了perf_event_open(2) 手册页中给出的示例,他们在读出计数器之前禁用了计数器。如果您不这样做,那么 read 调用可能会更改计数器的值。

以上是关于计算浮点指令的主要内容,如果未能解决你的问题,请参考以下文章

FPU 浮点运算单元和DSP指令

处理器 增强指令集

处理器 增强指令集

处理器 增强指令集

如何访问 NEON 指令中的完整 128 位?

浮点 汇编指令基础知识