- 注册时间
- 2010-10-22
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 2292
- 在线时间
- 小时
|
楼主 |
发表于 2011-11-14 14:28:38
|
显示全部楼层
接四楼,有点小问题修正一下,131=128+2+1 , BKDR_asm1中的inc edx 应该放在 movzx之后,这样三款hash值一致,当然不影响执行效率。
是不是很不错了呢?
对imul 与乘进行逻辑分解有个权衡,这与cpu有关。之前在赛扬上测试,imul 不如分解之后的快,今个在Intel Core i5上测试,BKDR_asm0 胜过BKDR_asm1.
可见imul 的执行效率已经大大改善。
可以设想,如果通过分解后与imul的执行效率相当,那么在稍差的机器上,分解版将完胜imul版,^_^。
出于这个想法,有必要再对BKDR_asm1做进一步优化,因为BKDR_asm1在i5上输给了BKDR_asm0.
还有可能优化吗?能否再减少A00循环体的指令数呢?
BKDRHash3:- __declspec(naked)
- unsigned int __stdcall BKDRHash3(unsigned char *str)
-
- { //131=128+2+1
- //hash = hash * (128+2+1) + (*str);
- __asm{
- xor eax,eax
- mov edx,[esp+4]
- A00:
- lea ecx,[eax+eax*2]
- shl eax,7
- add eax,ecx
- movzx ecx,byte ptr [edx]
- inc edx
- add eax,ecx
- test ecx,ecx
- jnz A00
- ;---------------------------
- retn 4
- }
- }
复制代码 小结:
整个BKDR hash函数的优化过程,为了减少push pop 将movzx 置后,使得ecx 可以在movzx之前使用^_^,通过分解将乘转化为简单的逻辑运算,使用强大的指令lea 完成加乘赋值一体化。
好的组合分解又能减少不必要的操作^_^。
这次在Intel Core i5 CPU上测试,发现imul 与分解后的执行效率相当,这说明在赛扬必完胜imul ,见下图的BKDRHash1(imul版)和BDKRHash4(分解优化版):
测试代码:- #include <stdio.h>
- #include <time.h>
- #define N0 10000000
-
- //string test
- unsigned char buf[]="InitializeCriticalSectionAndSpinCount";
-
- //=====================================================
- unsigned int __stdcall BKDRHash0(unsigned char *str)
- {
- unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
- unsigned int hash = 0;
- do{
- hash = hash * seed + (*str);
- }while(*str++);
- return hash;
- }
- //=====================================================
- __declspec(naked)
- unsigned int __stdcall BKDRHash1(unsigned char *str)
-
- {
- __asm{
- xor eax, eax
- mov edx, [4+esp]
- A00:
- imul eax, 131
- movzx ecx, BYTE ptr [edx]
- inc edx
- add eax, ecx
- test ecx, ecx
- jne A00
- retn 4
- }
- }
- //=====================================================
- __declspec(naked)
- unsigned int __stdcall BKDRHash2(unsigned char *str)
- {//131=128+2+1
- //hash =(hash * 64+hash)*2+hash + (*str);
- __asm{
- xor eax,eax
- mov edx,[esp+4]
- A00:
- mov ecx,eax
- shl ecx,6
- add ecx,eax
- lea eax,[eax+ecx*2]
- movzx ecx,byte ptr [edx]
- add eax,ecx
- inc edx
- test ecx,ecx
-
- jnz A00
- ;---------------------------
- retn 4
- }
- }
-
- //=====================================================
- __declspec(naked)
- unsigned int __stdcall BKDRHash3(unsigned char *str)
-
- { //131=128+2+1
- //hash = hash * (128+2+1) + (*str);
- __asm{
- xor eax,eax
- mov edx,[esp+4]
- A00:
- lea ecx,[eax+eax*2]
- shl eax,7
- add eax,ecx
- movzx ecx,byte ptr [edx]
- inc edx
- add eax,ecx
- test ecx,ecx
- jnz A00
- ;---------------------------
- retn 4
- }
- }
-
- //=====================================================
- int main()
- {
- double t0,t1,t2,t3;
- int i,j;
- printf("Hash Value:\n");
- printf("%x " ,BKDRHash0(buf));
- printf("%x " ,BKDRHash1(buf));
- printf("%x " ,BKDRHash2(buf));
- printf("%x " ,BKDRHash3(buf));
-
-
- printf("\nElapsed time: \nBKDRHash0 BKDRHash1 BKDRHash2\
- BKDRHash4(seconds)\n");
-
- for(j=0;j<20;j++)
- {
- //=======================================================
- t0=clock();
-
- for(i=0;i<=N0;i++)
- {
- BKDRHash0(buf);
-
- }
- printf("%.8f ",(clock()-t0)/CLOCKS_PER_SEC);
- //=======================================================
-
- t1=clock();
-
- for(i=0;i<=N0;i++)
- {
- BKDRHash1(buf);
-
- }
- printf("%.8f ",(clock()-t1)/CLOCKS_PER_SEC);
- //=======================================================
- t2=clock();
-
- for(i=0;i<=N0;i++)
- {
- BKDRHash2(buf);
- }
-
- printf("%.8f ",(clock()-t2)/CLOCKS_PER_SEC);
- //=======================================================
- t3=clock();
-
- for(i=0;i<=N0;i++)
- {
- BKDRHash3(buf);
- }
- printf("%.8f\n",(clock()-t3)/CLOCKS_PER_SEC);
- //=======================================================
- }
- system("PAUSE");
- return 0;
-
- }
复制代码 |
|