![](/img/trans.png)
[英]Do int8_t, int16_t, int32_t and int64_t have same respective ranges on different C++ compilers?
[英]Does int32_t have lower latency than int8_t, int16_t and int64_t?
(我指的是Intel CPU,主要是GCC,但可能是ICC或MSVC)
使用int8_t
是真的, int16_t
或int64_t
与int32_t
相比效率较低,因为生成了额外的指令来在CPU字大小和所选变量大小之间进行转换?
如果有人有任何示例或最佳实践,我会感兴趣吗? 我有时使用较小的可变大小来减少缓存行负载,但是我说只消耗了50个字节的缓存行,其中一个变量是8位int,通过使用剩余的缓存行空间并将8位int提升为a,可以更快地处理32位int等?
您可以将更多uint8_t
s填充到缓存行中,因此加载N uint8_t
将比加载N uint32_t
更快。
此外,如果您使用带有SIMD指令的现代英特尔芯片,智能编译器将对其进行矢量化。 同样,在代码中使用一个小变量将允许编译器将更多通道填充到SIMD寄存器中。
我认为最好使用最小的尺寸,并将细节留给编译器。 当涉及到这样的东西时,编译器可能比你(和我)更聪明。 对于许多操作(比如无符号加法),编译器可以对uint8
, uint16
或uint32
使用相同的代码(并忽略高位),因此没有速度差异。
最重要的是,高速缓存未命中比任何算术或逻辑操作都要昂贵,因此担心缓存(以及数据大小)几乎总是比简单算术更好。
(过去很长一段时间,在Sun工作站上,使用double
比float
显着快,因为硬件只支持double
。我认为现代x86不再是真的,因为SIMD硬件(SSE)等)直接支持单精度和双精度)。
Mark Lakata在正确的方向上回答了问题。
我想补充一些观点。
Agner文档是了解和优化决策的绝佳资源。
指令表文档具有最常见指令的延迟。 您可以看到其中一些在原生大小版本中表现更好。
例如,可以消除mov
, mul
具有较少的延迟。
然而,我们在谈论获得1个时钟 ,我们将不得不执行大量指令来补偿缓存未命中。
如果这是整个故事,那将是不值得的。
解码器带来了真正的问题。
当您使用一些长度变化的前缀(并且您将使用非原生大小的单词)时,解码器需要额外的周期。
因此,操作数大小前缀会更改指令其余部分的长度。 预编码器无法在单个时钟周期内解决此问题。 从此错误中恢复需要6个时钟周期。 因此,避免这种长度变化的前缀非常重要。
现在,不再是最近(但现在仍然存在)的微观,惩罚是严厉的,特别是有一些类型的算术指令。
在后来的微观领域,这已经得到了缓解,但仍然存在惩罚。
要考虑的另一个方面是使用非本机大小需要在指令前添加前缀 ,从而生成更大的代码。 尽管英特尔CPU可以处理非本机字大小,但它最接近声明“ 生成用于在CPU字大小和所选变量大小之间进行转换的附加指令 ”。
对于其他特别是RISC,CPU,这通常不正确,可以生成更多指令。
因此,在充分利用数据缓存时, 您也会错误地使用指令缓存 。
在常见的x64 ABI上,堆栈必须在16字节边界上对齐并且通常编译器以本机字大小或接近的一个(例如64位系统上的DWORD)保存本地变量也是值得的。
只有在分配足够数量的本地变量或者使用数组或压缩结构时,才能从使用小变量大小中获益。
如果声明一个uint16_t
var,它可能会占用单个uint64_t
的相同堆栈空间,因此最好选择最快的大小。
此外,当它来到数据缓存时,它是重要的位置 ,而不仅仅是数据大小。
幸运的是,您无需在拥有小数据或小代码之间做出决定。
如果您有相当数量的数据,通常使用数组或指针以及使用中间变量来处理。 这一行代码就是一个例子。
t = my_big_data[i];
我的方法是:
保持数据的外部表示,即my_big_data
数组尽可能小。 例如,如果该阵列存储温度对每个元素使用编码的uint8_t
。
保持数据的内部表示,即t
变量,尽可能接近CPU字大小。 例如, t
可以是uint32_t
或uint64_t
。
这样,您可以编程优化两个缓存并使用本机字大小。
作为奖励,您可以稍后决定切换到SIMD指令,而无需重新my_big_data
内存布局。
真正的问题是程序员花费了太多时间来担心在错误的地方和错误的时间提高效率; 过早优化是编程中所有邪恶(或至少大部分)的根源。
D. Knuth
在设计结构时,内存布局应该是问题驱动的。 例如,年龄值需要8位,城市距离以英里为单位需要16位。
在对算法进行编码时,使用已知编译器对该范围具有的最快类型。 例如,整数比浮点数快, uint_fast8_t
不比uint8_t
慢。
那时,是时候通过改变算法(通过使用更快的类型,消除冗余操作等)来改善性能开始,然后如果需要数据结构(通过对齐,填充,打包等)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.