C++ 对浮点指令计数

C++ 对浮点指令计数,c++,linux,performance,perf,C++,Linux,Performance,Perf,我试图计算我的一个程序中浮点运算的数量,我认为perf可能是我正在寻找的工具(有其他选择吗?),但我很难将它限制在某个函数/代码块内。让我们以下面的例子为例: #include <complex> #include <cstdlib> #include <iostream> #include <type_traits> template <typename T> typename std::enable_if<std::is_f

我试图计算我的一个程序中浮点运算的数量,我认为
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;
}
并按预期工作;但是,它计算UOP的总数(是否有一个表,说明一个
movsd
有多少UOP?
)并且我只对乘法的数字感兴趣(参见上面的示例)


如何做到这一点?

我终于找到了一种方法来做到这一点,虽然没有使用
perf
,而是使用相应的perf API。首先必须定义一个
perf\u event\u 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;
}
在这种情况下,我只想计算指令的数量。浮点指令可以在我的处理器(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\u event\u open(2)
手册页中给出的示例,其中他们在读取计数器之前禁用计数器。如果不这样做,
read
调用可能会更改计数器的值。
attr.type = PERF_TYPE_RAW;
attr.config = 0x8010; // Event Number = 10H, Umask Value = 80H
// 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);