|
[求助]求教汇编的问题
天啊~~加上 and eax ,0xFF 反而变快了!!!这是为什么??? 前一段代码没有and eax ,0xFF 耗时1989.71 ms 后一段代码加了and eax ,0xFF 耗时1602.22 ms (P4M 1G CPU) for ( i = 0; i < 100000000u; ++i ) //0x5F5E100 { _asm { mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al mov eax, dword ptr u.i mov c, al } } at foo1(): time is: 1989.71 ms /////////////////////////////////////// for ( i = 0; i < 100000000u; ++i ) //0x5F5E100 { _asm { mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al mov eax, dword ptr u.i and eax ,0xFF mov c, al } } at foo1(): time is: 1602.22 ms /////////////////////////////////// ////////////////// movzx al XXX mov eax XXX mov al XXX 实测速度基本没有区别 ///////////////// |
|
[求助]求教汇编的问题
//////////////////////////////// 还有就是我听说: mov al, byte ptr [esp+9C] and eax, 0FF 比 movzx al byte ptr [esp+9C] 要高效。 ///////////////////////////////// 这段有笔误。应该改为: //////////////////////////////// 还有就是我听说: mov eax, dword ptr [esp+9C] and eax, 0FF 比 movzx eax, byte ptr [esp+9C] 要高效。 ///////////////////////////////// |
|
[求助]求教汇编的问题
谢谢各位指点。 合理的优化是通过改进算法和数据结构完成的。 这个再怎么做都是有极限的,不是吗?这方面的工作我已经做了很多,我已经找不到挖掘的空间了。 优化程序的意义我已经说了,这个函数可以说有30%以上的人每天都在用。做这个不为钱,只是追求一种完美,只是说明一个问题。 ////////////////////////////////////////////////////////////// //试验代码 void main() { int arraya[16][16][16],arrayb[16][16][16],i,j,k,m; getch(); m=arraya[i][j][k]=arrayb[j][k][i]; arraya[i][j][k]=m=arrayb[j][k][i]; } ////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// //在VC中查看查看汇编代码 2: void main() 3: 4: { 0040D490 push ebp 0040D491 mov ebp,esp 0040D493 mov eax,8054h 0040D498 call $$$00001 (004010e0) 0040D49D push ebx 0040D49E push esi 0040D49F push edi 0040D4A0 lea edi,[ebp-8054h] 0040D4A6 mov ecx,2015h 0040D4AB mov eax,0CCCCCCCCh 0040D4B0 rep stos dword ptr [edi] 5: int arraya[16][16][16],arrayb[16][16][16],i,j,k,l,m; 6: 7: getch(); 0040D4B2 call _getch (0040d6a0) 8: m=arraya[i][j][k]=arrayb[j][k][i]; 0040D4B7 mov eax,dword ptr [ebp-8008h] 0040D4BD shl eax,0Ah 0040D4C0 lea ecx,[ebp+eax-8000h] 0040D4C7 mov edx,dword ptr [ebp-800Ch] 0040D4CD shl edx,6 0040D4D0 add ecx,edx 0040D4D2 mov eax,dword ptr [ebp-8004h] 0040D4D8 shl eax,0Ah 0040D4DB lea edx,[ebp+eax-4000h] 0040D4E2 mov eax,dword ptr [ebp-8008h] 0040D4E8 shl eax,6 0040D4EB add edx,eax 0040D4ED mov eax,dword ptr [ebp-800Ch] 0040D4F3 mov esi,dword ptr [ebp-8004h] 0040D4F9 mov ecx,dword ptr [ecx+esi*4] 0040D4FC mov dword ptr [edx+eax*4],ecx 0040D4FF mov edx,dword ptr [ebp-8008h] 0040D505 shl edx,6 0040D508 mov eax,dword ptr [ebp-8004h] 0040D50E shl eax,0Ah 0040D511 lea ecx,[ebp+eax-4000h] 0040D518 add ecx,edx 0040D51A mov edx,dword ptr [ebp-800Ch] 0040D520 mov eax,dword ptr [ecx+edx*4] 0040D523 mov dword ptr [ebp-8014h],eax 9: 10: arraya[i][j][k]=m=arrayb[j][k][i]; 0040D529 mov ecx,dword ptr [ebp-8008h] 0040D52F shl ecx,0Ah 0040D532 lea edx,[ebp+ecx-8000h] 0040D539 mov eax,dword ptr [ebp-800Ch] 0040D53F shl eax,6 0040D542 add edx,eax 0040D544 mov ecx,dword ptr [ebp-8004h] 0040D54A mov edx,dword ptr [edx+ecx*4] 0040D54D mov dword ptr [ebp-8014h],edx 0040D553 mov eax,dword ptr [ebp-8004h] 0040D559 shl eax,0Ah 0040D55C lea ecx,[ebp+eax-4000h] 0040D563 mov edx,dword ptr [ebp-8008h] 0040D569 shl edx,6 0040D56C add ecx,edx 0040D56E mov eax,dword ptr [ebp-800Ch] 0040D574 mov edx,dword ptr [ebp-8014h] 0040D57A mov dword ptr [ecx+eax*4],edx 11: 12: } ///////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// 源码中的: m=arraya[i][j][k]=arrayb[j][k][i]; arraya[i][j][k]=m=arrayb[j][k][i]; 两行代码实现的功能是完全一样的。但是从VC6的编译结果来看, VC6第一行高级语言代码编译成机器码时反汇编来看是25行。 而后一行高级语言代码编译成机器码时反汇编来看是是18行。 如果直接用汇编相对V60生成的机器码都可以有提高效率的空间。 这从一个侧面反映了编译器并不总是高明的,有时也很呆板。 ///////////////////////////////////////////////////////////// ///////////////////////////////////////// 还有我认为这些方法: for ( i = 0; i < 1000000000u; ++i ) { u1._dword = (unsigned long) u0._byte[0]; } for ( i = 0; i < 1000000000u; ++i ) { //u1._dword = 0; u1._byte[0] = u0._byte[0]; } 用于实测,可能离我们的测试的目标有比较大的差距。 要知道循环本身就是开销CPU的。 for ( i = 0; i < 1000000000u; ++i ) { mov eax, dword ptr [esp+9C] } >> 就算是最简单的循环方法也不过是 mov ecx 1000000000 //只做一次,不考虑它 loop1: mov eax, dword ptr [esp+9C] //正常开销 假设开销两个CPU周期 dec ecx //额外的开销 假设开销一个CPU周期 jnz loop1 //额外的开销 假设开销一个CPU周期 但是: for ( i = 0; i < 1000000000u; ++i ) { mov al, btye ptr [esp+9C] } >> 就算是最简单的循环方法也不过是 mov ecx 1000000000 //只做一次,不考虑它 loop1: mov al, btye ptr [esp+9C] //正常开销 假设开销一个CPU周期 dec ecx //额外的开销 假设开销一个CPU周期 jnz loop1 //额外的开销 假设开销一个CPU周期 如果满足上面的假设,本来 mov al, btye ptr [esp+9C] 和 mov eax, dword ptr [esp+9C] 是相差一倍的。 但是使用这个方法再统计时间的话。第一段是开销是4个单位的CPU 第二段是开销的是3个单位的CPU 成绩比是4/3 而不是真正的2/1 所以说这种方法的误差可能很大。 //////////////////////////////// 还有就是我听说: mov al, byte ptr [esp+9C] and eax, 0FF 比 movzx al byte ptr [esp+9C] 要高效。 ///////////////////////////////// 我打算自己做个实测,但这几天挺忙的,可能不会很快,测好后再发上来。 |
|
[求助]求教汇编的问题
谢谢大家的解答。 这是从一个函数中截取的部分代码,也许大家没想到的是这个函数应用十分广泛,十个人里最少有九个人用过。 这个函数通过本人的优化,到目前为止,我见过的其它人做的最快的那个也不及我做的1/3速度(这个主要是算法上的优化)。 这个函数可用于运算最密集的穷举上,所以效率很重要。 在一楼贴的那段代码在这个函数中出现近百次。所占汇编代码行数为整个函数的80%并在函数内多次循环。所以我觉得有必要进一步去探索优化的方法。 to dzhsurf: 影响程序的效率通常不在这些小处上,而是在算法的选择上。 这个道理我明白,但是如果在算法上已经没有提高的空间的情况下,为提高效率你不得把最细致的问题都考虑进去。我见过不少的程序员在运算最密集的代码编写上是用了汇编,可见编译系统不见所有的代码都很高明。 to 彭总: 谢谢指教,您让我明白了NOP也是开销CPU的。但是有一点我还是不明白,还是再抖胆再请教一下,按您的说法: mov eax, dword ptr [esp+9C] 比 mov al, byte ptr [esp+9C] 高效的话,我想 mov al XXXX是没有存在的意义的。 但事实上mov al XXXX是存在并广泛使用的,而且我N年前我道听途说的听过mov al XXXX 是比 mov ax XXXX 高效的。别人还告诉我如果用char 型可以解决的问题尽量不要用int 。 做成这样后: 00402F00 8A8424 9C000000 mov al, byte ptr [esp+9C] 00402F07 8A8C24 94000000 mov cl, byte ptr [esp+94] 00402F0E 90 nop 00402F0F 90 nop 00402F10 90 nop 00402F11 90 nop 00402F12 90 nop 00402F13 90 nop 00402F14 90 nop 00402F15 90 nop 00402F16 90 nop 00402F17 90 nop 00402F18 90 nop 00402F19 |. 8A9441 90DD9900 |mov dl, byte ptr [ecx+eax*2+99DD90] 00402F20 |. 8A8448 90DD9900 |mov al, byte ptr [eax+ecx*2+99DD90] 我实测没有影响正确性(当然执行这段代码时我已经确保eax和ecx之前不大于0xFF)。速度并没有慢,与原来基本一样,也许是NOP的原因,既然NOP开销CPU可以把它删掉。但是后面的代码前移了要解决跳转的问题。我打算把NOP去掉再试试速度如何。 00402F00 8A8424 9C000000 mov al, byte ptr [esp+9C] 00402F07 8A8C24 94000000 mov cl, byte ptr [esp+94] 00402F19 |. 8A9441 90DD9900 |mov dl, byte ptr [ecx+eax*2+99DD90] 00402F20 |. 8A8448 90DD9900 |mov al, byte ptr [eax+ecx*2+99DD90] 另外如果用VS2005的话编译出来的代码全部都是整版的movez XXX XXX。VS2005的比VC60的慢了将近一倍。 to mik: 如果 mov al, byte ptr [esp+9c] // 不可以保证整个 eax 寄存器的值是中高位是 0 所以: mov dl, byte ptr [ecx+eax*2+99DD90] 中的 eax 值得不到保证。 你提起的可能的问题我已经说明是有满足eax不大于0xFF的前提。 这段代码重复出现近100次,只要分辨出eax 在何时有大于0xFF的值时,要开始执行那段代码的时候别忘了&0xFF,因为那段代码一但出现总会重重复复的,只要开头时没忘了&0xFF,之后eax在很长的一段代码里是不会大于0xFF的。之后的&0xFF是不是就可以省了?这样看来就不会有问题了吧? |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值