有什么理由在64位CPU上使用32位整数进行常见操作吗?

时间:2022-02-22 04:58:56

I wonder if it's a good idea to keep using int (which is 32 bit on both x86 and x86_64) on 64 bit programs for variables that have nothing special and do not really need to span up to 2^64, like iteration counters, or if it's better to use size_t which matches the word size of the CPU.

我想知道在64位程序中继续使用int(在x86和x86_64上都是32位)对于没有任何特殊的变量并且实际上不需要跨越2 ^ 64(如迭代计数器),或者如果最好使用与CPU的字大小相匹配的size_t。

For sure if you keep using int you save half of the memory, and that could mean something speaking about CPU cache, but I don't know then if on 64 bit machine every 32 bit number has to be extended to 64 bit before any use.

当然,如果你继续使用int,你可以节省一半的内存,这可能意味着谈论CPU缓存,但我不知道如果在64位机器上,每个32位数字必须在任何使用之前扩展到64位。

EDIT: I've ran some test with a program of mine (see the self answer, I still keep janneb's as accepted though because it is good). It turns out that there is a significant performance improvement.

编辑:我已经用我的程序进行了一些测试(参见自我回答,我仍然保持janneb的接受,因为它很好)。事实证明,性能有了显着提升。

4 个解决方案

#1


4  

For array indices and pointer arithmetic, types which are of the same size as a pointer (typically, size_t and ptrdiff_t) can be better, as they avoid the need to zero or sign extend the register. Consider

对于数组索引和指针算法,与指针(通常是size_t和ptrdiff_t)大小相同的类型可以更好,因为它们避免了对寄存器进行零或符号扩展的需要。考虑


float onei(float *a, int n)
{
  return a[n];
}

float oneu(float *a, unsigned n)
{
  return a[n];
}

float onep(float *a, ptrdiff_t n)
{
  return a[n];
}

float ones(float *a, size_t n)
{
  return a[n];
}

With GCC 4.4 -O2 on x86_64 the following asm is generated:

在x86_64上使用GCC 4.4 -O2生成以下asm:


    .p2align 4,,15
.globl onei
    .type   onei, @function
onei:
.LFB3:
    .cfi_startproc
    movslq  %esi,%rsi
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE3:
    .size   onei, .-onei
    .p2align 4,,15
.globl oneu
    .type   oneu, @function
oneu:
.LFB4:
    .cfi_startproc
    mov %esi, %esi
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE4:
    .size   oneu, .-oneu
    .p2align 4,,15
.globl onep
    .type   onep, @function
onep:
.LFB5:
    .cfi_startproc
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE5:
    .size   onep, .-onep
    .p2align 4,,15
.globl ones
    .type   ones, @function
ones:
.LFB6:
    .cfi_startproc
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE6:
    .size   ones, .-ones

As can be seen, the versions with the int and unsigned int index (onei and oneu) requires an extra instruction (movslq/mov) to sign/zero extend the register.

可以看出,具有int和unsigned int索引(onei和oneu)的版本需要一个额外的指令(movslq / mov)来对寄存器进行符号/零扩展。

As was mentioned in a comment, the downside is that encoding a 64-bit register takes more space than the 32-bit part, bloating the code size. Secondly, ptrdiff_t/size_t variables need more memory than the equivalent int; if you have such arrays it can certainly affect performance much more than the relatively small benefit of avoiding the zero/sign extension. If unsure, profile!

正如评论中提到的,缺点是编码64位寄存器比32位部分占用更多空间,使代码大小膨胀。其次,ptrdiff_t / size_t变量需要比等效int更多的内存;如果你有这样的数组,它肯定会影响性能远远超过避免零/符号扩展的相对较小的好处。如果不确定,简介!

#2


3  

In terms of Cache, it will save space; cache handles blocks of data, regardless of whether CPU requested a single address or the complete chunk equal to cache block size.

在Cache方面,它将节省空间;缓存处理数据块,无论CPU是请求单个地址还是完整块等于缓存块大小。

So if you are asking whether 32-bit numbers take 64-bits of space inside caches on 64 bit machines then the answer is no, they will still take 32 bits for themselves. So in general, it will save you some space, especially if you are using large arrays with frequent accesses etc.

因此,如果你问的是32位数字是否在64位机器上的高速缓存中占用64位空间,那么答案是否定的,它们仍将为自己占用32位。所以一般来说,它会为你节省一些空间,特别是如果你使用频繁访问的大型数组等。

In my personal opinion, a simple int looks simpler than size_t and most editors will not recognize size_t type so syntax highlighting will also be better if you use int. ;)

在我个人看来,一个简单的int看起来比size_t简单,并且大多数编辑器都不会识别size_t类型,因此如果使用int,语法高亮也会更好。 ;)

#3


3  

I am coding a little hard spheres model. The source can be found on github.

我正在编写一个小硬球模型。源可以在github上找到。

I tried to keep using size_t for variables that are used as index of arrays, and int where I do other operations, not related to word size. The performance improvement was significant: a ~27 to ~24 execution time drop.

我试图继续使用size_t作为用作数组索引的变量,并尝试使用int进行其他操作,与字大小无关。性能提升非常显着:执行时间下降~27到24。

#4


0  

This should be the compiler developer's decision.

这应该是编译器开发人员的决定。

int is the natural type for "normal" signed integers. It's up to the compiler to decide what it is.
If, on a specific platform, there's a real advantage in using 64bit integers, the compiler developer is expected to make int 64bit. The standard allows it.

int是“普通”有符号整数的自然类型。由编译器决定它是什么。如果在特定平台上使用64位整数有一个真正的优势,那么编译器开发人员应该使用int 64bit。该标准允许它。

If the compiler developer decided to stick with 32bit integers, you should normally trust him.
Maybe, in some rare cases, after a significant optimization effort, you'll find that long works better. Then you might want to change.

如果编译器开发人员决定坚持使用32位整数,那么通常应该信任他。也许,在极少数情况下,经过大量的优化工作,你会发现长期工作更好。然后你可能想要改变。

#1


4  

For array indices and pointer arithmetic, types which are of the same size as a pointer (typically, size_t and ptrdiff_t) can be better, as they avoid the need to zero or sign extend the register. Consider

对于数组索引和指针算法,与指针(通常是size_t和ptrdiff_t)大小相同的类型可以更好,因为它们避免了对寄存器进行零或符号扩展的需要。考虑


float onei(float *a, int n)
{
  return a[n];
}

float oneu(float *a, unsigned n)
{
  return a[n];
}

float onep(float *a, ptrdiff_t n)
{
  return a[n];
}

float ones(float *a, size_t n)
{
  return a[n];
}

With GCC 4.4 -O2 on x86_64 the following asm is generated:

在x86_64上使用GCC 4.4 -O2生成以下asm:


    .p2align 4,,15
.globl onei
    .type   onei, @function
onei:
.LFB3:
    .cfi_startproc
    movslq  %esi,%rsi
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE3:
    .size   onei, .-onei
    .p2align 4,,15
.globl oneu
    .type   oneu, @function
oneu:
.LFB4:
    .cfi_startproc
    mov %esi, %esi
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE4:
    .size   oneu, .-oneu
    .p2align 4,,15
.globl onep
    .type   onep, @function
onep:
.LFB5:
    .cfi_startproc
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE5:
    .size   onep, .-onep
    .p2align 4,,15
.globl ones
    .type   ones, @function
ones:
.LFB6:
    .cfi_startproc
    movss   (%rdi,%rsi,4), %xmm0
    ret
    .cfi_endproc
.LFE6:
    .size   ones, .-ones

As can be seen, the versions with the int and unsigned int index (onei and oneu) requires an extra instruction (movslq/mov) to sign/zero extend the register.

可以看出,具有int和unsigned int索引(onei和oneu)的版本需要一个额外的指令(movslq / mov)来对寄存器进行符号/零扩展。

As was mentioned in a comment, the downside is that encoding a 64-bit register takes more space than the 32-bit part, bloating the code size. Secondly, ptrdiff_t/size_t variables need more memory than the equivalent int; if you have such arrays it can certainly affect performance much more than the relatively small benefit of avoiding the zero/sign extension. If unsure, profile!

正如评论中提到的,缺点是编码64位寄存器比32位部分占用更多空间,使代码大小膨胀。其次,ptrdiff_t / size_t变量需要比等效int更多的内存;如果你有这样的数组,它肯定会影响性能远远超过避免零/符号扩展的相对较小的好处。如果不确定,简介!

#2


3  

In terms of Cache, it will save space; cache handles blocks of data, regardless of whether CPU requested a single address or the complete chunk equal to cache block size.

在Cache方面,它将节省空间;缓存处理数据块,无论CPU是请求单个地址还是完整块等于缓存块大小。

So if you are asking whether 32-bit numbers take 64-bits of space inside caches on 64 bit machines then the answer is no, they will still take 32 bits for themselves. So in general, it will save you some space, especially if you are using large arrays with frequent accesses etc.

因此,如果你问的是32位数字是否在64位机器上的高速缓存中占用64位空间,那么答案是否定的,它们仍将为自己占用32位。所以一般来说,它会为你节省一些空间,特别是如果你使用频繁访问的大型数组等。

In my personal opinion, a simple int looks simpler than size_t and most editors will not recognize size_t type so syntax highlighting will also be better if you use int. ;)

在我个人看来,一个简单的int看起来比size_t简单,并且大多数编辑器都不会识别size_t类型,因此如果使用int,语法高亮也会更好。 ;)

#3


3  

I am coding a little hard spheres model. The source can be found on github.

我正在编写一个小硬球模型。源可以在github上找到。

I tried to keep using size_t for variables that are used as index of arrays, and int where I do other operations, not related to word size. The performance improvement was significant: a ~27 to ~24 execution time drop.

我试图继续使用size_t作为用作数组索引的变量,并尝试使用int进行其他操作,与字大小无关。性能提升非常显着:执行时间下降~27到24。

#4


0  

This should be the compiler developer's decision.

这应该是编译器开发人员的决定。

int is the natural type for "normal" signed integers. It's up to the compiler to decide what it is.
If, on a specific platform, there's a real advantage in using 64bit integers, the compiler developer is expected to make int 64bit. The standard allows it.

int是“普通”有符号整数的自然类型。由编译器决定它是什么。如果在特定平台上使用64位整数有一个真正的优势,那么编译器开发人员应该使用int 64bit。该标准允许它。

If the compiler developer decided to stick with 32bit integers, you should normally trust him.
Maybe, in some rare cases, after a significant optimization effort, you'll find that long works better. Then you might want to change.

如果编译器开发人员决定坚持使用32位整数,那么通常应该信任他。也许,在极少数情况下,经过大量的优化工作,你会发现长期工作更好。然后你可能想要改变。