I've you're a modder wondering which Papyrus script functions and operations are faster then you now have a way to find out. I've written an initial set of tests and if you're a script writer it should be easy enough for you to add your own to the list.
So what are my results so far? The raw data is here:
Papyrus Speed TesterObjectReference script testsOverhead Time: 0.013600 used by the timing function itselfBaseline Time: 0.013199 an 'empty' loop 1000 timesTest case 8: 12.858016 f = GetDistance(PlayerRef)Test case 7: 12.673988 f = self.GetDistance(PlayerRef)Test case 6: 12.948014 f = PlayerRef.GetDistance(self)Test case 5: 12.888017 b = IsLocked()Test case 4: 12.753998 f = GetPositionX()Test case 3: 12.745988 f = self.GetPositionX()Test case 2: 13.131989 f = XTest case 1: 13.151978 f = self.XReferenceAlias script testsOverhead Time: 0.013100 time used by the timing function itselfBaseline Time: 0.013400 'Empty' Loop 1000 timesTest case 45: 12.648018 Debug.GetVersionNumber()Test case 44: 12.712014 SKSE.GetVersionRelease()Test case 43: 13.050011 if ref.GetBaseObject() as Potion | endifTest case 42: 12.551986 if ref.GetType() == 46 | endifTest case 41: 0.012098 if GameDaysPassed as GlobalVariable | endifTest case 40: 12.718003 if GameDaysPassed.GetType() == 9 | endifTest case 39: 0.009546 s = "sample"Test case 38: 0.029388 i = GameDaysPassed.Value as intTest case 37: 0.027518 f = GameDaysPassed.ValueTest case 36: 0.028434 i = GameDaysPassed.GetValueInt()Test case 35: 0.017072 f = GameDaysPassed.GetValue()Test case 34: 12.950012 f = Utility.GetCurrentGameTime()Test case 33: 12.739990 f = PlayerRef.GetPositionX()Test case 32: 12.797974 f = ref.GetPositionX()Test case 31: 12.589997 f = PlayerRef.GetPositionX()Test case 30: 13.029968 f = PlayerRef.XTest case 29: 13.028077 f = ref.XTest case 28: 12.406006 f = PlayerRef.GetDistance(ref)Test case 27: 12.921876 ref = Game.GetPlayer()Test case 26: 0.031696 ref = GetRef()Test case 25: 0.021184 ref = GetReference()Test case 24: 0.009194 ref = PlayerRefTest case 23: 0.022252 ref = Game.GetForm(0x14) as ObjectReferenceTest case 22: 0.009192 ref = otherTest case 21: 0.012604 myActor = other as ActorTest case 20: 0.010586 ref = NoneTest case 19: 0.012588 i = 1 | if true | i = 2 | endifTest case 18: 0.008744 i = 1 + (true as int)Test case 17: 0.015898 i = Math.Floor(0.04)Test case 16: 0.008842 i = 0.04 as intTest case 15: 0.014084 if b | i=1 | endif | if !b | i=2 | endifTest case 14: 0.009972 if !b | i=1 | else | i=2 | endifTest case 13: 0.014116 if b | i=1 | elseif !b | i=2 | endifTest case 12: 0.012662 if b | b=false | elseif !b | b=true | endifTest case 11: 0.012398 if b==true | b=false | else | b=true | endifTest case 10: 0.010344 b = !bTest case 9: 0.008732 int n = 5Test case 8: 0.008734 i = 5Test case 7: 0.010072 if !i | i = 5 | endifTest case 6: 0.011458 if i > 0 | endifTest case 5: 0.010316 if i == 0 | endifTest case 4: 0.010160 if !i | endifTest case 3: 0.010128 if !b | b=true | endifTest case 2: 0.008736 b = trueTest case 1: 0.007236 0Testing Complete
A few of the highlights are:
- The fastest operations are simple assignments like "n = 5" or "ok = true".
- Checking to see if n != 5 before setting it to 5 is just wasteful since the if n != 5 part takes longer than just setting the variable.
- Casting with (0.04 as int) is about twice as fast as Math.Floor(0.04).
- GameDaysPassed.GetValue() is the best way to access a global variable. (But if you need to use it multiple times in a row, assign it to a local variable!)
- Accessing a PlayerRef property is about 1000 times faster than calling Game.GetPlayer().
- Accessing a property or variable is also about twice as fast as using GetReference().
- Using ref.GetPositionX() is slighly faster than ref.X, but the difference is small because both are pretty slow.
- All external script functions like Game.GetPlayer(), ref.GetPositionX(), ref.GetDistance(PlayerRef), etc. are approximately the same slow speed.
- SKSE provided functions aren't any slower than similar game functions.
Please try the scripts, add your own cases and post the results so we can find out more about what is and isn't good practice.
Let the testing begin.