找回密码
 点一下
查看: 3401|回复: 8

对于Galaxy触发的最大执行长度限制的简单测试。

[复制链接]
发表于 2010-8-16 13:37:40 | 显示全部楼层 |阅读模式
今天暂时测试了下对于Galaxy触发器的最大执行长度

由于我不会汇编,所以以下操作都仅仅是在Galaxy环境下的测试。


步骤一

首先新建一个无限循环+1的触发器

[codes=galaxy]
bool abc(bool a, bool bs){
    while(true) {gv_i+=1;}
    return true;
}

..................
//下面的代码用于将函数abc创建为触发器。
gv_tr= TriggerCreate("abc");
TriggerAddEventKeyPressed(gv_tr, c_playerAny, c_keyEscape, true, c_keyModifierStateIgnore, c_keyModifierStateIgnore, c_keyModifierStateIgnore);
[/codes]

注:gv_i为全局变量,初始值为0。

按下Esc后这个触发器就会开始无限循环直到语句执行长度达到上限。之后打印gv_i的值,即可得知该循环执行了几次。

最终输出结果为

1249999




真是相当微妙的一个数字呢……上限原来是125000整么?但现在就有个问题。由于这个Galaxy毕竟是个解释性语言。像
while(true) {gv_i+=1;}

这样循环一次究竟算执行了几句语句呢?按照C语言来推想理论上应该是2句,不过保险起见还是继续测试下吧。


步骤二

首先,测试gv_i+=1;到底算几句语句。它是否已经是最小的代码执行单位了?

要证明这个,当然要将其与Galaxy中最小的代码执行单位相比。按照常理来推断,一条最短代码应该是赋值语句。

于是改写函数abc

[codes=galaxy]
bool abc1(bool a, bool bs){
    while(true)
    {
        gv_i+=1;
        gv_j+=1;
    }
    return true;
}

bool abc2(bool a, bool bs){
    while(true)
    {
        gv_i+=1;
        gv_j=1;
    }
    return true;
}
[/codes]

函数abc1()相当于每个循环中都执行了2次x=x+1,而函数abc2()则相当于每个循环中执行一次x=x+1和一次x=1;如果x=x+1和x=1的代码长度相同,那么理论上这2个触发执行完后,gv_i的值都应该一样才对。

但实际执行结果却是,触发abc1的gv_i最终值为769231,而触发abc2的gv_i最终值为909091

明显的,x=x+1其实要长于x=1,由此看来,gv_i+=1并不是最短的一句语句呢。

然后增加一个测试:
[codes=galaxy]
bool abc3(bool a, bool bs){
    while(true)
    {
        gv_i+=1;
        gv_j=1;
        gv_j=1;
    }
    return true;
}
[/codes]

也就是额外的两个x=1和上面的abc1里的额外的一个x=x+1相比较,这次的结果是714286,接近于abc1的769231但是却比它小。可见其实gv_i+=1大致上相当于2个最简单的赋值语句,不过要短一些。


步骤三

大致对gv_i+=1的立场有掌握后,现在就可以来计算整个循环一次究竟算执行了几条语句了。因为前面用gv_i+=1得到的结果为1249999,比较像样,所以这次就依然以gv_i+=1为基准来计算。

设while(true) {gv_i+=1;}的每次循环中,除开gv_i+=1这句以外语句数量为X,而gv_i+=1本身的语句数为N。那么有。

1249999(X+N)=769231(X+2N)



便能解得X=1.666653955619958N

即,每次循环中,即使循环体内没有任何语句,while(true) {}每个循环执行的语句数量大致相当于一个半的gv_i+=1再多一点。大致相当于3句最简单的赋值语句。


这样,while(true) {gv_i+=1;}整体上每个循环执行的语句数量就大致相当于5句最简单的赋值语句。


这样的循环最多能执行1250000次,那么由此可知,galaxy触发器的最大执行长度大致为6250000条最简单的赋值语句。






以上只是一些简单的测试,如果大家有更多想法,欢迎发表意见hmmm。我呢主要不会汇编,否则直接察看Galaxy虚拟机的实现机制里是怎么限制触发器长度的了。
发表于 2010-8-16 18:02:57 | 显示全部楼层
多多益善。
回复

使用道具 举报

发表于 2010-8-16 18:27:12 | 显示全部楼层
V5,能否顺便测一下最大栈深度?
回复

使用道具 举报

发表于 2010-8-16 19:18:43 | 显示全部楼层
[codes=galaxy]
int i=0;

int aaa(){
    i+=1;
    return aaa();
}

int bbb(){
    i+=1;
    return bbb()*3;
}
[/codes]

怕aaa()把我跑死,就先跑的bbb(),结果是i=64824。

然后aaa()也一样的结果。

话说是这样测么?我代码写的对么?
回复

使用道具 举报

发表于 2010-8-16 20:35:09 | 显示全部楼层
应该没错吧。。呵呵,60000+已经完全可以满足一般需求了
回复

使用道具 举报

发表于 2011-3-9 14:40:06 | 显示全部楼层
无聊翻旧帖,看到这里貌似头目算错了。从下式开始:

1249999(X+N)=769231(X+2N)        ……①

头目推断X+N=5,得到“galaxy触发器的最大执行长度大致为6250000条最简单的赋值语句”的结论,那么经计算

X+2N=6250000/769231=8.1249975625

又X+N=5,所以

N=3.1249975625
X=5-N=1.8750024375

与X=1.666653955619958N 不符。实际上将X=1.666653955619958N带入①式中会发现

左式=3333314.777870991880042N
右式=2820503.888935495912298N

这样在N≠0的情况下,等式无论如何都不会成立。所以式①或者结果可能是错的。

现假设“galaxy触发器的最大执行长度大致”为A,有函数abc、abc1、abc2、abc3形如头目所写,其循环执行长度分别为n、n1、n2、n3,其运行次数分别约为1249999、769231、909091、714286。

则可知A≈1249999*n≈769231*n1≈909091*n2≈714286*n3
也就是说

n1≈1.6249982125005362498391250482625n
n2≈1.3749987625001237499876250012375n
n3≈1.7499979000008399996640001343999n

因为abc1与abc2的差别最小,我们先看它们的差值
n1-n2≈0.249999450000412499851500047025n≈0.25n

为保证n、n1、n2、n3均为整数,我们先假定n=8L,则
n1≈12.999985700004289998713000386096L≈13L        ……②
n2≈10.999990100000989999901000009896L≈11L        ……③
n3≈13.999983200006719997312001075192L≈14L        ……④

现在开始验证:
1249999*8L=9999992L
769231*13L=10000003L
909091*11L=10000001L
714286*14L=10000004L

因此我们可以假定A=10000000L。

由③④式可知x=1的消耗
n3-n2≈3L        ……⑤
由②③⑤式可知x=x+1的消耗
n1-n2+3L≈5L        ……⑥
由n=8L和⑥式可知while的消耗
n-5L≈3L        ……⑦

返回来看①式,其实结果应该是N=1.6666539556199581922118261267476X,带入⑥⑦式也是符合的,至于L是多少,那就要看有没有更小的执行长度了,或者大家习惯以哪个为基准了。

稍后我会以此为基础设法测试下更多的数据,不过就是意义不是很大就是了。
回复

使用道具 举报

发表于 2011-3-9 18:19:50 | 显示全部楼层
以上贴所说的为基础,下面为测试代码、显示结果。

[codes=galaxy]
int gv_i;
int gv_j;
int[3] gv_k;
int gv_a;
int gv_b;

void InitGlobals () {
    int init_i;

    gv_i = 0;
    gv_j = 0;
    init_i = 0;
    while (init_i <= 2) {
        gv_k[init_i] = 0;
        init_i = init_i + 1;
    }
    gv_a = 0;
    gv_b = 1;
}

struct aaa{
    int i;
    int[2] k;
};
aaa l;
struct bbb{
    aaa i;
    int[2] k;
};
bbb m;
bbb[2] n;
unit u=null;


bool gf_abc (bool lp_testConds, bool lp_runActions) {//1249999    --    8L
    while(true){gv_i+=1;}
    return false;
}

bool gf_abc1 (bool lp_testConds, bool lp_runActions) {//769231    --    13L
    while(true){
        gv_i+=1;
        gv_j+=1;
    }
    return false;
}

bool gf_abc2 (bool lp_testConds, bool lp_runActions) {//909091    --    11L
    while(true){
        gv_i+=1;
        gv_j=1;
    }
    return false;
}

bool gf_abc3 (bool lp_testConds, bool lp_runActions) {//714286    --    14L
    while(true){
        gv_i+=1;
        gv_j=1;
        gv_j=1;
    }
    return false;
}

bool gf_abc4 (bool lp_testConds, bool lp_runActions) {//999999    --    10L
    while(true && true){
        gv_i+=1;
    }
    return false;
}

bool gf_abc41 (bool lp_testConds, bool lp_runActions) {//833333    --    12L
    while(true && true && true){
        gv_i+=1;
    }
    return false;
}

bool gf_abc5 (bool lp_testConds, bool lp_runActions) {//1111111    --    9L
    while(true || false){
        gv_i+=1;
    }
    return false;
}

bool gf_abc51 (bool lp_testConds, bool lp_runActions) {//999999    --    10L
    while(false || true){
        gv_i+=1;
    }
    return false;
}

bool gf_abc6 (bool lp_testConds, bool lp_runActions) {//999999    --    10L
    while(true){
        if(true){gv_i+=1;}
    }
    return false;
}

bool gf_abc7 (bool lp_testConds, bool lp_runActions) {//999999    --    10L
    while(true){
        gv_i=gv_i+gv_j+1;
    }
    return false;
}

bool gf_abca (bool lp_testConds, bool lp_runActions) {//999999    --    10L
    while(gv_a<gv_b){
        gv_i+=1;
    }
    return false;
}

bool gf_abc21 (bool lp_testConds, bool lp_runActions) {//909091    --    11L
    while(true){
        gv_i+=1;
        gv_j=gv_i;
    }
    return false;
}

bool gf_abc61 (bool lp_testConds, bool lp_runActions) {//999999    --    10L
    while(true){
        if(false){}
        else{gv_i+=1;}
    }
    return false;
}

void gf_abci10 () {
    gv_i+=1;
}

int gf_abci101 () {
    return gv_i+1;
}

void gf_abci11 (int lp_i) {
    gv_i+=1;
}

int gf_abci111 (int lp_i) {
    return lp_i+1;
}

void gf_abci12 (int lp_i, int lp_j) {
    gv_i+=1;
}

bool gf_abcb (bool lp_testConds, bool lp_runActions) {//833333    --    12L
    while(true){
        gf_abci10();
    }
    return false;
}

bool gf_abcb1 (bool lp_testConds, bool lp_runActions) {//666666    --    15L
    while(true){
        gf_abci11(0);
    }
    return false;
}

bool gf_abcb2 (bool lp_testConds, bool lp_runActions) {//555555    --    18L
    while(true){
        gf_abci12(0,0);
    }
    return false;
}

bool gf_abcb3 (bool lp_testConds, bool lp_runActions) {//588235    --    17L
    while(true){
        gv_i=gf_abci111(gv_i);
    }
    return false;
}

bool gf_abcb4 (bool lp_testConds, bool lp_runActions) {//714285    --    14L
    while(true){
        gv_i=gf_abci101();
    }
    return false;
}

bool gf_abcc (bool lp_testConds, bool lp_runActions) {//666666 --    15L
    while(true){gv_i+=gv_k[1];}
    return false;
}

bool gf_abcc1 (bool lp_testConds, bool lp_runActions) {//416666    --    24L
    while(true){gv_i=gv_i+gv_k[1]+gv_k[0];}
    return false;
}

bool gf_abcc2 (bool lp_testConds, bool lp_runActions) {//1111111 --    9L
    while(true){gv_i+=l.i;}
    return false;
}

bool gf_abcc3 (bool lp_testConds, bool lp_runActions) {//624999    --    16L
    while(true){gv_i+=l.k[1];}
    return false;
}

bool gf_abcc4 (bool lp_testConds, bool lp_runActions) {//1111111 --    9L
    while(true){gv_i+=m.i.i;}
    return false;
}

bool gf_abcc5 (bool lp_testConds, bool lp_runActions) {//624999    --    16L
    while(true){gv_i+=m.i.k[1];}
    return false;
}

bool gf_abcc6 (bool lp_testConds, bool lp_runActions) {//624999    --    16L
    while(true){gv_i+=m.k[1];}
    return false;
}

bool gf_abcc7 (bool lp_testConds, bool lp_runActions) {//454545    --    22L
    while(true){gv_i+=n[1].k[1];}
    return false;
}

bool gf_abcc8 (bool lp_testConds, bool lp_runActions) {//666666    --    15L
    while(true){gv_i+=n[1].j;}
    return false;
}

bool gf_abcd (bool lp_testConds, bool lp_runActions) {//833333    --    12L
    while(true){gv_i+=AbsI(1);}
    return false;
}

bool gf_abcd1 (bool lp_testConds, bool lp_runActions) {//666666    --    15L
    while(true){gv_i+=ModI(1,2);}
    return false;
}

bool gf_abcd2 (bool lp_testConds, bool lp_runActions) {//1000000 --    10L
    while(true){gv_i+=1;
    EventKeyPressed();}
    return false;
}

bool gf_abcd3 (bool lp_testConds, bool lp_runActions) {//833333    --    12L
    while(true){gv_i+=1;
    gv_j=EventKeyPressed();}
    return false;
}

void gf_abc0 () {
}

bool gf_abcb5 (bool lp_testConds, bool lp_runActions) {//833333    --    12L
    while(true){gv_i+=1;
    gf_abc0();}
    return false;
}

bool gf_abcb6 (bool lp_testConds, bool lp_runActions) {//500000    --    20L
    while(true){gv_i+=1;
    gf_abci111(0);}
    return false;
}

unit gf_abc0u () {
    return u;
}

bool gf_abcb7 (bool lp_testConds, bool lp_runActions) {//666667    --    15L
    while(true){gv_i+=1;
    gf_abc0u();}
    return false;
}

[/codes]

脚本执行长度.SC2Map

15 KB, 下载次数: 25

回复

使用道具 举报

发表于 2011-3-9 18:19:58 | 显示全部楼层
网络卡了,发了一大堆....
而且也不能发附件,等网络好点了再补演示吧。
回复

使用道具 举报

发表于 2011-3-9 18:20:02 | 显示全部楼层
不说推断方法了吧,直接上计算方法吧。
1,脚本中,出现数值,变量,会消耗1L,数组变量消耗为7L
2,所有的符号(+ - * / && || < <= > >= !=)出现,消耗1L。
3,while(){}结构,消耗2L。if(){}else{}消耗1L。(最基本的,判断里面填true或false,它们消耗会多1L)
4,调用非数组结构,消耗为1L。(函数abcc2、abcc4,可知结构中的结构也是一样的),数组结构为6L。
5,调用galaxy的默认无参数无返回值函数,消耗为0L,每多一个参数多3L,带返回值多2L。调用无参数无返回值自定义函数,消耗为4L。
5(补充),第5条中,返回值类型如果是unit的话,不是多2L,而是多3L。像unit的赋值或者别的什么类型的变量就没有再测试了,等有时间了再详细测试下吧。

之所以说是计算方法,是因为实际情况可能不是这样的,但是用来计算函数的执行长度是没有问题的。下面是一些例子:
[codes=galaxy]
i+=1(i=i+1)
//(3个变量、2个符号)5L
[/codes]
[codes=galaxy]
int n=0;
int[6] i;
//上面的不计算了,还不知道是多少。

while(n<=6){
    i[n]=n;
    n+=1;
}
//while是2L,n<=5是3L,i[n]是8L,n+=1是5L,一次循环为(2+3+8+2+5)=20L,一共是20*6=120L。
[/codes]
[codes=galaxy]
int aaa(int x){return x;}

while(true){
    gv_i+=AbsI(1);
    gv_i+=ModI(1,gv_i);
    gv_i=aaa(0);
}
//while是2L,gv_i+=AbsI(1)是4(前面部分)+3(参数)+2(返回值)=9L,gv_i+=ModI(1,gv_i)是4+3*2+2=12L,调用aaa(0)为9L,一次循环为[(2+1)+9+12+(9+2)]=35L。
[/codes]

大概就是这样吧,其他的变量类型稍后再说吧。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-5-9 15:11 , Processed in 0.446729 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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