易码技术论坛

 找回密码
 加入易码
搜索
查看: 823713|回复: 13

[教程] [原创][分享][小论LavaX程序的速度优化]

[复制链接]
发表于 2006-8-26 16:07:56 | 显示全部楼层
哈哈啊哈哈我要了~~~
好东西
发表于 2006-8-26 16:08:19 | 显示全部楼层
呵呵,谢谢那么好的文章.
谢谢GG了
发表于 2006-8-26 16:19:26 | 显示全部楼层
感谢技术文章!
不知道您能完成编译器这个艰巨的任务吗?努力!
 楼主| 发表于 2006-8-26 18:05:14 | 显示全部楼层
引用第3楼Strongme2006-08-26 16:19发表的“”:
感谢技术文章!
不知道您能完成编译器这个艰巨的任务吗?努力!

可以倒是可以,但是需要时间.
发表于 2006-8-26 22:22:03 | 显示全部楼层
编译器万岁!!!
楼主加油啊!!!!
发表于 2006-8-27 09:29:53 | 显示全部楼层
很多都是很实用的,收益匪浅啊~
发表于 2006-8-27 11:34:27 | 显示全部楼层
好东东,收下了~~~嘎嘎
发表于 2006-8-27 17:13:02 | 显示全部楼层
谢谢楼主,我现在在做的东西对速度要求甚高,虽然有些速度优化方法我已经发现了,不过有楼主根据底层分析对我更有帮助。(做编译器肯定要了解底层吧)
发表于 2006-8-27 21:16:22 | 显示全部楼层
1.
if else 的优化应该是没必要的,这应该是编译器的工作....
lee做的编译器应该是实现了这一点的吧....
而且无论怎么优化,执行后一个else if都要经过前面的if...
所以把最可能的条件式往前放会有优化作用...

2.
a*16*5改成16*5*a的话LavaX编译器会编译成80*a(常量运行放变量前)

3.
if(a==b && c==d)改为 if(a==b & c==d)会快些,同理||改为|

4.
因为lavaX中TRUE是-1,即0xffffffff,所以
if(a==b)
{
c=x1;
}
else
{
c=0;
}
可改为
c=(a==b)&x1;//LavaX/Lavo专用技巧

5.
当确定不会溢出且是正数时,
a*2,a*4,a*8...,a/2,a/4,a/8,...可改为a<<1,a<<2,a<<3,...a>>1,a>>2,a>>3
此招中除法对arm/mips处理器也有效,应为arm/mips没有除法指令,除法只有宏指令

还有一些技巧,就不一一细说了....我是优化狂人,lee说我走极端...我自己也觉得自己有些BT了...
发表于 2006-8-28 03:09:19 | 显示全部楼层
呵呵
arm没有除法指令,但是mips有,只是比较耗时间。
发表于 2006-8-28 07:54:53 | 显示全部楼层
引用第9楼诗诺比2006-08-27 21:16发表的“”:
1.
if else 的优化应该是没必要的,这应该是编译器的工作....
lee做的编译器应该是实现了这一点的吧....
而且无论怎么优化,执行后一个else if都要经过前面的if...
所以把最可能的条件式往前放会有优化作用...
.......

我是优化白痴。。。
受教了,谢了啊~
 楼主| 发表于 2006-8-28 09:30:59 | 显示全部楼层
引用第9楼诗诺比2006-08-27 21:16发表的“”:
1.
if else 的优化应该是没必要的,这应该是编译器的工作....
lee做的编译器应该是实现了这一点的吧....
而且无论怎么优化,执行后一个else if都要经过前面的if...
所以把最可能的条件式往前放会有优化作用...
.......

我知道我发上来的只是小菜东西,但是你的一些观点我还是不同意:

1:if.else:你可以反一下lav的代码,如果出现else,if中的代码绝对是要goto到else最后面,因为编译器不知道是否在 else后面就返回,所以就多了一个goto.

3:&& 和&是完全不同的概念,&&只是逻辑关系,而&需要位运算,要是我编解释器,我会把&&编译成bne,beq,而&则是and,在时钟周期上6502运行and会慢点,所以我觉得逻辑运算应该比位运算快.
发表于 2006-8-30 01:52:52 | 显示全部楼层
当然是goto最后一个else后面,楼主的情况原来是直接return,之前没看仔细...say sorry,不过在if else后直接返回,此种情况很少见。。。
==========
&比&&快是很显然的,Lavax的if不是截断的,而且更不会编译成6502指令的!!
不过这点不想再多说,
因为大大降低了程序的移植和可读性,并不鼓励大家使用...
 楼主| 发表于 2006-8-26 16:04:39 | 显示全部楼层 |阅读模式
这是我在编LavaX程序的一些经验(可能在高手眼里都不算什么).
这里说的完全是为了程序速度的优化,是给需要运行速度的人看的,如果你的程序对速度要求不高,那就不要用这些方法,因为这样降低了程序的可读性


1. 运算的优化(不要小看这些微不足道的东西,当你把它用在大量的循环中时差别就十分明显了)

代码能短则短,由于LavaX使用的是伪指令,所以每个运算指令的执行时间也差不了多少,所以最好多用结合律.

能用char型变量运算的地方就不要用int和long,因为所占的字节数不同,所以处理不同类型的变量就需要不同的时间,当然越少越好.

像if(var!=0);这样的表达式因该这样写if(var);,而if(var==0);应该写成if(!var);


在函数中若出现if+else,如:
void fun(){
   if(){
      [program]
   }
   else {
      [program]
   }
}
应该在if的[program]后面加return;,不然程序要goto到else后面才返回,在函数内如果有多次判断:
long fun(){
   if(){
      [program]
   }
   else if(){
      [program]
   }
   else if(){
      [program]
   }
}
可以改成:
long fun(){
   if(){
      [program]
      return ?;
   }
   if(){
      [program]
      return ?;
   }
   if(){
      [program]
      return ?;
   }
}

减少额外的运算:
for(a=0;a<10;a++){
   c[a]=a;
}
应该写成
for(a=0;a<10;){
   c[a]=a++;
}


相同的表达式运算时应该使用赋值,如:
WriteBlock((a+b)*16+5,(c+d)*16,16,16,4,tile1);
WriteBlock((a+b)*16+5,(c+d)*16,16,16,3,tile2);
应该写成:
WriteBlock(e = (a+b)*16+5, f = (c+d)*16,16,16,4,tile1);
WriteBlock(e, f,16,16,3,tile2);

对于空循环,如果不是LavaX3.5(因为它已经对循环进行了优化),最好不要用for(;;)和while(1),由于内部结构的原因,那样比直接用goto慢了两倍以上!

数组的优化:
很多人在画背景图时这样写
//满屏贴16*16的图素
char tile[50][32];
char map[64][64];
char x,y,ox,oy;
for(ox=0;ox<10;ox++){
   for(oy=0;oy<5;oy++){
      WriteBlock(ox*16,oy*16,16,16,1,tile[map[x+ox][y+ox]]);
   }
}
这是很简单的贴图方式,可以这样优化:
int temp;
temp=map+y*64+x;
for(ox=0;ox<160;ox=ox+16){
   for(oy=0;oy<80;oy=oy+16){
      WriteBlock(ox,oy,16,16,1,tile[*temp++]);
   }
   temp=temp+64;
}
这里优化了两个地方:
(1)将ox的增量改为16,这样就免去了ox*16,而且少了50次oy*16,取而代之的是10次oy=oy+16,虽然ox的运算的指令的数量没有变.

在运算上能加减则加减,尤其在递增关系上,不应该用递增的数乘别的数,应该用递增的数加要乘的数,+ - 要比* /来的快,因为* /需要移位运算(除非你有乘法表):

(2)使用的类似指针的方式,tile[map[x+ox][y+ox]]实际会编译成类似这样:
   tile + ( (map + (x + ox) * 64 + y + oy)<--[取对应地址的值] ) * 32
表达式需要的运行一次的指令数量为15.
而tile[*temp++]会编译成类似这样:tile + (*temp++) * 32 指令数量为7,在这样的多层循环里优化效果就很明显,所以尽量在多循环中减少运算量.



2. if.else.的优化
对于这样的优化只在出现大串的if+else有效,使用的方法就是以前我发过的贴里的函数的特殊用法,在这里就不多说了.
不过if+else如果没超过10个就不要用这样的方法了.



3. 贴图的优化,这个方法可能很多人都用到了,不过还是说说吧

同样是上面的的贴图例子.这样贴每一贞都要50次循环,导致大量的运算,而这些运算的速度比WriteBlock的速度慢多了,50次这样的运算也够你文曲星受的.

在移动的时候屏幕大多数的地面只是作了平移,所以只要在每一贞画出新增加的图就ok:
先画一次全屏幕的图,然后将其保留,每移动一点的时候,只画多移动出来的一条然后将保留的图按偏移位置贴上去,这样速度不知道快了多少倍.
当然,要是用XDraw,就连保留都不需要,几乎可以实现完美的点移.

如果是在LavaX3.5的环境下,使用引用和指针更能很大的优化速度,尤其是对于结构和数组,具体方法就不用多说了吧.
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-4-29 00:02 , Processed in 0.011559 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表