C++ int32_t的延迟是否比int8_t、int16_t和int64_t低?

C++ int32_t的延迟是否比int8_t、int16_t和int64_t低?,c++,performance,assembly,optimization,cpu-architecture,C++,Performance,Assembly,Optimization,Cpu Architecture,(我指的是英特尔CPU,主要是GCC,但不是poss ICC或MSVC) 是否使用int8\u t,int16\u t或int64\u t与int32\u t相比,由于在CPU字大小和所选变量大小之间转换而生成的附加指令,因此效率较低 我很感兴趣,如果有任何人在这方面有任何例子或最佳做法?我有时使用较小的变量大小来减少缓存线负载,但假设我只消耗了缓存线的50个字节,其中一个变量是8位int,那么使用剩余的缓存线空间并将8位int提升为32位int等可能会加快处理速度。您可以在缓存线中填充更多的u

(我指的是英特尔CPU,主要是GCC,但不是poss ICC或MSVC)

是否使用
int8\u t
int16\u t
int64\u t
int32\u t
相比,由于在CPU字大小和所选变量大小之间转换而生成的附加指令,因此效率较低


我很感兴趣,如果有任何人在这方面有任何例子或最佳做法?我有时使用较小的变量大小来减少缓存线负载,但假设我只消耗了缓存线的50个字节,其中一个变量是8位int,那么使用剩余的缓存线空间并将8位int提升为32位int等可能会加快处理速度。

您可以在缓存线中填充更多的
uint8\t
s,因此,加载N
uint8\u t
s将比加载N
uint32\u t
s更快

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

我认为最好使用尽可能小的大小,细节由编译器决定。当涉及到这样的东西时,编译器可能比你(和我)更聪明。对于许多操作(比如无符号加法),编译器可以对
uint8
uint16
uint32
使用相同的代码(只需忽略高位),因此没有速度差异

归根结底,缓存未命中比任何算术或逻辑运算都要昂贵,因此担心缓存(以及数据大小)几乎总是比简单的算术好


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

标记拉卡塔回答的正确方向。
我想补充几点

文档是理解和做出优化决策的极好资源

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

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

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

在今天,不再是最近(但仍然存在)的微阵列中,惩罚是严厉的,特别是使用某种算术指令。
在后来的微阵列中,这已经减轻,但惩罚仍然存在

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

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

同样值得注意的是,在普通x64 ABI上,堆栈必须在16字节边界上对齐,并且编译器通常以本机字大小或接近字大小保存本地变量(例如64位系统上的DWORD)。
只有分配足够数量的局部变量,或者使用数组或压缩结构,才能从使用小变量大小中获益。
如果声明单个
uint16\u t
var,它可能会占用与单个
uint64\u t
相同的堆栈空间,因此最好选择最快的大小

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

那么,该怎么办? 幸运的是,您不必在小数据和小代码之间做出选择

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

t = my_big_data[i];
我的做法是:

  • 保持数据的外部表示,即
    my_big_data
    数组,尽可能小。例如,如果阵列存储温度对每个元素使用编码的
    uint8\t

  • 保持数据的内部表示,即
    t
    变量,尽可能接近CPU字大小。例如,
    t
    可以是
    uint32\u t
    uint64\u t

通过这种方式,您可以对缓存进行编程优化,并使用本机字号。
作为奖励,您以后可能会决定切换到SIMD指令,而无需重新打包
my\u big\u data
内存布局


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

当你设计你的记忆结构时