 |
chamenas Wizard

Joined: 26 Mar 2008 Posts: 1547
|
Posted: Sun Jan 16, 2011 4:54 am
[Theory] Efficiency of User-Defined Functions |
EDIT: Ack! Double post, can someone please delete the OTHER thread??
Hey there.
Introduction
I've been coding a lot on Lua lately doing an AddOn for World of Warcraft. However, now that I'm back to playing my MUD actively, I've been trying to apply some of the scripting concepts that I've learned from making WoW AddOns to how I design and make scripts for CMUD. One of the aspects of Lua, among many other languages, that a lot of scripters focus on is readability and maintainability vs. CPU efficiency. Aka, if it doesn't have a notable impact on the CPU, and thus we can consider excess CPU usage insignificant, then we favor readability and maintainability. However, if CPU usage is not negligible then one must try to keep processing efficiency in mind when designing how to approach the problem.
I found that turning blocks of code into functions was a bit more readable and easier to maintain than unwieldy blocks of if statements and the like. So, slowly, my code evolved to include more and more functions, each function doing small bits and tasks assigned to them. It then occurred to me, as I returned to mudding and CMUD, that I might be able to apply these same concepts to how I wrote my CMUD scripts.
The Question
Do User-Defined Functions in CMUD come at a premium CPU-wise. Aka, do they cost enough processing power or memory that it would be inefficient to use them? Or, is the difference between using them and not using them negligible enough that I can choose to use them in order to make my code more readable.
The Experiment
The following class contains all of the tools used in my experiment to try this out. There are three aliases. I ran "testa" and "testb" 1000 times each by doing #LOOP 1000 {testa} and #LOOP {testb} respectively from the command-line (yes, it took a little while).
Code: |
<class name="Test" id="69">
<alias name="testa" id="64">
<value>$a = 1
$b = 2
#LOCAL $c
$secs = %float(%secs)
#LOOP 10000 {#CALL @DoTest()}
$elapsed = %float((%secs - $secs))
$elap_var = $elapsed/1000
#ADDKEY testa_db %concat("rec", %numkeys(testa_db)) $elapsed
#SAY {%concat("Took ", $elap_var, " seconds to run")}</value>
</alias>
<func name="DoTest" id="65">
<value>#RETURN $c = $c + ($a*$b*$c)</value>
</func>
<alias name="testb" id="66">
<value>$a = 1
$b = 2
#LOCAL $c
$secs = %float(%secs)
#LOOP 10000 {$c = $c + ($a*$b*$c)}
$elapsed = %float((%secs - $secs))
$elap_var = $elapsed/1000
#ADDKEY testb_db %concat("rec", %numkeys(testb_db)) $elapsed
#SAY {%concat("Took ", $elap_var, " seconds to run")}</value>
</alias>
<var name="testa_db" id="67"/>
<var name="testb_db" id="68"/>
<alias name="test" id="70">
<value>#LOCAL $avg $total $numi
$max = 0
$min = 0
#SAY {"Results: "}
#SAY {"---------"}
#SAY {"testa"}
#LOOPDB @testa_db {
$num = %float(%int( %val))
$num = $num/1000
$max = %max( $max, $num)
$min = %min( $min, $num)
$total = %float($total + $num)
}
$numi = %float(%numitems( testa_db))
$avg = %float($total/$numi)
#SAY {%concat( "testa was run ", $numi, " times.")}
#SAY {%concat( "Times: max: ", $max, " | min: ", $min, " | avg: ", $avg)}
#SAY {"---------"}
#SAY {"testb"}
$max = 0
$min = 0
$total = %null
$num = %null
$numi = %null
#LOOPDB @testb_db {
$num = %float(%int( %val))
$num = $num/1000
$max = %max( $max, $num)
$min = %min( $min, $num)
$total = %float($total + $num)
}
$numi = %float(%numitems( testb_db))
$avg = %float($total/$numi)
#SAY {%concat( "testb was run ", $numi, " times.")}
#SAY {%concat( "Times: max: ", $max, " | min: ", $min, " | avg: ", $avg)}
#SAY {"---------"}</value>
</alias>
</class>
|
Results
This is the output that I got from the alias "test" after running both (for some reason the min/max values weren't showing properly):
Quote: |
Results:
---------
testa
testa was run 1000 times.
Times: max: 0 | min: 0 | avg: 0.0886939999999993
---------
testb
testb was run 1000 times.
Times: max: 0 | min: 0 | avg: 0.0667500000000002
---------
|
"testa" was the alias which uses the function call in place of doing the formula out normally. "testb" was the "normal" function. As you can see, "testb" is clearly more efficient than "testa". However, the margin of difference is 0.02 seconds over 1000 iterations of the formula.
Discussion
As expected, the function does have an added burden on processing which makes it take longer. However, is an extra 0.2 seconds over 1000 iterations (roughly 0.00002 seconds each) significant enough to worry about? I'm thinking that I can safely use functions for purposes of readability and maintainability without worrying too much over a slow-down in performance. |
|
|
 |
Rahab Wizard
Joined: 22 Mar 2007 Posts: 2320
|
Posted: Sun Jan 16, 2011 8:26 pm |
No, it is not enough to worry about. Use functions. Zugg included them specifically because it would make code easier to handle without causing extra overhead. His timing tests include testing the efficiency of functions.
|
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Jan 17, 2011 5:15 pm |
CMUD uses an efficient hashing scheme for looking up function names and those lookups are done at "compile time". So function calls in CMUD are efficient, just like they are in Lua. So yes, using functions is good.
|
|
|
 |
|
|
|
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
|
|