您的位置:首页 > 其它

使用汇编优化BCB6的itoa

2008-04-15 20:41 316 查看
今天写了个测试itoa性能的程序,做了1千万次itoa操作,主要代码如下:
char buf[64];
unsigned long t = GetTickCount();
for (int i = 0; i <= 10000000; ++i) {

itoa(i, buf, 10);

}

unsigned long t2 = GetTickCount();
printf("last=%s, %u/n", buf, t2 - t);

分别使用VC++2003和C++BUILDER6编译,打开所有速度优化选项,结果发现性能相差很大。
VC最快用了2547ms,BCB最快用了4016ms。想想C运行库应该都是高度优化过的,怎么会有这么大的性能差距呢?

为了一探究竟,我翻出了itoa的源码,稍做修改(去掉了正负号处理)代码如下:
void myxtoa (unsigned long val, char *buf, unsigned radix)

{

char *p; /* pointer to traverse string */

char *firstdig; /* pointer to first digit */

char temp; /* temp char */

unsigned digval; /* value of digit */
p = buf;
firstdig = p; /* save pointer to first digit */
do {

digval = (unsigned) (val % radix);

val /= radix; /* get next digit */
/* convert to ascii and store */

if (digval > 9)

*p++ = (char) (digval - 10 + 'a'); /* a letter */

else

*p++ = (char) (digval + '0'); /* a digit */

} while (val > 0);
/* We now have the digit of the number in the buffer, but in reverse

order. Thus we reverse them now. */
*p-- = '/0'; /* terminate string; p points to last digit */
do {

temp = *p;

*p = *firstdig;

*firstdig = temp; /* swap *p and *firstdig */

--p;

++firstdig; /* advance to next two digits */

} while (firstdig < p); /* repeat until halfway */

}

我使用myxtoa这个函数代替C运行库中的itoa,再编译测试,VC和BCB的编译结果都比原来快了几十毫秒(去掉了符号处理当然快了)。看来BCB对这段代码优化得不如VC好。查看BCB生成的汇编代码后发现,BCB对val /= radix的编译结果是通过存储器读操作数的,没有放到寄存器中。为了测试是该语句影响了性能,将val /= radix语句注释掉,在VC和BCB下重新编译,发现BCB的运行结果居然比VC快了2倍多,看来两个编译器对寄存器变量使用的不同造成了性能上的差异。

为了证实自己的想法,我用汇编重写了myxtoa,用BCB编译,果然现在BCB版本跑的VC一样快了,基本两者都在几毫秒差距间波动。进一步使用__fastcall优化调用后,发现BCB版比VC版快了50-60ms,当然VC也能如此优化。下面是我改写的汇编代码BCB版(VC使用此代码只需对寄存器变量稍做修改即可):
void __fastcall myxtoa (unsigned long val, char *buf, unsigned radix)

{

__asm {

mov ebx, edx
mov esi, ebx

}

do {

__asm {

xor edx, edx

div ecx

}

if (_EDX > 9) {

_EDX += ('a' - 10);

}

else {

_EDX += '0';

}

__asm mov [ebx], dl

++_EBX;
} while (_EAX > 0);

/* We now have the digit of the number in the buffer, but in reverse

order. Thus we reverse them now. */

__asm mov byte ptr [ebx], 0

--_EBX;
do {

__asm {

mov cl, [ebx]

mov al, [esi]

mov [ebx], al

mov [esi], cl

}
--_EBX;
++_ESI;
} while (_ESI < _EBX); /* repeat until halfway */
}

总结,对寄存器变量的优化安排将有效提升程序性能,不过一般这种事情交给C++编译器就可以了,现在PC上的编译器已经足够强了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: