我正在研究(相当大的)现有的单线程C应用程序。 在这种情况下,我修改了应用程序来执行一些额外的工作,每次我们调用一个特殊的函数(这个函数被称为〜80.000次),递增一个计数器。 该应用程序在运行64位Linux内核3.2.0-31的Ubuntu 12.04上进行编译 – 与-O3选项一起使用。
令人惊讶的代码的仪表版本运行速度更快,我正在调查为什么。我用clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
来衡量执行时间,并获得代表性的结果,我报告平均执行时间值超过100次运行。 此外,为了避免来自外界的干扰,我尽可能地在没有任何其他应用程序运行的情况下尝试启动应用程序(在附注中,因为CLOCK_PROCESS_CPUTIME_ID返回处理时间而不是挂钟时间,所以其他应用程序“应该”在理论只影响caching而不直接影响stream程的执行时间)
我怀疑“指令caching效应”,也许有点大(less量字节)的检测代码适合不同和更好的caching,这个假设是可以想象的吗? 我试图用valegrind –tool = cachegrind做一些caching调查,但不幸的是,仪表版本(似乎是逻辑上的)比初始版本更多的caching未命中。
这个主题和想法的任何提示都可以帮助我们找出为什么仪表代码运行得更快,这是可以接受的(某些GCC优化可以在一种情况下使用,为什么?)
由于这个问题的细节并不多,所以在调查问题时,我只能提出一些考虑因素。
很少有额外的工作(如递增计数器)可能会改变编译器是否应用某些优化的决定。 编译器并不总是有足够的信息来做出完美的选择。 它可能会尝试优化速度瓶颈是代码大小。 当没有太多的数据要处理时,它可能会尝试自动向量化计算。 编译器可能不知道要处理什么类型的数据或CPU的确切型号,它将执行代码。
即使此更改不影响编译器优化,也可能会改变CPU如何执行代码的方式。
为了调查编译器优化的效果,您可以比较在添加反递增代码之前和之后生成的汇编代码。
要调查CPU效应,请使用分析器来检查处理器性能计数器。
根据我对嵌入式编译器的经验猜测,编译器中的优化工具寻找递归任务。 也许额外的代码迫使编译器看到更多的递归,并以不同的方式构造机器代码。 编译器做一些奇怪的事情来优化。 在某些语言中(Perl我认为?)一个“不是”条件是比“真实”条件执行更快。 您的调试工具是否允许您单步执行代码/汇编比较? 这可以增加一些关于编译器决定如何处理额外任务的见解。