Author |
Topic |
|
Deleted
deleted
4116 Posts |
Posted - 20 August 2002 : 01:20:23
|
I continue to run performance benchmarks on for-us-important topics: This time direct code vs procedure & function calls, with and without parameters...
Introduction <ul> <li>Testbed: P3-733, 512MB Ram, Win 2K Adv Srv SP3, IIS 5, closed many unnecessary services, firewall, virus checking etc, ran it with about 400MB free RAM.</li> <li>I ran the scripts on the same machine using IE 5.5 SP 2</li> <li>The timer code of the forum is used to measure the execution time between the start and end of the script, so it will not include any disk I/O</li> <li>I used a simple string assignment of type str2=str1, where str1 was a string of 100 chars. This is chosen as v4 addons mostly deal with strings.</li> <li>I ran the tests 10 times and took the average. I each case the variance was negligable.</li> <li>The data from first run is not taken into account (because IIS 5 precompiles the files in the first run, if necessary), I pressed Ctrl+F5 for the second run.</li> <li>I took the iteration as 1,000,000 in all tests. All times are in seconds.</li> <li>I included TEST-0 here, which measures the loop execution time, whithout doing anything, it is not negligable in this case (about 0.5 sec for 1,000,000 iterations).</li> </ul>
I tried to determine which one is (how much) better, to decide on comprimise between using subs/functions for better readability/maintainability and speed. <ol type="1"> <li>Using the code in the loop as is,</li> <li>Using SUB without parameters,</li> <li>Using SUB with a parameter,</li> <li>Using FUNCTION without parameters,</li> <li>Using FUNCTION with a parameter.</li> </ol id="1">
<b>TEST-0 (dummy loop)</b> This is included to measure the time that is used for the looping code.
<b>test_subcall1.asp:</b> <pre id="code"><font face="courier" size="2" id="code"><font color="blue"> timer start Dim str1, str2 str1 = "01234567890..." ' 100 chars
' ==== START OF LOOP (TIMED WORK)===== StartTimer 1 for i = 1 to MaxIteration str2 = str1 next
timer stop </font id="blue"></font id="code"></pre id="code">
<b>test_subcall2.asp:</b> <pre id="code"><font face="courier" size="2" id="code"><font color="blue"> timer start sub dummysub() str2 = str1 end sub
Dim str1, str2 str1 = "01234567890..." ' 100 chars
' ==== START OF LOOP (TIMED WORK)===== StartTimer 1 for i = 1 to MaxIteration call dummysub() next
timer stop </font id="blue"></font id="code"></pre id="code">
<b>test_subcall3.asp:</b> <pre id="code"><font face="courier" size="2" id="code"><font color="blue"> timer start sub dummysub(str1) str2 = str1 end sub
Dim str1, str2 str1 = "01234567890..." ' 100 chars
' ==== START OF LOOP (TIMED WORK)===== StartTimer 1 for i = 1 to MaxIteration call dummysub(str1) next
timer stop </font id="blue"></font id="code"></pre id="code">
<b>test_subcall4.asp:</b> <pre id="code"><font face="courier" size="2" id="code"><font color="blue"> timer start
function dummysub() dummysub = str1 end function
Dim str1, str2 str1 = "01234567890..." ' 100 chars
' ==== START OF LOOP (TIMED WORK)===== StartTimer 1 for i = 1 to MaxIteration str2 = dummysub() next
timer stop </font id="blue"></font id="code"></pre id="code">
<b>test_subcall5.asp:</b> <pre id="code"><font face="courier" size="2" id="code"><font color="blue"> timer start
function dummysub(str1) dummysub = str1 end function
Dim str1, str2 str1 = "01234567890..." ' 100 chars
' ==== START OF LOOP (TIMED WORK)===== StartTimer 1 for i = 1 to MaxIteration str2 = dummysub(str1) next
timer stop </font id="blue"></font id="code"></pre id="code">
<hr noshade size="1">
<b>TEST RESULTS</b>
<pre id="code"><font face="courier" size="2" id="code"> <b> TEST-0 TEST-1 TEST-2 TEST-3 TEST-4 TEST-5</b> <b>AVG</b> 0.48 1.51 4.65 4.50 4.99 4.90 <b>VAR</b> 0.0000 0.0001 0.0001 0.0001 0.0002 0.0001 <b>INDEX</b> 32 100 309 299 331 325 </font id="code"></pre id="code">
<hr noshade size="1"> <b>PRELIMINARY CONCLUSION</b>
As can be seen from the results, passing a parameter to a function or sub does not effect the performance in negative way (actual results are a bit in positive direction this case). The reason can be that parameter case usess local variables that are more speedy than global variables.
Functions (in this examples) have %10 performance overhead because of the returned data.
And finally, functions/procedures (again in this example) are 3 times slower than using the code directy.
<b><font color="red">BUT: This does not mean that subs/functions should be avoided.</b></font id="red">
<ol type="1"> <li>The example given above uses a very simple string assignment, which takes a server time of [1.51-0.48=1.03] seconds for 1 million iterations. The overhead of calling a sub is about 3.1-3.3 seconds. If the code that executed takes more amount of time, the percentage of the overhead will drop drastically, because it is fixed. I.e. calling a sub once will take about 0.000003 seconds on the server. This is about 1/100.000th of the page execution time (e.g. active.asp) on Snitz site with v3.4.</li> <li>Having repeated inline code will take additional time to load, as the file size is larger. With subs/procedures </li> <li>As you know, subs/procedures are great if you can generalize tasks so that readability, re-usability and maintainability is improoved.</li> <li>As an example I can give function fLang(s). It does nothing! But, with the help of it I take the control in my hands during development. <pre id="code"><font face="courier" size="2" id="code"><font color="blue"> function fLang(s) if blnLangDebug then fLang= "*" & s else fLang = s end if end function </font id="blue"></font id="code"></pre id="code">
As you can see here, with setting blnLangDebug to true, every string which is transferred to the Languge files gets a "*" nfront of it, so that we can fish out untransformed ones.
Note: This is a code portion from v4b04, which is different from v4b03.x... </li>
Also the readability will be improved if you use this structure:
<pre id="code"><font face="courier" size="2" id="code"><font color="blue"> select case strCode case 1 call sub1() case 2 call sub1() case 3 call sub1() case 4 call sub1() ... case N call subN() end select
sub sub1() ...some 100 lines of code... end sub : : sub subN() ...some 100 lines of code... end sub </font id="blue"></font id="code"></pre id="code">
This is, if these calls are NOT deep in the loops, where the overhead is larger.
<li>So, go use subs/functions!</li> </ol id="1">
|
Stop the WAR! |
Edited by - Deleted on 20 August 2002 01:22:56 |
|
Nathan
Help Moderator
USA
7664 Posts |
Posted - 20 August 2002 : 02:13:56
|
There is a problem in your tests, your functions are very simple and quick to execute. In test two there IS nothing to execute within them.
This makes the overhead of calling the function more substatntial in relation to the time it takes the code normally to parse. Run the test again whith longer functions, you may no longer see a 3x overhead.< |
Nathan Bales CoreBoard | Active Users Download |
|
|
Deleted
deleted
4116 Posts |
Posted - 20 August 2002 : 03:06:41
|
This is exactly what I'm saying above ! Read #1 in the conclusions part.
I used the extreme case to be able to calculate the exact absolute overhead (not relative), thus I was able to find it to be 3 microseconds.
If I were used a code which needs 1000x more execution time, I would have to use 1000x iteration instead of 1 million, I could not be able to even measure the difference, unless I run the test for hours instead of seconds, and that will be unreliable in a multi tasking environment (although minimized). < |
Stop the WAR! |
|
|
Deleted
deleted
4116 Posts |
Posted - 20 August 2002 : 03:09:32
|
quote: Originally posted by Nathan
In test two there IS nothing to execute within them.
Why < |
Stop the WAR! |
|
|
Nathan
Help Moderator
USA
7664 Posts |
|
Deleted
deleted
4116 Posts |
Posted - 20 August 2002 : 04:14:55
|
quote: Originally posted by Nathan
lol, I think I was being too pickey
It would help if you make suggestions . I'll run some existing forum code to show the difference (was planning already ). < |
Stop the WAR! |
|
|
|
Topic |
|
|
|