是否有一种可编程的方法来估计CPU执行fp操作所需的时间
Is there a programmatic way to estimate the time my CPU takes to perform a fp operation?
这里的"fp运算"是指"浮点运算"。我正在开发一个Linux操作系统。是否有一个系统调用返回这个值作为一个静态度量,或者你可以用C/c++/其他语言的算法来测试这个?
edit:我应该提到这不是为了测试我的代码的效率。在一次采访中,有人问我一个理论算法需要运行多长时间。我必须计算出将执行多少个FLOPS,并将其乘以每个操作所需的时间,从而得出一个粗略的估计。我只是觉得这是个有趣的问题。
这几乎肯定不是一个有用的指标。还有很多其他因素影响代码效率——尤其是缓存命中/未命中。
话虽如此,在这个主题上有一个ServerFault线程,它链接到您可以使用的英特尔基准测试套件,但您应该意识到,您可能不会看到系统的最大FLOPS与应用程序性能之间的任何相关性。
您要使用的是Agner Fog的软件"用于测量时钟周期和性能监控的测试程序"。他用它来测量指令的延迟和吞吐量,从而生成他著名的指令表。它有很好的文档记录,包括可以在自己的代码中使用的设备驱动程序(以及如何安装它们的说明)。这是特别有用的,因为为了测量某些数量,如实际CPU频率,您需要访问特定于模型的寄存器(MSR),而用户级代码通常无法访问这些寄存器。
编辑:根据你对面试问题的编辑来估计运行一个浮点密集型运算需要多长时间,你可以使用这个公式:
time = efficiency * number_of_floating_point_operations / peak_flops.
可以从这个链接中找到许多处理器的每个内核的峰值flop -per-cycle
这些数量中的每一个都可能很难计算/估计,但效率是最困难的,因为它可能取决于许多因素,例如:
- 算法是计算受限还是内存受限?
- 该算法使用SIMD(例如SSE/AVX/FMA)的效果如何?
- 该算法如何使用MIMD(例如多核)?
- 你的实现如何使用不同的缓存级别?
为了更清楚地说明这一点,让我们考虑两个算法:矩阵乘法和点积。计算这两种算法的浮点运算次数很容易。矩阵乘法的浮点运算次数是2*n*n*n
。点积是2*n
矩阵乘法如果做得对,它是计算界,可以充分受益于SIMD和MIMD。对于小n,它的效率开始很低,对于大n,它的效率稳定。我自己的实现达到了75%。英特尔MKL获得95%以上(但使用FMA不到90%)。
因此,对于大n的矩阵乘法时间的粗略估计是假设在给定 time = 2*n^3/peak_flops
时效率为100%。
然而,对于点积,对于小n,效率将开始很高,对于大n,效率将下降到平台。这是因为它是内存限制。所以对于大n,效率是由读取内存的速度决定的。对于一台现代机器来说,大约是10gb/s。由于具有四核的现代桌面将具有超过100 GLOPS的峰值flops,并且浮点数为4或8字节,我估计在 time = 0.01*n/peak_flops
时,大型n
的效率接近1%。我对此进行了测试(参见下面的代码)。我在我的系统上得到了大约2.2 GFLOPS,峰值为236 GFLOPS,所以这大约是峰值的1%。我的系统带宽大约是11gb/s。
大多数算法都是内存限制的,所以知道你的系统读取内存的速度(DDR3, DDR4,…)是估计时间最有用的指标之一。
所以一般来说,如果你知道一个算法的浮点运算次数和处理器的峰值flops,你应该问的第一件事是,对于大n,该算法是计算边界还是内存边界,然后对于时间的粗略估计,我会假设计算边界的效率是100%,对于内存边界,我会查找带宽来估计效率。
此代码从点积估计数据速率和GFLOPS。
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
float dot(float *x, float *y, int n) {
float sum = 0;
for(int i=0; i<n; i++) {
sum += x[i]*y[i];
}
return sum;
}
int main(){
const int LEN = 1 << 28;
float *x = new float[LEN];
float *y = new float[LEN];
for(int i=0; i<LEN; i++) { x[i] = 1.0*rand()/RAND_MAX - 0.5; y[i] = 1.0*rand()/RAND_MAX - 0.5;}
uint32_t size = 2*sizeof(float)*LEN;
clock_t time0 = clock();
float sum = dot(x,y,LEN);
clock_t time1 = clock();
double dtime = (double)(time1 - time0) / CLOCKS_PER_SEC;
double rate = 1.0*size/dtime*1E-9;
double flops = 2.0*LEN/dtime*1E-9;
printf("sum %f, dtime %f, rate %f, flops %fn", sum, dtime, rate,flops);
}
试图确定FLOP"在真空中"所花费的时间并没有多大意义,因为有很多其他因素影响它(操作数是否在内存/缓存/寄存器中,它实际上是什么类型的操作,如果编译器发出x87/SSE/SSE2/…指令,是否涉及"奇怪"的IEEE754值,处理器管道是否被有效使用,代码是否分支预测器友好,…)。
你应该在你的算法的实际代码上使用一个分析器,看看什么是真正的瓶颈,以及在你的特定代码中在这些瓶颈上实际花费了多少时间。
有一种快速的方法,在执行某些操作之前和之后获取时间戳并将它们相减以查看消耗了多少时间。然而,这并不十分准确。
下面提供了来自我的一个基准测试的可变性的概念,该基准测试使用相同的汇编代码指令的长序列,试图填充管道,不同的测试使用可变数量的寄存器。这只是加法。
Intel(R) Core(TM) i7-4820K CPU running at near 3.9 GHz
Speeds adding to 1 Register 2 Registers 3 Registers 4 Registers
32 bit Integer MIPS 4303 8553 11997 12294
32 bit Float MFLOPS 1304 2608 3866 3866 SP
64 bit Float MFLOPS 1304 2608 3866 3865 DP
32 bit MMX Int MIPS 7824 14902 14936 14902
32 bit SSE MFLOPS 5215 10431 15464 15463 SP
64 bit SSE2 MFLOPS 2608 5216 7732 7731 DP
32 bit SSE2 Int MIPS 15647 29803 29872 29803
64 bit SSE2 Int MIPS 7823 14902 14936 14902
- 在执行其他功能的同时播放动画(LED矩阵和Arduino/ESP8266)
- C++,系统无法执行指定的程序
- 使用C++中的模板和运算符重载执行矩阵运算
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何禁用 CPU 的无序执行
- 维护/维持两个代码集的风险,一个用于 CPU,一个用于 GPU,需要执行非常相似的功能
- 代码执行/CPU 速度每 2 秒减慢一次
- 二叉搜索真的是在 0 时钟 CPU 时间内执行的吗?
- 视觉 从 C++ 应用程序执行的外部程序中的 CPU 负载有限
- C++:多线程设计,每个线程都应该同时执行I/O和CPU密集型任务
- 在同一个cpu内核上执行的OpenMP线程
- 是否有一种可编程的方法来估计CPU执行fp操作所需的时间
- 在有限的cpu时间内定期执行一个pthread
- 如何在c++中计算函数的执行时间和cpu消耗
- 即使cpu数量增加,执行时间也会增加,为什么?
- 为什么每次执行这个程序的CPU时间都不一样
- 基准测试和限制执行到特定的CPU
- OpenCL示例程序在CPU上的执行速度是在GPU上的10倍
- SDL_Renderer使用 100% CPU 和 RAM 来不执行任何操作