/*
有以下5种方法实现两个整数的交换
swap,swap0, swap1用汇编语言编写
swap2, swap3用C语言编写
swap用中间变量方式实现
swap0用xchg指令实现
swap1用xor方法实现
swap2也是用xor方法实现
swap3用中间变量方法实现
问题:目的是测一测不同的swap函数的执行效率,看看C和汇编、不同算法之间的差别,分别计了一下时间,本以为使用xchg指令时间应该最短,但是结果却是xchg时间最长,而用c语言写的程序时间却最短。查看反汇编,C语言写的swap函数指令并不比汇编swap指令少,执行上用时却最少,很让人费解。
更费解的是,调整一下函数的声明顺序,执行时间上也不尽相同。
请高手给一个合理解释,最好有对应的测试代码,证明这个情况到底源于哪里呢??
*/
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
void swap(int *x, int *y)
{
_asm
{
mov ecx, x
mov edx, y
mov eax, [ecx]
mov ebx, [edx]
mov [ecx], ebx
mov [edx], eax
}
}
void swap0(int *x, int *y)
{
_asm
{
mov ecx, x
mov edx, y
mov eax, [ecx]
xchg eax, [edx]
xchg eax, [ecx]
}
}
void swap1(int *x, int *y)
{
_asm
{
mov ecx, x
mov edx, y
mov eax, [ecx]
xor eax, [edx]
mov ebx, eax
xor ebx, [edx]
mov [edx], ebx
xor eax, ebx
mov [ecx], eax
}
}
void swap2 (int *x, int *y)
{
*x = *x ^ *y;
*y = *x ^ *y;
*x = *x ^ *y;
}
void swap3 (int *x, int *y)
{
register z;
z = *x;
*x = *y;
*y = z;
}
int main(void)
{
int z1 = 3, z2 = 4;
int i;
int c = 50000000;
clock_t x;
x = clock();
for (i = 0; i < c; i++)
swap0(&z1, &z2);
printf("t0 = %d\t asm xchg\n", clock() - x);
x = clock();
for (i = 0; i < c; i++)
swap1(&z1, &z2);
printf("t1 = %d\t asm xor\n", clock() - x);
x = clock();
for (i = 0; i < c; i++)
swap2(&z1, &z2);
printf("t2 = %d\t c xor\n", clock() - x);
x = clock();
for (i = 0; i < c; i++)
swap3(&z1, &z2);
printf("t3 = %d\t c temp\n", clock() - x);
x = clock();
for (i = 0; i < c; i++)
swap(&z1, &z2);
printf("t = %d\t asm temp\n", clock() - x);
getchar();
return 0;
}
比较两次结果
这是完全相同的程序和配置多次运行的差异,再看下面这个
这是去掉了优化配置后的运行结果。
前两个的差异和不稳定性,是多线程系统下任务分配造成的。第三个,说明工程配置和编译环境的干扰非常大。
本身来说,现在的编程环境下,各种优化各种兼容,造成了C编译器编译的程序,汇编和C语言进行相同的操作没有本质差别(只有优化差别),无法通过这个方式进行汇编和C的效率比较。
如果要比较,那么安装一个纯UNIX吧(这个下面还可以获取微妙级时间片),通过纯汇编程序和纯C程序进行比较,才能看到差别。
总结:当前C编译器下,汇编和C代码运算几乎没有差异,而xchg,我认为是编译器没有相关优化造成的结果。
就是调整了一下函数声明的顺序,比如把swap3放在最开始,似乎是最先声明的函数,执行时间上会慢下来,不知何故。
另外,能否简要举例说明一下C是怎么被优化成适合硬件特性的,谢谢
可能是缓存cache问题吧。
刚开始没有任何缓存,所以速度慢。
比如第一个函数,没有cache,执行它的时候,把包含它的程序从磁盘读到内存。但是显然,一次性读取的大小,并不只是第一个函数,比如一次读取4k,显然会把后面几个函数全部读入。
所以,第二个第三个在读取第一个的时候一起读入了。所以就快了。
你可以,写几个无聊的函数,放在这些函数前面。那么这些swap函数就是平等的了。
比如无聊的函数可以这样写
void swap_wuliao1(int *x, int *y)
{
_asm
{
mov ecx, x
mov edx, y
mov eax, [ecx]
mov ebx, [edx]
mov [ecx], ebx
mov [edx], eax
}
}
void swap_wuliao2 (int *x, int *y)
{
*x = *x ^ *y;
*y = *x ^ *y;
*x = *x ^ *y;
}
这2个函数和后面真的使用的函数式一样的,仅仅名称不一样。
把这2个函数放在最前面执行。作为warm up函数。