变量x为int,可能的值为:-1, 0, 1, 2, 3。哪个表达式更快(以CPU计时周期为单位):
1 2
| 1. (x < 0)
2. (x == -1) |
语言:C/C++,但我想所有其他语言都会有相同的语言。
另外,我个人认为答案是(x < 0)。
更广泛地说,对于古鲁来说,如果x从-1到2^30呢?
- 要回答这种低级的考虑,CPU架构将是一个最小的信息,你不认为吗?但即便如此,对于这些条件,需要不同周期的CPU也将是相当原始的。
- 在任何相当现代的CPU上(在过去十年左右),如果任何32位整数比较花费了不止一个周期,我会感到惊讶。
- 为什么这个问题不好?对这一问题的彻底回答将使我们更好地理解处理器的工作原理和类似的东西。这不是好事吗?
- 如果你正在优化到如此低的水平,你就错了。唯一有意义优化这种操作的语言是汇编语言,您应该有一个很好的理由。
- 在当今的处理器体系结构和编译器中,汇编程序可能不会再快了。编译器的输入定义了它应用于结果指令的约束,不同的约束可能导致不同的执行代码。
- 最后一点:对于这样的问题,没有办法概括出答案。最好的方法是用你的产品编译器和一个有代表性的测试系统来尝试这两种方法,并比较结果。我很惊讶这种问题出现的频率有多高,几分钟的基准测试可以提供答案。
- 我相信他只是想了解更多。优化这是愚蠢的。其实我很好奇,因为我不知道。+我的1
- @伊斯梅尔:听起来你从来没有研究过嵌入式代码。
- 你是否也在同一个地方比较0,1,2,3?因为开关/外壳将是一个选项。
- 你能告诉我们周围的代码吗?可能有一些非常重要的方法来优化代码。
- 是的,显示代码!还有其他的检查方法。你可以加一个,然后核对零。你可以用4做一个逻辑和。如果你去组装,有各种可能的捷径。但是没有办法告诉你什么最适合你发布的内容。
- 这是一个表面上愚蠢的优化。您声称了解您的算法并对其进行了分析(使其成为有效的优化),但您从未想过要查看程序集代码?
- 给我们看汇编代码
- 可能的重复是<比<=?
- 或者反过来,检查日期
这完全取决于您为其编译的ISA以及编译器优化器的质量。不要过早地优化:首先分析以找出瓶颈。
也就是说,在x86中,在大多数情况下,您会发现两者速度相同。在这两种情况下,您都有一个比较(cmp和一个条件跳转(jCC指令)。但是,对于(x < 0)来说,有些情况下编译器可以省略cmp指令,从而将代码加速一个完整的周期。
具体地说,如果值x存储在寄存器中,并且最近是在eflags寄存器中设置符号标志sf的算术运算(如add或sub的结果,但还有更多的可能性),则不需要cmp指令,编译器只会发出EDOCX1。〔8〕指示。没有简单的jCC指令在输入为-1时跳转。
- 我不认为这是或曾经是任何程序的"瓶颈"。如果在时间上看到差异,则更可能是通过将其设置为-2而在=-1条件上"跳过"代码,因此没有终止循环(假设表达式是循环的一部分)。
- 不要忘记,CMP指令可能会被OR指令替换,这不会减少循环数,但可能会更改内存对齐方式。这可能会有所帮助,也可能适得其反,这就是为什么分析如此重要的原因。
- P.S.不要轻视这个问题——我的循环太紧了,这样的优化会有所不同。通常只有百分之几,但有时每一点点都有帮助!
- 在x86上,测试可以用来测试Reg==0,并且它应该比CMP更快。
- 甚至不仅仅依赖于ISA,还依赖于体系结构的实际实现…
- @需要Bastienl&233;ONARD引文。
- 不需要引用,不同的CPU供应商之间的管道是不同的,因此x86中的相同指令需要在2个不同的CPU上计算不同的CPU周期。
为什么?无论您使用哪种方法,编译器都会在当前编译的任何平台上对其进行优化。
如果你需要检查它是否是-1,使用(x=-1),如果你想知道它是否小于零,使用那个。写下你会大声读出的内容。
像这样的小东西不会使任何东西更快,你应该担心可读性和干净的设计,而不是哪个小操作更快。
即使它不做任何逻辑更改,也有可能是在您的平台上,两个都将在一个CPU周期内执行。
- 谢谢您。它实际上是高负载程序中的瓶颈操作符。这个1-2字符串的性能比可读性更有价值,我总是可以写//注释。
- 如果您从这么小的东西中获得了显著的性能提升,那么您的设计很可能需要重构(更合适的算法)。但正如其他人所说,通过分析来找出你目前的状况。
- 所有的瓶颈通常都很小,即使是在完美的算法设计中(尽管没有这样的算法)。我做高负荷DNA处理,对我的领域和算法非常了解。
- "所有瓶颈通常都很小",这不是很正确。大多数瓶颈来自以不正确的方式处理问题。不可能节省1个CPU时间。:
- 尼古拉:哇。这实际上比程序中的缓存未命中成本小?
试试看!做一百万次,或者更好,每次做十亿次。我敢打赌在你的结果中没有统计意义,但是谁知道——也许在你的平台和编译器上,你会找到一个结果。
这是一个伟大的实验,可以让你自己相信过早的优化可能不值得你花时间——而且很可能是"万恶之源——至少在编程中是这样的"。
x<0会更快。如果没有其他内容,它将阻止作为操作数提取常量-1。大多数体系结构都有专门的指令来与零进行比较,这样也会有所帮助。
- 在不了解体系结构和/或编译器的情况下,您如何能够分辨出这一点?
- 你在说什么建筑?我相信大多数x86指令集都可以与即时值进行比较。无需获取操作数。以下链接指向英特尔指令集参考:intel.com/assets/pdf/manual/253666.pdf
- 当然,几乎任何架构都可以与即时值进行比较。但即使在那里,指令也更大(因此需要从内存中提取另一个指令)。不算什么,除非每一盎司的性能都是关键的,这似乎就是本文的背景。我假设发问者正在写设备驱动程序之类的东西。
- 关于第一个问题,我已经研究了很长时间的架构。大约在前半打之后,模式开始出现。我对x86指令集的语义也了解得更多,这是目前大多数人所关注的。例如,任何时候在x86上对值进行任何操作时,都会设置条件位。因此,在进行计算、将值加载到寄存器等操作后,您可以使用JB指令测试负值。编译器通常会尝试利用这一点,但有些愚蠢的编译器不会。
这可能取决于比较之前的操作或成功的操作。例如,如果在进行比较之前将值赋给X,则检查符号标志可能比比较特定值更快。或者CPU的分支预测性能可能会受到所选比较的影响。
但是,正如其他人所说,这取决于CPU体系结构、内存体系结构、编译器和许多其他东西,因此没有一般的答案。
这两个操作都可以在一个CPU步骤中完成,因此它们应该具有相同的性能。
- 啊!虽然这在绝大多数芯片上都是真的,但如果你不知道他正在开发的平台,你就无法做出明确的声明。全世界都不是x86。
- 其中大部分;)
- 我想如果他问这个问题是为了一个特定的,非正常的架构,他会这样指定。如果他总的来说是问的话,我想对大多数现代建筑给出一个简单的答案。
- 当然,我没有考虑任何具体的建筑。常用的x86。
不管怎样,重要的考虑是,这实际上指导了您的程序流,并且恰好产生了相同的结果?
如果x实际上是和索引或枚举中的一个值,那么-1总是您想要的,还是任何负值都有效?现在,-1是唯一的负值,但这可能会改变。
你甚至不能断章取义地回答这个问题。如果您尝试使用一个小的微基准,那么优化器完全有可能将您的代码放入以太中:
1 2 3 4 5 6 7
| // Get time
int x = -1;
for (int i = 0; i < ONE_JILLION; i++) {
int dummy = (x < 0); // Poof! Dummy is ignored.
}
// Compute time difference - in the presence of good optimization
// expect this time difference to be close to useless. |
- 它将被编译器优化为零指令。但我理解你的想法,谢谢。
- 是的-这就是我想用一种愉快的方式说的。如果第一次不清楚,我的错。
- 您可以通过允许x和dummy转义(即,将它们的指针传递到另一个翻译单元中的函数)并引入编译器特定的内存屏障指令(如gcc的uu sync_synchronize())来在一定程度上避免这种情况。这将强制编译器发出代码来计算(x<0)并设置dummy-但也将强制内存访问。
- 最后,你将创建一个精心构建的结构来尝试测量一个没有或没有100%上下文无法测量的差异。例如,OP用"C++"和"C"来标注这个问题——两者之间有很大的差别,在不同平台上的各种编译器之间的差别要小得多。
- 在这样一小段代码中,由于缓存、优化等原因,添加测量代码可能会改变结果。
- @马克斯,是的,我就是这么说的。
尼古拉,你写道:
It's actually bottleneck operator in
the high-load program. Performance in
this 1-2 strings is much more valuable
than readability...
All bottlenecks are usually this
small, even in perfect design with
perfect algorithms (though there is no
such). I do high-load DNA processing
and know my field and my algorithms
quite well
如果是,为什么不下一步呢?
获取计时器,设置为0;
用(x<0)编译高负载程序;
启动程序和计时器;
在程序结束时,查看计时器并记住结果1。
同1;
用(x=-1)编译高负载程序;
同3;
在程序结束时,查看计时器并记住结果2。
比较结果1和结果2。
你会得到答案的。
我相信你相信这是一个真正的接受者。
我想问机器会比我们任何人都给出更可靠的答案。
我发现,即使是在你所说的代码中,我认为我知道时间的去向并不完全正确。例如,如果这是在一个内部循环中,如果有任何类型的函数调用,甚至是编译器插入的一个不可见的函数调用,那么到目前为止,该调用的开销将占主导地位。
正如其他人所说,可能没有什么区别。比较是CPU中的基本操作,芯片设计者希望尽可能快地进行比较。
但你可以考虑其他的事情。分析每个值的频率,并按该顺序进行比较。这样可以节省很多周期。当然,您仍然需要将代码编译到ASM来验证这一点。
这取决于体系结构,但是x=-1更容易出错。X<0是前进的道路。
- 不,这不是去的路。要检测错误,请使用单元测试,而不是花哨的代码。减少出错的可能性:为常量命名。通常最好直奔主题。如果目标是与-1进行比较,只需编写(x=-1),否则维护此代码的下一个开发人员将必须弄清楚为什么我们要与0进行比较("哦,好吧,实际上是对-1进行测试"),然后弄清楚(f…)是-1。
- 好吧,我们正在讨论一个理想的案例。正如你所说,没有人应该使用"神奇数字",而是常量。您可以通过这种方式与(x<=value)进行比较。通常使用计数器变量,因此这是减少错误发生的一个好方法。在现实世界中,单元测试并不总是可以完成(时间或其他约束)。显然,如果是特殊情况,您只需要检查'-1'值,(x==value),就可以了。
同样,两个操作通常在1个时钟内完成。
- 它将是一个指令获取和执行周期,但不是一个时钟周期。