如何在现代x86-64 Intel CPU上实现每个周期4个浮点运算(双精度)的理论峰值性能?
据我所知,SSE 需要三个周期,add而mul大多数现代Intel CPU需要五个周期才能完成(参见例如Agner Fog的"指令表").由于流水线操作,add如果算法具有至少三个独立的求和,则每个周期可以获得一个吞吐量.因为打包addpd和标量addsd版本都是如此,并且SSE寄存器可以包含两个,double每个周期的吞吐量可以高达两个触发器.
此外,似乎(虽然我没有看到任何适当的文档)add并且mul可以并行执行,给出每个周期四个触发器的理论最大吞吐量.
但是,我无法使用简单的C/C++程序复制该性能.我最好的尝试导致大约2.7个翻牌/周期.如果有人可以贡献一个简单的C/C++或汇编程序,它可以表现出非常高兴的峰值性能.
我的尝试:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
double stoptime(void) {
struct timeval t;
gettimeofday(&t,NULL);
return (double) t.tv_sec + t.tv_usec/1000000.0;
}
double addmul(double add, double mul, int ops){
// Need to initialise differently otherwise compiler might optimise away
double sum1=0.1, sum2=-0.1, sum3=0.2, sum4=-0.2, sum5=0.0;
double mul1=1.0, mul2= 1.1, mul3=1.2, mul4= 1.3, …Run Code Online (Sandbox Code Playgroud) 我做了一些时间测试,也喜欢读一些文章,这样一个(最后的评论),它看起来像在发布版本,float和double值采取的处理时间相同.
这怎么可能?当float值与double值相比精度更低且更小时,CLR如何在相同的处理时间内获得双倍?
通过编码是否有任何(非微优化)性能增益
float f1 = 200f / 2
Run Code Online (Sandbox Code Playgroud)
在比较中
float f2 = 200f * 0.5
Run Code Online (Sandbox Code Playgroud)
几年前我的一位教授告诉我,浮点除法比浮点乘法慢,但没有详细说明原因.
这句话适用于现代PC架构吗?
UPDATE1
关于评论,请同时考虑这个案例:
float f1;
float f2 = 2
float f3 = 3;
for( i =0 ; i < 1e8; i++)
{
f1 = (i * f2 + i / f3) * 0.5; //or divide by 2.0f, respectively
}
Run Code Online (Sandbox Code Playgroud)
更新2 从评论中引用:
[我想]知道什么是算法/架构要求导致>除法在硬件上比复制要复杂得多
双值存储更高的精度并且是浮点数的两倍,但英特尔CPU是否针对浮点数进行了优化?
也就是说,双重操作与+, - ,*和/的浮点运算一样快或快.
对于64位架构,答案是否会改变?
使用float类型比使用double类型慢吗?
我听说现代的Intel和AMD CPU可以比使用浮点数更快地进行双倍计算.
什么标准的数学函数(sqrt,pow,log,sin,cos,等)?以单精度计算它们应该相当快,因为它应该需要更少的浮点运算.例如,单精度sqrt可以使用比双精度更简单的数学公式sqrt.另外,我听说标准数学函数在64位模式下更快(在64位操作系统上编译和运行时).对此有何明确答案?
result是的float,我可以用这三种方式编码:
if (result < 0)if (result < 0.)if (result < 0.f)据我了解,
0隐含地int,0. 是隐含的 double0.f是float.我更喜欢使用第一种方法,因为它清晰简单,但我是否通过使用它来强制进行类型转换?
我总是假设双精度除以整数会产生更快的代码,因为编译器会选择更好的微代码来计算:
double a;
double b = a/3.0;
double c = a/3; // will compute faster than b
Run Code Online (Sandbox Code Playgroud)
对于单个操作而言,这无关紧要,但对于重复操作而言,它可能会有所不同。我的假设总是正确的还是依赖于编译器或 CPU 之类的?
同样的问题也适用于乘法;即会3 * a比3.0 * a?
我正在评估我的项目的网络+渲染工作负载。
程序连续运行一个主循环:
while (true) {
doSomething()
drawSomething()
doSomething2()
sendSomething()
}
Run Code Online (Sandbox Code Playgroud)
主循环每秒运行 60 多次。
我想查看性能故障,每个程序需要多少时间。
我担心的是,如果我打印每个程序的每个入口和出口的时间间隔,
这会导致巨大的性能开销。
我很好奇什么是衡量性能的惯用方法。
日志打印是否足够好?
我使用浮点数进行这些操作:
这两个哪个更准确呢?
或者
这到底重要还是取决于具体情况?如果是这样,在什么情况下我应该选择哪一个?
c++ ×8
c ×3
c# ×2
performance ×2
.net ×1
architecture ×1
assembly ×1
benchmarking ×1
clr ×1
intel ×1
java ×1
literals ×1
optimization ×1
precision ×1
x86 ×1