What is the disadvantage to importing functions into a scrip

Post » Thu Jun 21, 2012 11:52 pm

So why do this:


float xfloat yfloat zmath.pow()math.pow()math.pow()


instead of this:

import mathfloat xfloat yfloat zx = Pow()y = pow()z = pow()
User avatar
Kayla Bee
 
Posts: 3349
Joined: Fri Aug 24, 2007 5:34 pm

Post » Fri Jun 22, 2012 1:14 am

None, it appears.
	While aiIteration < 1000 ; Time Elapsed: 0.012001		aiIteration += 1		fVar = Math.Pow(10, 23)	EndWhile	While aiIteration < 1000 ; Time Elapsed: 0.012001		aiIteration += 1		fVar = Pow(10, 23)	EndWhile
Both while loops took the same amount of time to resolve.
User avatar
Skrapp Stephens
 
Posts: 3350
Joined: Mon Aug 06, 2007 5:04 am

Post » Thu Jun 21, 2012 5:08 pm

As JustinOther showed, it's not about the compiler, it's about making it easier for the coder. If you had a lot of calls to Math, it would reduce your typing. Even more significant, is if we could import custom scripts, those reference names could get much longer so even more typing is saved.
User avatar
lillian luna
 
Posts: 3432
Joined: Thu Aug 31, 2006 9:43 pm

Post » Fri Jun 22, 2012 1:07 am

I like typing the whole thing instead of importing scripts. But I guess I'm just weird like that.
User avatar
Add Me
 
Posts: 3486
Joined: Thu Jul 05, 2007 8:21 am

Post » Thu Jun 21, 2012 11:27 am

he he he.... I am going to start calling you Dr. Who. :biggrin:

None, it appears.
	While aiIteration < 1000 ; Time Elapsed: 0.012001		aiIteration += 1		fVar = Math.Pow(10, 23)	EndWhile	While aiIteration < 1000 ; Time Elapsed: 0.012001		aiIteration += 1		fVar = Pow(10, 23)	EndWhile
Both while loops took the same amount of time to resolve.
User avatar
BrEezy Baby
 
Posts: 3478
Joined: Sun Mar 11, 2007 4:22 am

Post » Thu Jun 21, 2012 11:58 pm

I like typing the whole thing instead of importing scripts. But I guess I'm just weird like that.
Same here. This way I'm less likely to goof and suggest Utility.DisablePlayerControls() or Game.RandomInt(1, 100).
he he he.... I am going to start calling you Dr. Who. :biggrin:
Ha :biggrin: It's actually really easy to run speed tests with Papyrus.
Spoiler
Function SpeedTest(Int aiIteration = 0, Float afStart = 0.0, Float afFinish = 0.0)	Debug.Notification("Test started...")	afStart = GetCurrentRealTime()	Debug.Trace("Start: " + afStart)	While aiIteration < 1000		aiIteration += 1	EndWhile	afFinish = GetCurrentRealTime()	Debug.Trace("Finish: " + afFinish)	Debug.Trace("Time elapsed: " + (afFinish - afStart))	Debug.Notification("Time elapsed: " + (afFinish - afStart))EndFunction
I use a quest which starts the test about 15 seconds after loading a clean save in a relatively empty cell.
User avatar
KIng James
 
Posts: 3499
Joined: Wed Sep 26, 2007 2:54 pm

Post » Thu Jun 21, 2012 7:40 pm

I need a test area with nothing but a floor and walls, do you know of any modder resource like that on the net someplace or maybe a TEST area hidden in the game?

There were several like this in Oblivion. I did most of my testing in the Arena in Oblivion, not exactly an empty cell but testing there also triggered lots of bugs that I would not have found in a clean cell. So I have been testing in the skyrim world for the same reason. But it is good to have a clean cell as well to be sure there is no interfering scripts running.

I could make one I guess but that is time away from scripting and I am too deep in the scripting right now.

...... use a quest which starts the test about 15 seconds after loading a clean save in a relatively empty cell.
User avatar
Roanne Bardsley
 
Posts: 3414
Joined: Wed Nov 08, 2006 9:57 am

Post » Thu Jun 21, 2012 6:26 pm

~COC Elsweyr or QASmoke from the main menu will do nicely (with nothing loaded for a clean save). QASmoke is Skyrim's TestingHall. QASmoke only has containers and crafting tables while Elsweyr just has M'aiq. Either cell should work without adding overhead for the test(s).
User avatar
Killer McCracken
 
Posts: 3456
Joined: Wed Feb 14, 2007 9:57 pm

Post » Thu Jun 21, 2012 1:52 pm

Nice to see you doing a few speed tests, JustinOther, but keep in mind that script speed can now be altered by unrelated scripts running at the same time, which is a problem I never had to worry about when running speed tests in Fallout.

How much are you controlling your testing environment? Actually, I'd love to have another script optimisation thread open to talk about this stuff, which would be a great place to discuss and test what the appropriate controls would be.

I think perhaps I should leave opening such a thread to you this time though. I've noticed you've done a few speed tests with Papyrus lately :)

Cipscis
User avatar
Kayla Oatney
 
Posts: 3472
Joined: Sat Jan 20, 2007 9:02 pm

Post » Thu Jun 21, 2012 7:22 pm

Nice to see you doing a few speed tests, JustinOther, but keep in mind that script speed can now be altered by unrelated scripts running at the same time, which is a problem I never had to worry about when running speed tests in Fallout.
The idea to test stuff in this manner was directly inspired by http://www.gamesas.com/topic/987561-script-optimisation/page__view__findpost__p__14279570 http://www.gamesas.com/topic/1139867-script-optimisation/page__p__16678605__hl__optimisation__fromsearch__1#entry16678605. Those were great!:)
How much are you controlling your testing environment? Actually, I'd love to have another script optimisation thread open to talk about this stuff, which would be a great place to discuss and test what the appropriate controls would be.
I perform the tests with a clean save (COC'd from main menu to QASmoke) 15 seconds after save load to reduce the likelihood of other scripts/whatnot interfering with the speed tests, all with the same programs open and such to ensure the environment is as close to identical as possible for each contender. If testing the same While loop multiple times, invariably the results are very close, so I'd imagine that's enough control.
I think perhaps I should leave opening such a thread to you this time though. I've noticed you've done a few speed tests with Papyrus lately :)

Cipscis
I've no cool graphs or charts or anything though :( I'd actually been hoping you were planning on doing it, but am willing if you aren't planning on it.

Here's the SpeedTest function I've been using:
Spoiler
Function SpeedTest(Int aiIteration = 0, Float afStart = 0.0, Float afFinish = 0.0)	Debug.Notification("Test started...")	afStart = GetCurrentRealTime()	Debug.Trace("Start: " + afStart)	While aiIteration < 1000		aiIteration += 1		; Code to test	EndWhile	afFinish = GetCurrentRealTime()	Debug.Trace("Finish: " + afFinish)	Debug.Trace("Time elapsed: " + (afFinish - afStart))	Debug.Notification("Time elapsed: " + (afFinish - afStart))EndFunction
User avatar
Princess Johnson
 
Posts: 3435
Joined: Wed Feb 07, 2007 5:44 pm

Post » Thu Jun 21, 2012 1:34 pm

Just to add some data for anyone who is worried about performance my testing shows these relative speeds for some operations. (I originally posted these over in the SKSE thread, but maybe it's more relevant here.)

ref = cachedRef
1.0 - simply copying a reference variable is pretty fast (although there are some things like just checking "if x > 3" that are even slightly faster.

GetReference()
1.0 - Just calling the function without using the result (which obviously isn't very useful)

ref = GetReference()
2.0 - obviously it's just the sum of assignment and function call results

GetRef()
2.0 - it's a wrapper function which then calls GetReference() so that's two calls total and would be 3 if you then try to use it!

GetPlayer()
Game.GetPlayer() 
930.0 - with Game imported or without makes absolutely no difference

So calling a function from another script has a huge performance hit (at least on my system) but the use of import doesn't make any difference.
User avatar
StunnaLiike FiiFii
 
Posts: 3373
Joined: Tue Oct 31, 2006 2:30 am

Post » Thu Jun 21, 2012 9:58 am

I can't remember what or where, exactly, but I remember reading recently about some funny things happening after using COC from the main menu. I don't remember the details though, so I'm not sure if it'd be relevant to this sort of thing.

This definitely still has my interest, but I'm stuck without internet at home right now so I can't do much at the moment. Almost all of my recent posts have been from my phone.

One thing that could be a useful shortcut now for testing very low-level changes is just comparing compiled scripts from different sources. It'd be interesting to see if the compiler optimises code so, for example, incrementing variables via the = and + operators is as efficient as the += operator.

I'll likely set something up once I can if you haven't before then, but if you're already doing this stuff I don't think starting without me (sort of) would hurt.

Cipscis
User avatar
Emma Parkinson
 
Posts: 3401
Joined: Wed Jul 26, 2006 5:53 pm

Post » Thu Jun 21, 2012 1:48 pm

@cdcooley:
That's just the sort of stuff I'd like to see in an optimisation thread :)

In the case of Game.GetPlayer() I expect it's not that the function is external that's the problem, just like it doesn't mean global fuctions are less efficient. More likely that's just how long the GetPlayer function takes to execute.

Cipscis
User avatar
Brad Johnson
 
Posts: 3361
Joined: Thu May 24, 2007 7:19 pm

Post » Thu Jun 21, 2012 9:12 am

I can't remember what or where, exactly, but I remember reading recently about some funny things happening after using COC from the main menu. I don't remember the details though, so I'm not sure if it'd be relevant to this sort of thing.
So far, I've notice no oddities using such a clean save, but I never do anything with it but test stuff. Given the results of the speed tests are consistent across PC restarts, game restarts, and save loads, It seems a sufficiently controlled environment.
This definitely still has my interest, but I'm stuck without internet at home right now so I can't do much at the moment. Almost all of my recent posts have been from my phone.
Ah... Hope you get internet back at home, in that case. Was wondering where you'd been... :)
One thing that could be a useful shortcut now for testing very low-level changes is just comparing compiled scripts from different sources. It'd be interesting to see if the compiler optimises code so, for example, incrementing variables via the = and + operators is as efficient as the += operator.
Like 'aiIteration += 1' vs. 'iaiIteration = (aiIteration + 1)'. I could do that right now and also estimate the 'cost' of the SpeedTest's While loop.

*Done 'aiIteration += 1' and 'aiIteration = (aiIteration + 1)' took the same amount of time whether as an argument or variable.

I'll likely set something up once I can if you haven't before then, but if you're already doing this stuff I don't think starting without me (sort of) would hurt.

Cipscis
Just might start one if you don't get around to it. Will be a handy reference either way.
User avatar
Timara White
 
Posts: 3464
Joined: Mon Aug 27, 2007 7:39 am

Post » Thu Jun 21, 2012 6:05 pm

If you guys are going to take requests, can you check which is more efficient?

GlobalVar.Value vs GlobalVar.GetValue()
(GlobalVar.Value as Int) vs GlobalVar.GetValueInt()
SomeReference.X vs SomeReference.GetPositionX()
(SomeFloat as Int) vs Math.Floor(SomeFloat)
User avatar
Kayla Bee
 
Posts: 3349
Joined: Fri Aug 24, 2007 5:34 pm

Post » Thu Jun 21, 2012 3:36 pm

If I may make a couple of suggestions if you want to dig into performance and low-level stuff:

http://www.creationkit.com/StartStackProfiling_-_Debug
http://www.creationkit.com/StartScriptProfiling_-_Debug
http://www.creationkit.com/StartObjectProfiling_-_Form

And try invoking the compiler and assembler in the command line with the -? switch.
User avatar
Matthew Barrows
 
Posts: 3388
Joined: Thu Jun 28, 2007 11:24 pm

Post » Thu Jun 21, 2012 9:14 pm

Thanks SmkViper, those might be handy (especially some of the command line switches for the compiler and assember). But frankly for determining what is and isn't effciient the instruction counts and trace information in the profile log files aren't really that helpful. JustinOther's profiling technique combined with some Trace calls is almost as accurate as the timing on the profile log. The only two (minor) flaws I can find with his code is that the Utility.GetCurrentRealTime call actually takes longer to execute than the while loop and decrement wrapped around the test code and that Skyrim's threaded operation means that times can vary widely from one run to the next.

OK, I'm putting together a more formal test framework to try and address both of those issues plus the fact that some operations take more than 10,000 times longer than others! I already have a basic version that I want to polish a little more tomorrow and then maybe release for others to see. I'll also start a new thread about this sometime tomorrow, but here are some of the results so far. Each case is run five times so you can see how much the times vary. And the loop that calculates the cost can run anywhere from 100 to 1000000 times trying to get a different big enough to be reliable. And still there's far too much variation for my taste.

Test Case:    0               if 0            if n            if !n           ref=0x14/ActorCost/1000:   -0.000073        0.002433        0.002467        0.005600        0.017034Cost/1000:    0.000100        0.002500        0.002500        0.005600        0.017600Cost/1000:   -0.000093        0.002367        0.002267        0.005433        0.018533Cost/1000:    0.000033        0.002500        0.002434        0.005633        0.018467Cost/1000:    0.000100        0.002433        0.002367        0.004800        0.017767

The first case is just a 0 and apparently that gets optimized away because it doesn't take any more time than an empty loop.

The second, third, and fourth are just variations on a very basic and empty if/endif statement. The ! (not) operator seems to take about as much time as the if itself.

The fifth was really "ref = GetForm(0x00000014) as Actor" which is functionally equivalent to Game.GetPlayer() but as you'll see in the next section is very, very much faster.

Test Case:    GetPlayer()     GetReference()  ref = me        0.04 as int     Floor(0.04)Cost/1000:    20.773335       0.019167        0.002433        0.002500        0.009700Cost/1000:    21.303345       0.020267        0.002500        0.002333        0.009667Cost/1000:    20.960020       0.019933        0.002400        0.002400        0.009734Cost/1000:    21.179985       0.019533        0.002467        0.002267        0.009667Cost/1000:    21.439970       0.020033        0.002334        0.002433        0.009533

So as you can see a "ref = GetReference()" is the same as the the GetForm() function above.

"ref = Game.GetPlayer()" was much, much worse and "ref = me" where me already had the player reference was faster.

Casting an floating value into an int is also faster than using the Math.Floor function.

Test Case:    GetDistance()   get time        if n == 0       if !n; n=5      n = 5Cost/1000:    21.783318       21.749992       0.005500        0.004833        0.002367Cost/1000:    21.246670       21.376659       0.004833        0.004900        0.002433Cost/1000:    21.926651       21.253384       0.005700        0.004734        0.002400Cost/1000:    21.450018       20.509975       0.006366        0.004867        0.002467Cost/1000:    21.423367       21.360014       0.005600        0.004767        0.002333

In Morrowind and Oblivion "dist = self.GetDistance(other)" was one of the most expensive functions to call, but now it's no worse than
"ref = Game.GetPlayer()" and "Utility.GetCurrentRealTime()".

But the classic case still holds that simply setting a variable to a value "n = 5" is better than wrapping it with an if to check whether it is zero.

OK, so I know the formatting could use some work. Inverting my tables is probably the best first step.
User avatar
Lucky Girl
 
Posts: 3486
Joined: Wed Jun 06, 2007 4:14 pm

Post » Thu Jun 21, 2012 12:53 pm

Thanks SmkViper, those might be handy (especially some of the command line switches for the compiler and assember). But frankly for determining what is and isn't effciient the instruction counts and trace information in the profile log files aren't really that helpful. JustinOther's profiling technique combined with some Trace calls is almost as accurate as the timing on the profile log.

One piece of data you can get from profiling logs that you can't get from Justin's test case (which is a great "quick n' dirty" test!) is how long a function was waiting to run because outside factors put the call "on hold", and how long the return of the function was also "on hold". It's a little more work when you're just trying to find out if "GetPlayer" or "GetReference" is faster, but can be invaluable when you're trying to figure out that your script is slow because it's fighting over the same object with 20 other threads.

But yes, you'll probably want some kind of tool to parse the profile logs to make sense out of them.
User avatar
Felix Walde
 
Posts: 3333
Joined: Sat Jun 02, 2007 4:50 pm

Post » Thu Jun 21, 2012 8:26 pm

If I may make a couple of suggestions if you want to dig into performance and low-level stuff:

http://www.creationkit.com/StartStackProfiling_-_Debug
http://www.creationkit.com/StartScriptProfiling_-_Debug
http://www.creationkit.com/StartObjectProfiling_-_Form

And try invoking the compiler and assembler in the command line with the -? switch.
Thanks for the tips. :) I've read of them, but hadn't yet delved into tinkering with those.
...Justin's test case (which is a great "quick n' dirty" test!)...
Danke :) Three cheers for your brainchild :foodndrink: Papyrus is brain candy!
User avatar
luis dejesus
 
Posts: 3451
Joined: Sun Aug 19, 2007 7:40 am

Post » Thu Jun 21, 2012 11:51 am

Got another one:

int PowerAttack = 1
if attacker.isinfaction(aadpPowerAttackFaction) == true
PowerAttack = 2
endif

OR

int PowerAttack = 1 + ((attacker.isinfaction(aadpPowerAttackFaction)) as int)

Seems to me the latter would have to be faster or the same but not slower...right?
User avatar
kasia
 
Posts: 3427
Joined: Sun Jun 18, 2006 10:46 pm

Post » Thu Jun 21, 2012 5:15 pm

Got another one:

int PowerAttack = 1
if attacker.isinfaction(aadpPowerAttackFaction) == true
PowerAttack = 2
endif

OR

int PowerAttack = 1 + ((attacker.isinfaction(aadpPowerAttackFaction)) as int)

Seems to me the latter would have to be faster or the same but not slower...right?
An interesting one. the second one would be way faster should you wouldn't be using a casting at the end. But that casting from bool to int, could change all the balance.

The best you can do is to avoid the casting entirelly.

Instead of using aadpPowerattackFaction as a faction to be in or not, give it rank 1 (instead of not being in the faction) and rank 2 (instead of just being in the faction). and instead of adding or removing NPCs from that faction, just give them the first or second rank.

That way, your code would end like:

int PowerAttack = attacker.getfactionrank(aadpPowerAttackFaction)

which would be way faster than any of your two options, unless getfactionrank is extremelly slow comparing with isinfaction.
User avatar
Gemma Flanagan
 
Posts: 3432
Joined: Sun Aug 13, 2006 6:34 pm

Post » Thu Jun 21, 2012 7:42 pm

Keyword vs. FormList
Spoiler
	While aiIteration < 1000		aiIteration += 1		bVar = kFLST.HasForm(kARMO) ; Time elapsed: 14.004997	EndWhile
	While aiIteration < 1000		aiIteration += 1		bVar = kARMO.HasKeyword(kKYWD) ; Time elapsed: 14.024998	EndWhile
Not much difference, but it appears checking a FormList is slightly faster.

Incidentally, adding a few hundred forms to the FLST didn't impact the speed of the loop, nor did adding a few dozen keywords to the ARMO.
User avatar
Tiffany Holmes
 
Posts: 3351
Joined: Sun Sep 10, 2006 2:28 am

Post » Thu Jun 21, 2012 1:51 pm

It may be overkill, but I almost always type out the 'other scripts' name when calling those external functions... like debug.notif, utility.wait, etc. Maybe it's getting a bit late and I missed it in a previous post, but is there hard evidence either way: doing a utility.wait vs doing the import utility first? I've tried to avoid it because of the sheer SOUND of it... importing an entire script - and I KNOW that's not really the case, but it still has psychosomatic repercussions on my scripting persona... heheh. Maybe that could be elaborated on in the wiki if it hasn't been already (it's been several months since I breezed through that site).
User avatar
Laura Wilson
 
Posts: 3445
Joined: Thu Oct 05, 2006 3:57 pm

Post » Thu Jun 21, 2012 1:43 pm

Maybe it's getting a bit late and I missed it in a previous post, but is there hard evidence either way: doing a utility.wait vs doing the import utility first?
http://www.gamesas.com/topic/1381253-what-is-the-disadvantage-to-importing-functions-into-a-script/page__view__findpost__p__20929622
User avatar
Daniel Lozano
 
Posts: 3452
Joined: Fri Aug 24, 2007 7:42 am

Post » Thu Jun 21, 2012 1:31 pm

I don't mean to be a stickler.. but one function may not cause much difference. (though at .012etc it doesn't really matter too much) I have several of such functions I call - probably a dozen or so per iteration. But as your test shows, it MAY kick it up to .013 heheheh. My lingering issue is for people with systems that aren't so fast, and are running tons of mods that screw up timing. I know that can't be helped from an individual modder's perspective (aside from helping to educate others to fix their stuff)... but it's still an inevitability that people will complain about... so may play a part. I suppose it would come down to the amount of time each thread is allocated - and whether the system and errors push that back - as opposed to the import. I guess I just answered my own question - but I'd still like to know for SURE.

[EDIT: and yes.. it's getting late... I missed it heheheh - thanks for your patience!]
User avatar
liz barnes
 
Posts: 3387
Joined: Tue Oct 31, 2006 4:10 am

Next

Return to V - Skyrim