Register to post in forums, or Log in to your existing account
 

Play RetroMUD
Post new topic  Reply to topic     Home » Forums » CMUD General Discussion Goto page 1, 2  Next
Jaegord
Newbie


Joined: 25 Nov 2007
Posts: 9

PostPosted: Wed Dec 19, 2007 1:15 am   

Speed, what gives and takes?
 
I have heard alot of things about CMUD, triggers, aliases, etc. Certain things do this, and certain things do that.. but what exactly contributes to slowing down your triggers overall? And are there certain ways of writing triggers that contribute to speed? If so, what are they? And of course, what kind of things should be avoided? I have heard that using an alias in a trigger is faster than having the script directly in the trigger, for instance. I have no idea if that is true or not, but if there are other things like that, that are true, could anyone who knows them post here?
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: Wed Dec 19, 2007 2:53 am   
 
It's important that your patterns are thrown out as fast as possible. If you simply must have tons of triggers, then make the patterns as precise as you can - never use * unless you need to, and especially never at the start or end of a pattern.

Aliases in triggers is clearly bottom-speak. Having to look up an alias adds another step to the process - it won't make a great deal of difference since it's just a hash lookup, but it's still another step.

Finally, talking about speed in scripting is a very difficult area - oftentimes, greater speed can be achieved only at the expense of readable or managable code. Sometimes speedier code is code that's more difficult to expand or change in the future. It's also difficult to say categorically that one thing's faster than another, because it depends how you're using them. It's much easier to be presented with a problem and to offer a number of solutions.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Wed Dec 19, 2007 4:49 am   
 
The usage of aliases to gain speed was a zMud thing. zMud copied the entire text of a setting from one spot in memory to another before executing it. So a speed gain could be achieved by putting code that would be conditionally executed into aliases. In CMud no such copying occurs, and actually a nanosecond (that is millionth of a second) can be gain by not breaking code into reusable aliases and functions. As Fang said the gain is not worth it.

On using aliases versus using functions, I tend to use functions for all code I publish. The frequency that I do "#IF (@function)" is nearly equal with "#CALL @function", and there is no discernable speed difference from doing things with functions versus aliases. Although I will probably run some extreme test later just to make sure.

The are a few things I can say contribute directly to trigger speed. First is volume, number of triggers is the most significant contributing factor, disbaling those that can be helps. Second is pattern quality, which I think Fang addressed very well, although I believe the matching engine throws out an * at the beginning or end anyway. Third is depth, burying a trigger more classes down is slower. Fourth is function of trigger, a trigger that causes further display (anything except the #SUB and #PSUB) is vastly slower then a trigger that does not cause more display.

There are a few things you can do to adjust these problems. First cut down the number of trigger you have, if you have 17 different triggers that all do the exact same thing use a list pattern and a list variable and achor it at the start of the line. The matching engine actually compares against all 17 things at once when it is anchored, and as it eliminates one from being possible it stops checking that one. The reason for the third thing I mentioned is a bit complex to get into, just trust me on it, don't bury your triggers unless you have to.

The fourth item I mentioned is easy to get around for all your child window; if that child window does not have any triggers it uses then add an onLoad event with the #IGNORE command to that window. If it does use some triggers make them priority 1 and set the Stop Further Processing flag on them, if there is the further possibility that they won't match add a catch all (pattern of *) at priority 2 with Stop. For those in the main window that must display something all the time (#SAY, #SHOW, etc.) turn off the Trigger on Trigger flag. These particular tricks may not be needed with a future version, but they won't hurt anything.

In general shorter is faster, fewer is faster, and faster is not always better. There are many little things that can add up to small speed gains, but largely the beta testers have very complex scripts and anything that is horribly slow we whine about until Zugg makes a way for it to be faster. There really are many specific speed tricks, but most are very dependent on what you need to do.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Jaegord
Newbie


Joined: 25 Nov 2007
Posts: 9

PostPosted: Wed Dec 19, 2007 6:10 am   
 
I have a few somewhat more specific questions.

Is there much of a difference in speed between #SW and #IF statements? And how much slow-down do you get from using #SA or maybe #SHOW? And finally, is there that much slowdown from using #SUB? Possibly more than once in a few seconds of time between? Something about subs were said in the above post, but I'm still curious.
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Wed Dec 19, 2007 6:36 am   
 
There isn't any speed difference between #SWITCH and an #IF else chain. There is a huge legibility difference which is why #SWITCH is often prefered.

I mentioned #SAY and #SHOW, so I guess I should explain it somewhat. Currently both those commands, #ECHO, #CAPTURE, and #WINDOW name {text} can cause triggers to fire (don't ever expect that to change). This means that some of the checks involved with triggers in the first place have to occur again for the new line that is made. In most cases those checks return false soon enough that all the checks are not occuring again. Generally with #SHOW, #SAY, and #ECHO you will be outputting to the main window meaning you just ran full testing on all of your triggers a second time. Following my above suggestions eliminates that second test.

Individual trigger testing time is measured in nanoseconds, I had to time a million trigger tests to figure out what actually contributed to what. So unless you have 1 million triggers, or 1000 triggers with 1000 lines to test, there is no truly noticeable speed issue.

#SUB and #PSUB are very well optimized and do not cause any extra trigger testing.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Jaegord
Newbie


Joined: 25 Nov 2007
Posts: 9

PostPosted: Wed Dec 19, 2007 7:12 am   
 
Thanks for the information so far! And when you say that #SUB and #PSUB do not cause any extra trigger testing, do you also mean that there isn't a loss in speed when using them?
Reply with quote
mr_kent
Enchanter


Joined: 10 Oct 2000
Posts: 698

PostPosted: Wed Dec 19, 2007 8:41 am   
 
Jaegord wrote:
And when you say that #SUB and #PSUB do not cause any extra trigger testing, do you also mean that there isn't a loss in speed when using them?

#SUB and #PSUB triggers will cause a tiny, miniscule loss in speed...
Vigilante wrote:
Individual trigger testing time is measured in nanoseconds, I had to time a million trigger tests to figure out what actually contributed to what. So unless you have 1 million triggers, or 1000 triggers with 1000 lines to test, there is no truly noticeable speed issue.

but, once the replacement text from your #SUB/#PSUB trigger is displayed in the window the program ignores it. The program doesn't try to match the replacement text with your trigger patterns the way it does when you use #SHOW, ECHO, etc. (unless you uncheck 'Trigger on Trigger' which again causes the program to just display the new message text and then ignore it).
Reply with quote
Jaegord
Newbie


Joined: 25 Nov 2007
Posts: 9

PostPosted: Thu Dec 20, 2007 1:51 am   
 
In IRE games, the prompt has certain elements that will change, depending on certain conditions. That means that one part of it could be multiple things at any time. What would be the best way to determine what these values would be? Right now, I might use a nasty, giant #SW which considers every combination, but I do wish I could think of a better way to do it. Would that kind of trigger firing off of the prompt constantly be a bad idea?
Reply with quote
MattLofton
GURU


Joined: 23 Dec 2000
Posts: 4834
Location: USA

PostPosted: Thu Dec 20, 2007 3:59 am   
 
Maybe go with events on that one, Jaegord. Events are like triggers that trigger on Windows messages (ie, clicking a button, resizing a window, and so on). Like triggers, all the events with that name are run at the same time.

#TRIGGER {whatever your prompt pattern is} {#RAISEEVENT eventname}

#EVENT eventname {whatever the code you want here}
#EVENT eventname {some other code goes here}
#EVENT eventname {even more unrelated stuff goes here}
_________________
EDIT: I didn't like my old signature
Reply with quote
Jaegord
Newbie


Joined: 25 Nov 2007
Posts: 9

PostPosted: Thu Dec 20, 2007 4:57 am   
 
EDIT: Nevermind.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: Thu Dec 20, 2007 9:53 pm   
 
%pos is probably the easiest way to check for the presence of a particular character in a string.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
Jaegord
Newbie


Joined: 25 Nov 2007
Posts: 9

PostPosted: Fri Dec 21, 2007 1:35 am   
 
Does subbing the prompt cost you alot of speed?
Reply with quote
oldguy2
Wizard


Joined: 17 Jun 2006
Posts: 1201

PostPosted: Tue Mar 18, 2008 2:24 am   
 
bleh nevermind. I swore I hit new topic.
Reply with quote
ReedN
Wizard


Joined: 04 Jan 2006
Posts: 1279
Location: Portland, Oregon

PostPosted: Wed Mar 19, 2008 7:28 am   
 
Vijilante wrote:
The usage of aliases to gain speed was a zMud thing. zMud copied the entire text of a setting from one spot in memory to another before executing it. So The are a few things I can say contribute directly to trigger speed. First is volume, number of triggers is the most significant contributing factor, disbaling those that can be helps. Second is pattern quality, which I think Fang addressed very well, although I believe the matching engine throws out an * at the beginning or end anyway. Third is depth, burying a trigger more classes down is slower. Fourth is function of trigger, a trigger that causes further display (anything except the #SUB and #PSUB) is vastly slower then a trigger that does not cause more display.

There are a few things you can do to adjust these problems. First cut down the number of trigger you have, if you have 17 different triggers that all do the exact same thing use a list pattern and a list variable and achor it at the start of the line. The matching engine actually compares against all 17 things at once when it is anchored, and as it eliminates one from being possible it stops checking that one. The reason for the third thing I mentioned is a bit complex to get into, just trust me on it, don't bury your triggers unless you have to.


Two questions:

1) How buried is buried? I tend to organize by logic and not worry too much about how many levels there are. Sometimes there can be probably up to 4 levels of hierarchy depending on circumstances. Is 4 levels too many? How do you organize your triggers?

2) I had thought that a #say couldn't cause triggers to fire. For that reason I've always used #show to test trigger patterns because #show will be matched by triggers. Following that logic I sometimes use #gag followed by a #say as equivalent to a #sub. Am I mistaken in my approach here?
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: Wed Mar 19, 2008 10:14 am   
 
Jaegord wrote:
Does subbing the prompt cost you alot of speed?

Yes, but no more than any other subbing - it's not slow like printing lines is, by any means. It's just that prompts happen more often. The trouble with "costing a lot of speed" is that you mean "will changing this have a big effect on the speed of my collection of scripts?" and the answer is normally "it depends, but probably not". It depends on what code you're actually running and when, on how you have your settings organised and layered, on the types of variables you use, on how often you call functions and which functions, and on many, many other things. It's normally a whole bunch of things that makes scripts slow. And really, if you have a half-decent computer it's not going to make much difference anyway.

So yeah, not subbing your prompt will be faster than subbing it. Will be a lot? It depends. Try it and see. Faster isn't necessarily better, either - maybe you'll think having whatever info you're subbing into your prompt will be worth it.


ReedN: Forgive me for answering some of your questions, even though they weren't addressed to me. I'm sure Viji will say his piece if he thinks there's one to say :)

ReedN wrote:
1) How buried is buried? I tend to organize by logic and not worry too much about how many levels there are. Sometimes there can be probably up to 4 levels of hierarchy depending on circumstances. Is 4 levels too many? How do you organize your triggers?

Like I said above, speed isn't everything. Viji goes to lengths in another thread to explain how the inscope testing traverses your class tree. Changing it won't make a world of difference unless you have thousands of triggers that're all buried deep. It's a tradeoff - organisation is important, but so is speed. See if you can cope with fewer classes, and if you can, it'll be faster. If you can't, you'll have to accept that it's slower. I organise my triggers like that - as few classes as I can stand, which is still quite a few. Not four-deep, I don't think, but definitely three on rare occasion and for only a couple of triggers where it won't make much difference. One trick you can use is instead of nesting "checking" inside "defs" inside "main", have "main", "main_defs" and "main_defs_checking" all at root level. It basically works as if you'd expanded every arm in the treeview. Obviously they invented treeviews for a reason, and you won't want it for all your classes, but it's useful if you think you're getting too deep too often.

ReedN wrote:
2) I had thought that a #say couldn't cause triggers to fire. For that reason I've always used #show to test trigger patterns because #show will be matched by triggers. Following that logic I sometimes use #gag followed by a #say as equivalent to a #sub. Am I mistaken in my approach here?

Yes. #say, #echo and #show can all fire triggers. I don't think they did once upon a time, but they do now. I'm not sure if "stop further processing" stops triggers firing on your #say, but I doubt it (I expect all your triggers are checked afresh as part of the display-another-line routine), but you might try that.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
oldguy2
Wizard


Joined: 17 Jun 2006
Posts: 1201

PostPosted: Wed Mar 19, 2008 2:04 pm   
 
I've noticed that on a lot of lines I sub I see the original line first then I see the sub.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: Thu Mar 20, 2008 1:35 am   
 
Vijilante wrote:
I believe the matching engine throws out an * at the beginning or end anyway.

I've been bugged for a while now by this, and then just now it stuck me why - talking only about regexes, that can't be true. A lot of implementations of regexes are for subbing, and in those cases, having .* at the beginning and end will change what's replaced. The same is true of zScript triggers using #sub. So the onus is on the user to specify only what he wants to match. I suppose the only way to find out for sure would be to do a test... and so I shall:

Code:
#loop 500 {#trig %concat("s_",%i) {*test1*} {} "stars"};#loop 500 {#trig %concat("ns_",%i) {test1} {} "nostars"};#loop 500 {#regex %concat("rs_",%i) {.*test1.*} {} "regexstars"};#loop 500 {#regex %concat("rns_",%i) {test1} {} "regexnostars"}

Then enabled and disabled classes to test the different triggers with Ctrl+Q. Results:

ns: 34.5
s: 42.6
rns: 34.8
rs: 42.8

The results varied a little in later tests, but not enough to throw out my point - using catch-alls at the ends when you don't need to is slower.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
oldguy2
Wizard


Joined: 17 Jun 2006
Posts: 1201

PostPosted: Thu Mar 20, 2008 2:14 am   
 
So apparently using Regex is slower period? Granted it is not much, but your test shows they are slower. I have a ton of triggers and they are all Regex. The only time I use ".*" at the end of the pattern is when I want to sub it. Otherwise I get a partial sub and part of the original pattern from the mud.

Would it actually be faster to change them all from Regex?

Edit: Nevermind. I got just the opposite on my computer.

26.1 NS
34.1 S

25 RNS
33.8 RS

Mine shows Regex as faster. However, using "*" in the pattern is certainly slower.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: Thu Mar 20, 2008 2:50 am   
 
I remember Viji saying somewhere that you divide the number by 10 to get the ms for each line. So using regexes is 0.03ms slower per line with 500 triggers. Milliseconds, not seconds. Not exactly breaking the bank, is it?
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
oldguy2
Wizard


Joined: 17 Jun 2006
Posts: 1201

PostPosted: Thu Mar 20, 2008 3:10 am   
 
Not at all. I was just confused because I thought Regex was faster, which on my computer it was.

I have 406 triggers right now, the majority of which are multiple triggers in string lists because they do the same thing. So in reality I have triple that amount of triggers if I didn't put them in string lists. When I do CTRL+Q I hit 18 ms with everything in my package.
Reply with quote
ReedN
Wizard


Joined: 04 Jan 2006
Posts: 1279
Location: Portland, Oregon

PostPosted: Thu Mar 20, 2008 4:13 am   
 
I thought I recall reading during the Zmud era that regex was faster. Perhaps it's now reversed for Cmud.
Reply with quote
Fang Xianfu
GURU


Joined: 26 Jan 2004
Posts: 5155
Location: United Kingdom

PostPosted: Thu Mar 20, 2008 4:24 am   
 
That's not been the case so far. In my test, they were basically the same; in oldguy's they were faster. Much easier than trying to work out which is objectively faster, I think, is just to try it and see. There're just too many things that might affect it.
_________________
Rorso's syntax colouriser.

- Happy bunny is happy! (1/25)
Reply with quote
JQuilici
Adept


Joined: 21 Sep 2005
Posts: 250
Location: Austin, TX

PostPosted: Thu Mar 20, 2008 2:56 pm   
 
Vijilante wrote:
...if that child window does not have any triggers it uses then add an onLoad event with the #IGNORE command to that window.

This is extremely interesting - I had always thought (from the manual page for #IGNORE) that the #IGNORE command stopped trigger processing for the entire session, not just for the window in which it was issued.

I presume that #IGNORE stops (global) alarms from firing in the window, too?
_________________
Come visit Mozart Mud...and tell an imm that Aerith sent you!
Reply with quote
leonardofaoro
Novice


Joined: 07 Feb 2008
Posts: 40
Location: Italy

PostPosted: Thu Mar 20, 2008 3:25 pm   Anchor triggers
 
Vijilante wrote:
There are a few things you can do to adjust these problems. First cut down the number of trigger you have, if you have 17 different triggers that all do the exact same thing use a list pattern and a list variable and achor it at the start of the line. The matching engine actually compares against all 17 things at once when it is anchored, and as it eliminates one from being possible it stops checking that one. The reason for the third thing I mentioned is a bit complex to get into, just trust me on it, don't bury your triggers unless you have to.


Mr. Einstein used to say that example is not a new method to learn, in fact is the only method to learn. Let me post an example:
#tr {* You try to behead * and miss so badly that you nearly take your own head off.} {behead}
#tr {* As you try to behead *, something distracts you and you only manage to slice his shoulder.} {behead}
#tr {* You swing your * in a perfect arc and neatly behead * The head rolls away with a look of horror upon it.} {--}

These are three triggers on the BEHEAD skill, two of them do the same action, so I assume that I could anchor them as you say?
What will I do is to make a list var and fill it with both messages, then build a #case to trig the behead command?
Ex.
#va bhtrig {* You try to behead * and miss so badly that you nearly take your own head off.|* As you try to behead *, something distracts you and you only manage to slice his shoulder.}
#tr {#case @bhtrig} {behead}

This is how I'd have to build it? This is how it will get faster?
Reply with quote
JQuilici
Adept


Joined: 21 Sep 2005
Posts: 250
Location: Austin, TX

PostPosted: Thu Mar 20, 2008 3:37 pm   
 
FWIW, the sample sizes being used here are WAY too small to draw conclusions about tenths of ms in relative speeds of regex/non-regex matching. I ran each set (plus a couple more) five times, to get a better sample:

ONLY nostars enabled: 41.3 38.7 39.1 38.8 38.6
ONLY regexnostars enabled: 40.9 38.1 38.5 39.0 38.4
ONLY stars enabled: 68.6 66.4 66.0 66.5 66.0
ONLY regexstars enabled: 68.4 65.8 64.9 65.0 65.0

Looks pretty much like a wash to me, with the possible exception of regex star patterns matching approximately 1% faster than zScript star patterns (and that may not be statistically significant, either). It's interesting to note that the first execution time is consistently about 2-3 (whatever these units are) higher, presumably due to internal bookkeeping being updated after the class enable/disables.

Even more interesting is this other set of tests:

Before defining triggers: 10.3 7.6 7.1 7.2 7.5
After defining triggers, all 4 classes disabled: 20.4 17.4 17.7 17.3 18.3
After defining triggers, all 2000 triggers individually disabled: 10.8 11.1 10.6 10.6 10.8

It seems that disabling the triggers individually makes the system faster than just disabling the class - almost as fast as not having them there at all, in fact. And note that the actual speed penalty for having 2000 class-disabled triggers is pretty minor - about 1ms on my machine, if the information in posts above is correct. Even having 500 of them enabled only costs another 2-4 ms, depending on the patterns.

(And yes, my machine is slower than most of yours, apparently, or maybe it's that I ran this in 2.20).
_________________
Come visit Mozart Mud...and tell an imm that Aerith sent you!

Last edited by JQuilici on Thu Mar 20, 2008 4:26 pm; edited 1 time in total
Reply with quote
Display posts from previous:   
Post new topic   Reply to topic     Home » Forums » CMUD General Discussion All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

© 2009 Zugg Software. Hosted by Wolfpaw.net