int32_t的延迟是否低于int8_t,int16_t和int64_t?

use*_*112 2 c++ optimization performance assembly cpu-architecture

(我指的是Intel CPU,主要是GCC,但可能是ICC或MSVC)

是真的使用int8_t,int16_tint64_t与相比效率较低int32_t,由于生成向CPU字大小和所选择的可变大小之间进行转换的附加指令?

如果有人有任何示例或最佳实践,我会感兴趣吗?我有时使用较小的变量大小来减少缓存行负载,但是我说只消耗了50个字节的缓存行,其中一个变量是8位int,通过使用剩余的缓存行空间并将8位int提升为a,可以更快地处理32位int等?

小智 6

Mark Lakata 的回答指出了正确的方向。
我想补充几点。

Agner文档是理解和做出优化决策的绝佳资源。

指令表文件有最常见的指令的等待时间。您可以看到其中一些在本机大小版本中表现更好。
一种mov例如可以被消除,一个mul具有更短的延迟。
然而,这里我们谈论的是获得 1 个时钟,我们将不得不执行大量指令来补偿缓存未命中。
如果这是整个故事,那就不值得了。

真正的问题来自解码器。
当您使用一些改变长度的前缀(并且您将使用非本机大小字)时,解码器需要额外的周期。

因此,操作数大小前缀会更改指令其余部分的长度。预解码器无法在单个时钟周期内解决此问题。从这个错误中恢复需要 6 个时钟周期。因此,避免这种长度变化的前缀非常重要。

在现在,不再是最近(但仍然存在)的微弓中,惩罚是严厉的,特别是一些算术指令。
在后来的微弓中,这已经得到缓解,但仍然存在惩罚。

要考虑的另一个方面是使用非本机大小需要为指令添加前缀,从而生成更大的代码。这是尽可能最接近语句“生成附加指令以在 CPU 字大小和所选变量大小之间进行转换”的语句,因为 Intel CPU 可以处理非本机字大小。
对于其他的,特别是 RISC 的 CPU,这通常不是真的,可以生成更多指令。

因此,在优化使用数据缓存的同时,您也错误地使用了指令缓存

在常见的 x64 ABI 上,堆栈必须在 16 字节边界上对齐并且通常编译器以本机字大小或接近的字大小(例如 64 位系统上的 DWORD)保存本地变量,这一点也毫无价值。
仅当您分配足够数量的局部变量或使用数组或打包结构时,您才能从使用小变量大小中获益。
如果您声明单个uint16_tvar,它可能会占用与 single 相同的堆栈空间uint64_t,因此最好选择最快的大小。

此外,当涉及到数据缓存时,重要的是位置,而不仅仅是数据大小。

那么该怎么办?

幸运的是,您不必在拥有小数据或小代码之间做出选择。

如果您有大量数据,通常使用数组或指针以及使用中间变量来处理。这行代码就是一个例子。

t = my_big_data[i];
Run Code Online (Sandbox Code Playgroud)

我的方法是:

  • 保持数据的外部表示,即my_big_data数组,尽可能小。例如,如果该数组存储温度uint8_t为每个元素使用一个编码 。

  • 保持数据的内部表示,即t变量,尽可能接近 CPU 字长。例如t可以是 auint32_tuint64_t

通过这种方式,您可以对两个缓存进行编程优化并使用本机字大小。
作为奖励,您可以稍后决定切换到 SIMD 指令,而无需重新打包my_big_data内存布局。


真正的问题是程序员在错误的地方和错误的时间花费了太多时间来担心效率;过早优化是编程中所有邪恶(或至少大部分)的根源。
D. 克努斯

当你设计你的结构内存布局是由问题驱动的。例如,年龄值需要 8 位,以英里为单位的城市距离需要 16 位。
当您编码算法时,使用已知编译器对该范围具有的最快类型。例如整数比浮点数快,uint_fast8_t不比uint8_t.

当那么它是时间通过改变算法(通过使用更快的类型,从而消除冗余操作,等等),然后,以改善性能开始如果需要它的数据结构(由调心,填充,包装等)。


Mar*_*ata 5

您可以将更多uint8_ts 填充到缓存行中,因此加载N uint8_ts将比加载N uint32_ts 更快.

此外,如果您使用带有SIMD指令的现代英特尔芯片,智能编译器将对其进行矢量化.同样,在代码中使用一个小变量将允许编译器将更多通道填充到SIMD寄存器中.

我认为最好使用最小的尺寸,并将细节留给编译器.当涉及到这样的东西时,编译器可能比你(和我)更聪明.对于许多操作(比如无符号加法),编译器可以使用相同的代码uint8,uint16或者uint32(并且忽略高位),因此没有速度差异.

最重要的是,高速缓存未命中比任何算术或逻辑操作都要昂贵,因此担心缓存(以及数据大小)几乎总是比简单算术更好.

(过去很长一段时间,在Sun工作站上,使用double速度明显快float,因为硬件只支持double.我认为现代x86不再如此,因为SIMD硬件(SSE等)直接支持单精度和双精度).