fishburger67 Posted August 16, 2016 Posted August 16, 2016 View File This topic is designed for Fallout 4 mod developers. It is not for mod users. As I move along in my papyrus experience, I learned a great deal. The purpose of this thread is to collect "Gems" of knowledge that other developers might find useful. I hope everyone with papyrus experience will share their knowledge. If you post something useful here, I will collect it and add it to the download document. The only thing I ask is that you prove your assertion with example code. Submitter fishburger67 Submitted 08/16/2016 Category Other Requires
Guest Posted August 16, 2016 Posted August 16, 2016 I did the standard test of Game.getPlayer() compared to the PlayerRef property. The code was: int i =10000 while i i-=1 Actor a = Game.getPlayer() bool t = a.isDisabled() endWhile And Actor property PlayerRef Auto int i =10000 while i i-=1 Actor a = PlayerRef bool t = a.isDisabled() endWhile The second one is about twice as fast. (I will post real numbers, but I did the test months ago.)
darkconsole Posted August 17, 2016 Posted August 17, 2016 the reason for your #1 is actually the heart of the multithreading engine, and can be both a good and bad thing. every time you access an external function that unlocks the papyrus engine to process other threads, when it gets back to yours that external call happens and the result is returned back to your original thread. you actually /need/ to design your scripts with this in mind. things that are not mission critical you can actually help the game be more responsive by letting your lock go for a little bit when calling these external methods. the only time you should really local all the things is when timing is critical - but considering papyrus, even that is kind of a joke. for example in soulgem oven the background loop that processes all the actors in queue references all external methods to the sgo main script. it is not mission critical that my queue processes as fast as it can, in fact, it should go as slow as it can and use the least amount of cpu time possible. by constantly unblocking my thread with these external calls other scripts trying to do more important things can do more important things more often. by doing that i am basically allowing my loop to be put on hold for other things at multiple points during any single iteration. skyrim link, but its basically the same engine in fo4. http://www.creationkit.com/index.php?title=Threading_Notes_(Papyrus) if you replace Math.pow with a multiplicative loop, there is a chance that 4.7ms function could be even faster because of the external call to Math.pow. depends how busy your engine is, and if the external call to a native function is slower than an all local execution scope of non native code.
Guest Posted August 17, 2016 Posted August 17, 2016 ... Very good posts. And, if may add, don't do something that is invariant many times inside a cycle. If you just ask for the player once, then there is no real difference between the two ways. But if you do it in a cycle, then don't use the heavy form. (The same for every other call/computation.)
darkconsole Posted August 17, 2016 Posted August 17, 2016 for anther example, because sexlab is soooooooooooooooooo fragmented, its actually theoretically, technically, and most probably, allowing more different things to access and do sexlab things as the chance for an unblock is so high. and that actually ends up being a good thing, things like sexlab aroused, etc, and any other mod ever using the sexlab api, can get in and out of sexlab script instances more often than if he coded it all flat. so at the end of it, while his execution time is slower, in whole, the game is going to be generally more responsive due to it.
Guest Posted August 17, 2016 Posted August 17, 2016 ... That is not actually true. SexLab is structured as 3 main types of scripts. The interface, The data, Then runners. Runners, once started, then should NOT be called or changed. (e.g. sslThreadController) The interface is safe for multiple calls. (And is not really event based, all functions are NOT latent) (e.g. SexLabFramework) The data does not matter, it is just data. (e.g. sslbaseAnim) Writing all in a single script? not possible, and really limiting the parallelism, and consuming way too much memory.
darkconsole Posted August 17, 2016 Posted August 17, 2016 but you can still ping the runners. Untamed actually pings and modifies running sexlab instances to make "infinite sex mode" work, and the core framework is still an instance. if all his work was done in the core, it would almost never unblock and all the other mods would get queued up against it for doing simple things like GetGender. because its fragmented the SexLabFramework instance almost never blocks.
Guest Posted August 17, 2016 Posted August 17, 2016 ... That is correct. But then you will limit a lot the parallel execution of different mods (or a multi threaded mod like the one I wrote.)
darkconsole Posted August 17, 2016 Posted August 17, 2016 yep. tl;dr don't fear the external calls there are very few reasons you genuinely need to ensure a blocking thread in papyrus. expired often used to tell me to shut up and just write an skse plugin when talking about needing precision lol.
fishburger67 Posted August 17, 2016 Author Posted August 17, 2016 This is not entirely true. the reason for your #1 is actually the heart of the multithreading engine, and can be both a good and bad thing. every time you access an external function that unlocks the papyrus engine to process other threads, when it gets back to yours that external call happens and the result is returned back to your original thread. you actually /need/ to design your scripts with this in mind. things that are not mission critical you can actually help the game be more responsive by letting your lock go for a little bit when calling these external methods. the only time you should really local all the things is when timing is critical - but considering papyrus, even that is kind of a joke. There is still a context switch when you call external functions, that in itself takes CPU cycles. for example in soulgem oven the background loop that processes all the actors in queue references all external methods to the sgo main script. it is not mission critical that my queue processes as fast as it can, in fact, it should go as slow as it can and use the least amount of cpu time possible. by constantly unblocking my thread with these external calls other scripts trying to do more important things can do more important things more often. by doing that i am basically allowing my loop to be put on hold for other things at multiple points during any single iteration. skyrim link, but its basically the same engine in fo4. http://www.creationkit.com/index.php?title=Threading_Notes_(Papyrus) if you replace Math.pow with a multiplicative loop, there is a chance that 4.7ms function could be even faster because of the external call to Math.pow. depends how busy your engine is, and if the external call to a native function is slower than an all local execution scope of non native code. I used Math.pow() because it is one of the few external calls that do not do a lock. http://www.creationkit.com/fallout4/index.php?title=Category:Non-Delayed_Native_Functions Quote from http://www.creationkit.com/fallout4/index.php?title=Performance_(Papyrus) Because every time you call a function on another script that isn't you or a script you extend (i.e. the "self" variable would be different - even if it's attached to the same form) there is a cost in switching. This cost may be expensive if the object is used by a lot of scripts (i.e. the player). So if you find yourself calling multiple functions in a row on the same object, it might be better to group them into a function on the target object and call that instead. That way the switch cost is only paid once. This may not always be possible, however, especially if the destination script isn't one you own. So, in my view, this is all a balancing act. You want to minimize CPU cycles while still making FO4 responsive.
fishburger67 Posted August 17, 2016 Author Posted August 17, 2016 Additional testing for non-local calls. Redid the test where a bit of code was run locally within class or externally in another class. The results are similar For a 100 count loop this time: local - 103.87msec remote - 126.03 remote with return value - 138.43 That means about .26msecs per call, so if you subtract out the frame rate of .16, you get .1msec per context switch. Not a big deal unless you are doing lots of it which I do in several cases. This time, I got rid of the math.pow() function and just did this: function testMath2Local(int count) int i = 0 while i < count Float timeSinceUpdate = 4.00 Float res = timeSinceUpdate * 25.6 i = i + 1 endwhile endFunction function testMath2Remote(int count) int i = 0 while i < count testScript.mathTestRemoteNoExternal() i = i + 1 endwhile endFunction Scriptname SLAR:slaTestScript extends Quest function mathTestRemote() Float timeSinceUpdate = 4.00 Float res = Math.pow(1.5, - timeSinceUpdate) endFunction function mathTestRemoteNoExternal() Float timeSinceUpdate = 4.00 Float res = timeSinceUpdate * 25.6 endFunction Float function mathTestRemoteNoExRet() Float timeSinceUpdate = 4.00 Float res = timeSinceUpdate * 25.6 return res endFunction
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now