Intel(x86_64) 64 位 vs 32 位整数运算性能差异
Intel(x86_64) 64 bit vs 32 bit integer arithmetic performance difference
我正在测试一些程序,我遇到了一个相当意外的异常。
我编写了一个计算素数的简单程序,并使用 pthreads API 来并行化此工作负载。
在进行了一些测试后,我发现如果我使用 uint64_t 作为计算和循环的数据类型,程序在 运行 上花费的时间比我使用 uint32_t 时要多得多.
这是我 运行:
的代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#define UINT uint64_t
#define SIZE (1024 * 1024)
typedef struct _data
{
UINT start;
UINT len;
int t;
UINT c;
}data;
int isprime(UINT x)
{
uint8_t flag = 1;
if(x < 2)
return 0;
for(UINT i = 2;i < x/2; i++)
{
if(!(x % i ))
{
flag = 0;
break;
}
}
return flag;
}
void* calc(void *p)
{
data *a = (data*)p;
//printf("thread no. %d has start: %lu length: %lu\n",a->t,a->start,a->len);
for(UINT i = a->start; i < a->len; i++)
{
if(isprime(i))
a->c++;
}
//printf("thread no. %d found %lu primes\n", a->t,a->c);
pthread_exit(NULL);
}
int main(int argc,char **argv)
{
pthread_t *t;
data *a;
uint32_t THREAD_COUNT;
if(argc < 2)
THREAD_COUNT = 1;
else
sscanf(argv[1],"%u",&THREAD_COUNT);
t = (pthread_t*)malloc(THREAD_COUNT * sizeof(pthread_t));
a = (data*)malloc(THREAD_COUNT * sizeof(data));
printf("executing the application on %u thread(s).\n",THREAD_COUNT);
for(uint8_t i = 0; i < THREAD_COUNT; i++)
{
a[i].t = i;
a[i].start = i * (SIZE / THREAD_COUNT);
a[i].len = a[i].start + (SIZE / THREAD_COUNT);
a[i].c = 0;
}
for(uint8_t i = 0; i < THREAD_COUNT; i++)
pthread_create(&t[i],NULL,calc,(void*)&a[i]);
for(uint8_t i = 0; i < THREAD_COUNT; i++)
pthread_join(t[i],NULL);
free(a);
free(t);
return 0;
}
我在 uint32_t 和 uint64_t 之间更改了 UINT 宏并编译了 运行 程序并使用 linux 上的时间命令确定了它的 运行time .
我发现 uint64_t 的 运行 时间与 uint32_t 的时间存在重大差异。
在使用 uint32_t 时,程序 46s 到 运行 而使用 uint64_t 时,程序 2m49s 到 运行!
我在这里写了一篇博客post:https://qcentlabs.com/index.php/2021/02/01/intelx86_64-64-bit-vs-32-bit-arithmetic-big-performance-difference/
如果您想了解更多信息,可以查看 post。
这背后的问题可能是什么? x86_64 上的 64 位算术比 32 位算术慢吗?
一般来说,64 位算法与 32 位算法一样快,忽略诸如占用更多内存和 BW(带宽)的较大操作数之类的事情,并且在 x86-64 上寻址完整的 64 位寄存器需要更长的指令。
但是,您成功地遇到了此规则的少数例外之一,即用于计算除法的 div
指令。
我正在测试一些程序,我遇到了一个相当意外的异常。
我编写了一个计算素数的简单程序,并使用 pthreads API 来并行化此工作负载。
在进行了一些测试后,我发现如果我使用 uint64_t 作为计算和循环的数据类型,程序在 运行 上花费的时间比我使用 uint32_t 时要多得多.
这是我 运行:
的代码#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#define UINT uint64_t
#define SIZE (1024 * 1024)
typedef struct _data
{
UINT start;
UINT len;
int t;
UINT c;
}data;
int isprime(UINT x)
{
uint8_t flag = 1;
if(x < 2)
return 0;
for(UINT i = 2;i < x/2; i++)
{
if(!(x % i ))
{
flag = 0;
break;
}
}
return flag;
}
void* calc(void *p)
{
data *a = (data*)p;
//printf("thread no. %d has start: %lu length: %lu\n",a->t,a->start,a->len);
for(UINT i = a->start; i < a->len; i++)
{
if(isprime(i))
a->c++;
}
//printf("thread no. %d found %lu primes\n", a->t,a->c);
pthread_exit(NULL);
}
int main(int argc,char **argv)
{
pthread_t *t;
data *a;
uint32_t THREAD_COUNT;
if(argc < 2)
THREAD_COUNT = 1;
else
sscanf(argv[1],"%u",&THREAD_COUNT);
t = (pthread_t*)malloc(THREAD_COUNT * sizeof(pthread_t));
a = (data*)malloc(THREAD_COUNT * sizeof(data));
printf("executing the application on %u thread(s).\n",THREAD_COUNT);
for(uint8_t i = 0; i < THREAD_COUNT; i++)
{
a[i].t = i;
a[i].start = i * (SIZE / THREAD_COUNT);
a[i].len = a[i].start + (SIZE / THREAD_COUNT);
a[i].c = 0;
}
for(uint8_t i = 0; i < THREAD_COUNT; i++)
pthread_create(&t[i],NULL,calc,(void*)&a[i]);
for(uint8_t i = 0; i < THREAD_COUNT; i++)
pthread_join(t[i],NULL);
free(a);
free(t);
return 0;
}
我在 uint32_t 和 uint64_t 之间更改了 UINT 宏并编译了 运行 程序并使用 linux 上的时间命令确定了它的 运行time .
我发现 uint64_t 的 运行 时间与 uint32_t 的时间存在重大差异。
在使用 uint32_t 时,程序 46s 到 运行 而使用 uint64_t 时,程序 2m49s 到 运行!
我在这里写了一篇博客post:https://qcentlabs.com/index.php/2021/02/01/intelx86_64-64-bit-vs-32-bit-arithmetic-big-performance-difference/
如果您想了解更多信息,可以查看 post。
这背后的问题可能是什么? x86_64 上的 64 位算术比 32 位算术慢吗?
一般来说,64 位算法与 32 位算法一样快,忽略诸如占用更多内存和 BW(带宽)的较大操作数之类的事情,并且在 x86-64 上寻址完整的 64 位寄存器需要更长的指令。
但是,您成功地遇到了此规则的少数例外之一,即用于计算除法的 div
指令。