- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发现一个有趣的现象:
#include<stdio.h>
#include<time.h>
int main() {
int p, q;
clock_t s,e;
s=clock();
for(int i = 1; i < 1000; i++){
for(int j = 1; j < 1000; j++){
for(int k = 1; k < 1000; k++){
p = i + j * k;
q = p; //Removing this line can increase running time.
}
}
}
e = clock();
double t = (double)(e - s) / CLOCKS_PER_SEC;
printf("%lf\n", t);
return 0;
}
addl $1, -12(%rbp)
之前,速度较快的一种具有两种更多的操作:
movl -44(%rbp), %eax
movl %eax, -48(%rbp)
最佳答案
TL:DR:如果重新加载不是立即尝试进行,则Sandybridge系列存储转发的延迟较低。添加无用的代码可以加快调试模式的循环,因为-O0
反优化代码中的循环延迟延迟几乎总是涉及某些C变量的存储/重载。
其他示例:hyperthreading,calling an empty function,accessing vars through pointers。
这些都与优化代码无关。存储转发延迟有时会出现瓶颈,但是给您的代码增加无用的复杂性并不能加快速度。
您正在对调试版本which is basically useless 进行基准测试。
但是显然,一个版本的调试版本比另一版本的调试版本运行缓慢的确有原因。 (假设您正确地进行了测量,这不仅是导致挂钟时间不同的CPU频率变化(涡轮增压/节能)。)
如果您想了解x86性能分析的详细信息,我们可以尝试解释为什么asm首先执行它的方式,以及为什么额外的C语句(带有-O0
的asm编译为额外的asm指令)中的asm可以使整体速度更快。 这将告诉我们一些有关asm性能影响的信息,但对于优化C并没有任何帮助。
您没有显示整个内部循环,仅显示了部分循环主体,但是gcc -O0
是pretty predictable。每个C语句都与其他所有C语句分开编译,所有C变量在每个语句的块之间溢出/重新加载。这样,您就可以在单步执行时使用调试器来更改变量,甚至可以跳到函数中的另一行,并使代码仍然有效。以这种方式进行编译的性能成本是灾难性的。例如,您的循环没有副作用(不使用任何结果),因此整个三嵌套循环可以并且将在实际构建中编译为零指令,并且运行速度无限快。或者更现实的是,即使不进行优化或进行重大转换,每次迭代运行1个周期而不是大约6个周期。
瓶颈可能是对k
的循环依赖,带有存储/重载和add
来增加。存储转发延迟通常为around 5 cycles on most CPUs。因此,您的内部循环仅限于每〜6个周期运行一次,这是内存目标add
的延迟。
如果您使用的是Intel CPU,则当重新加载无法立即尝试执行时,存储/重新加载延迟实际上会更低(更好)。在依赖对之间有更多独立的加载/存储可能会解释您的情况。参见Loop with function call faster than an empty loop。
因此,如果在循环中进行更多工作,那么在连续运行时可以维持每6个周期吞吐量一次的addl $1, -12(%rbp)
可能只会造成每4或5个周期一次迭代的瓶颈。
根据from a 2013 blog post的测量,这种影响显然发生在Sandybridge和Haswell(不仅是Skylake)上,所以是的,这也是Broadwell i5-5257U上最有可能的解释。看来这种影响发生在所有Intel Sandybridge系列CPU 上。
如果没有有关测试硬件,编译器版本(或内部循环的asm源),以及这两个版本的绝对和/或相对性能数字的更多信息,这是我最好的省力猜测。在Skylake系统上进行基准测试/分析gcc -O0
不够有趣,无法自己亲自尝试。下次,包括计时编号。
与循环无关的链中不包含的所有工作的存储/重载延迟并不重要,仅吞吐量无关紧要。现代无序CPU中的存储队列确实有效地提供了内存重命名,从而消除了write-after-write and write-after-read hazards重复使用相同的堆栈内存来写入p
,然后在其他地方读取和写入的情况。 (有关详细的内存危害,请参见https://en.wikipedia.org/wiki/Memory_disambiguation#Avoiding_WAR_and_WAW_dependencies;有关延迟与吞吐量的关系以及更多地重用同一寄存器/寄存器重命名,请参见this Q&A)
内部循环可以一次进行多次迭代,因为内存顺序缓冲区可以跟踪每个负载需要从哪个存储区获取数据,而无需将先前的存储区移至相同的位置以提交到L1D并退出。存储队列。 (有关CPU微体系结构内部的更多信息,请参阅Intel的优化手册和Agner Fog的microarch PDF。)
这是否意味着添加无用的语句将加快实际程序的速度? (启用优化)
通常,不,它不是。编译器将循环变量保存在最内层循环的寄存器中。而无用的语句实际上将在启用优化的情况下进行优化。
调整gcc -O0
的源是没有用的。 使用-O3
或项目使用的默认构建脚本的任何选项进行度量。
另外,这种存储转发加速是特定于Intel Sandybridge系列的,除非在Ryzen之类的其他微体系结构上,您也不会看到它,除非它们也具有类似的存储转发延迟效果。
在真正的(优化的)编译器输出中,存储转发延迟可能是一个问题,尤其是如果您没有使用链接时间优化(LTO)来使微型函数内联,尤其是那些通过引用传递或返回任何内容的函数(因此它必须通过内存而不是寄存器)。如果您真的想在Intel CPU上解决该问题,则缓解此问题可能需要volatile
之类的黑客,并且可能使某些其他CPU的情况更糟。参见discussion in comments
关于performance - 在没有优化的情况下添加冗余分配可以加快代码的速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49189685/
我有下面提供的“示例代码”,我觉得这很多余,并且想请您与我一起解释是否有任何更少冗余的方法来处理以下代码。 public interface Bars { FOO1 FOO1 = (FOO1)
我们刚刚测试了一个由 2 个服务器组成的 AppFabric 集群,我们在其中删除了“领导”服务器。第二个服务器对它的任何请求超时并出现错误: Microsoft.ApplicationServer.
我正在设计一个关系数据库 - 底层是 MySQL - DBDesigner 4 . 我有 3 个表:module、page 和 lang。每个模块属于一个页面,每个页面都有特定的语言: 外键 pag
我的 Fraction 程序运行流畅,但 NetBeans IDE 告诉我以下 if 是多余的: public boolean equals(Object other) { Fraction bo
下面的代码显然是多余的,但根据我的经验,我经常使用这种模式。有没有更好的方法在 python 中执行此操作? if re.search("at (\d{1,2}):\d{2}", p): a=
我有一个用具体示例说明的一般性问题。当所有组件对象都已测试时,您建议对复合对象进行多少测试? 作为具体示例,请考虑下面的 NullTerminatedStringReader。它从字节缓冲区中读取一个
if ( a > b) { return true; } return false; 对于上面的代码,Netbeans 给出了 “Redundant if statement” 警告并建议将其更改
当我添加一些约束时,例如: create table Test( IDTest int primary key, Credit int not null constraint Credit
此代码适用于 Microchip 的 PIC32MX 微处理器。他们的编译器本质上是 GCC 3.4。 我倾向于使用 GCC 的 __packed__ attribute将位域打包到一个 union
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
我正在为我的应用程序使用apns通知,为此,我将apns设备 token 存储在我的sql数据库中。 问题在于,每次用户删除或安装该应用程序时,它都会生成一个新的设备 token ,并将其存储在数据库
Action Keyname Type Unique Packed Column Cardinality Collation Null Comment Edit Dro
我正在开发一个使用 ARM Cortex-M0 处理器的项目。在这个项目中,我需要提供计时器支持(CMSDK (SSE-200)计时器)。 因此,在 vector 表中,在 TIMER0_IRQn 表
有没有写的理由 corsFilter.setAllowedOrigins(new HashSet(Arrays.asList("*"))); 其中allowedOrigins在ReSTLet框架中的定
我正在创建一个包含 4 个链接的 HTML/CSS 页面, Home.html Details.html ContactMe.html AboutUs.html 我想在所有关联的 HTML 页面中将其
我试图理解并使用其他人编写的代码,但由于我对 typedef 经验不多。 , 我有时会感到困惑。 有两个不同的头文件,一个继承另一个,并且在两个文件上声明相同的typedef。 为什么会出现冗余,如何
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我有一个用于改造的 POJO 类。 public class AppData(){ String a; String b; String c;
我想知道: 编写这段代码: DataRow[] g = new DataRow[1] ; var t=new StringBuilder().AppendFormat("{0}", g[0]["a
只是一个性能问题...... 假设我有 5 个类,每个类都引用了 System.Data 和一个自己开发的库。这 5 个类是类库的一部分,最终将被构建并发布到一些 Web 应用程序作为引用。 通过将引
我是一名优秀的程序员,十分优秀!