64位编程技术及其优化

64位编程技术及其优化

By Minidxer | October 8, 2007

 

简介
在市场上大多数CPU和操作系统支持64的操作处理。这种模式特别有利于需要运行大量数据的科学和工程应用。主要优势在于可使用巨大的地址空间。程序能够分配两次更多内存,容易维护大型数据库等。并且还有一定的性能优化优势。大多数64位机器运算集中能力处理需要超过4GB的内存。目前版本的BM library没有涉及内存问题,而是关注于表现方面。64位CPU在同一时间运行64位的计算是可以而且必须的功能。

64-bit Safety

可惜如今的很多软件并没有利用64位微处理器的优势,甚至经常不能在64位模式下编译运行。在这种情况下常常运行32位兼容模式。这真是对芯片的一种浪费啊。所以,让我们面对挑战来看一下如果我们用64位CPU替代32位系统出现的不当C编码。

  1. 事实上指针大小和整形相同。64位系统sizeof(void*) == 8 and sizeof(int) 通常保持4。忽略可能会导致的不正确分配和冲突。
  2. 依赖某一字节按机器语言排序。这对位设置的执行特别重要,因为位集合(bitset)可以是字节,整形或者长整形。
  3. 使用长形推测他和int同样大,直接转换这种类型 可能导致几乎不可发现的问题。
  4. 堆变量排列。堆变量有时可以不定位在8位界面。如果直接把这样的变量换成64位变量对系统可能碰到些麻烦。但是如果你把64位变量(长整型或双整形)转换为堆却保证绝对一致。堆分配的内存也是一致。
  5. 不同结构和阶层的排列规则。64位组织结构通常被排列在64位界面。这导致在IPC,网络(network)和磁盘(disk)共享二进制数据时出现问题。打包数据结构节省资源时如果不考虑排列因素可能会造成问题。
  6. 指针运算,64位指针增量为32位指针,反之亦然。64位指针变为32位增8字节,32位指针变为64位减少4字节。
  7. 缺少函数返回值时默认为整型(int),这可能造成值短缺。现在回头来看软件端口安全目录,我们能。。。

每个时间周期下获得最大工作效率

高性能64位C程序的关键点在于广泛的整数运算处理寄存器。寄存器(Registers)是一种昂贵的计算机内存。64位CPU寄存器是8字节。它通常伴随相应的128位或256位内存通路。我们的目标是有效地利用这些资源。

让我们来看一段C编码的短例。在一块内存中进行与(AND)操作,基于整数位集合块

{
int a1[2048];
int a2[2048];
int a3[2048];
for (int i = 0; i < 2048; ++i)
{
a3[i] = a1[i] & a2[i];
}
}

现在我们能优化以上这段编码为64位模式。(这段编码是长C形并不是有编译器提供)

{
long long a1[1024];
long long a2[1024];
long long a3[1024];
for (int i = 0; i < 1024; ++i)
{
a3[i] = a1[i] & a2[i];
}
}

如你所见,我们并没有改变位集合块的总体大小。但AND的矢量运算只花了两次很少的操作。这减少了架设回路并且等价与用系数2展开回路。缺点在于它是纯64位。用32位系统汇编时由于长度不同而提示错误信息。

进一步的优化可如下所示:

{
int a1[2048];
int a2[2048];
int a3[2048];
long long* pa1 = (long long*) a1;
long long* pa2 = (long long*) a2;
long long* pa3 = (long long*) a3;
for (int i = 0; i < sizeof(a1) / sizeof(long long); ++i)
{
pa3[i] = pa1[i] & pa2[i];
}
}

以上代码是32位和稳定的64位以及使用寄存器在64位CPU上工作。如果这样编码写得话,我们要记住指针的位置。如果我们盲目的用整数(int)指针作为64位长指针,有可能产生地址不为8位的情况。对于一些结构来说这将造成总线(BUS)错误及冲突。这一影响发现于Sun Solaris。很可能是32位整数变量(int variable),形成堆将有4位对应地址,那以上的编码就无用了。

位计数(Bits counting )

在位设置运算中最重要的操作就是计算1位的数目。BM使用整数位矢量,这意味着每一个位矢量是由整数列作为一个最小单位组成。BM的默认方法是把每个整数分成4字节然后查找包含位计数的表。使用16位宽表这种能提高该线性方法的效率,代价是生成巨大的列表。巨大的列表很有可能产生额外内存的存取操作,妨碍CPU缓存最后导致性能并没有得到显著提升。

int count(long long b)
{
b = (b & 0×5555555555555555LU) + (b >> 1 & 0×5555555555555555LU);
b = (b & 0×3333333333333333LU) + (b >> 2 & 0×3333333333333333LU);
b = b + (b >> 4) & 0×0F0F0F0F0F0F0F0FLU;
b = b + (b >> 8);
b = b + (b >> 16);
b = b + (b >> 32) & 0×0000007F;
return (int) b;
}

这段代码的灵感来自于Gutman 2000年9月在Dr.Dobb’s 杂志上发表的”Exploiting 64-Bit parallelism 开发64位并行”。实验表明,这段代码将表计数的方法远远的甩在身后。

执行(Implementation 

目前BM 版本使用64位运算优化提高性能。为了转换成你所需要的在制作文件前或进行中头文件预先定义BM640PT宏函数。这一选项使得64位长整形可使用。执行时允许该选项在32位机器上例如Intel x86 CPU编辑运行BM。不用说,这样的操作你很快就会发现不但没有利用优势反而使得性能降低了。

明智得在例如Intel Itanium, MIPS, HP PA-RISC, IBM’s POWER Series, Compaq Alpha, Sun UltraSPARC等64位CPU上使用该选项。

总结

我们已经讲述了几种如何利用64位操作来提高位间运算的性能。由于Intel和AMD扩大了64位处理器的生产线的背景下,转换成64位系统变得特别重要。如果你知道其他能提高改善64位性能的方法,我将会很高兴听到这一消息。

你可能感兴趣的:(数据结构,编程,优化,Solaris,性能优化,library)