计算浮点指令
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
调用可能会更改计数器的值。以上是关于计算浮点指令的主要内容,如果未能解决你的问题,请参考以下文章