SKKmods Posted September 25, 2021 Share Posted September 25, 2021 @PJMail when you run sctipt tests you need to know what frame rate your game is running at. Use something like Nvidia, Riva, or Steam overlay. ps I'm super interested but cant participate in testing as working on another game platform. Link to comment Share on other sites More sharing options...
DlinnyLag Posted September 25, 2021 Share Posted September 25, 2021 ps I'm super interested but cant participate in testing as working on another game platform. Don't miss my comment on previous page %) Link to comment Share on other sites More sharing options...
PJMail Posted September 25, 2021 Author Share Posted September 25, 2021 Hi SKK - sorry I forgot to add it into my email. The steam overlay said 13FPS. Told you it is a potato (old HP Core i5 laptop with Intel Graphics). Link to comment Share on other sites More sharing options...
PJMail Posted September 25, 2021 Author Share Posted September 25, 2021 (edited) I added 2 extra scripts on the same actor - basically a copy of my test script in each of these scripts. ScriptName Testscript1 extends Actorint itestCount;Function StartTest1() StartTimer(2.0,2)Endfunction;Event OnTimer(int tnum) int iIterations = 300 Const Debug.Trace("Timing Test "+tnum+" Started "+iIterations+" Iterations",0) int iCounter = 0 int iMinCounter = 0 GlobalVariable gTimeScale = Game.GetForm(0x03A) as GlobalVariable float fStartTime = Utility.GetCurrentRealTime() While (iCounter < iIterations); int iR = Utility.RandomInt(0, 100); int fs = self.getflyingstate(); bool b3D = self.is3DLoaded(); float fTime = Utility.GetCurrentRealTime() float fTs = gTimescale.GetValue(); (Self as Objectreference).enableNoWait(); (Self as Objectreference).enable() iCounter += 1 iTestCount += 1 iMinCounter += 1 int itestCountCopy = itestCount if (iMinCounter == 60) Debug.Trace(" - Test "+tnum+" at "+iCounter+" Iterations. Global count "+iTestCountCopy,0) iMinCounter = 0 Endif EndWhile float fScriptFrameRate = iIterations as float / (Utility.GetCurrentRealTime() - fStartTime) Debug.Trace("Timing Test "+tnum+" Ended. FPS="+fScriptFrameRate,0) Debug.Notification("Timing Test "+tnum+" Ended. FPS="+fScriptFrameRate)EndEvent And a similar testscript2, with procedure starttest2 that does StartTimer(2.0,3) The main script runs StartTimer(2.0,1) ((Self as objectreference) as Testscript1).StartTest1() ((Self as objectreference) as Testscript2).StartTest2() The results are - all functions run as if 'latent' - i.e. the output from the 3 loops are interleaved.If the function is "GetValue()" then I get about 140 iterations/s from all 3 loops simultaneouslyIf it is self.enable() I get 12 iterations/s from all 3 loops simultaneouslyIf it is "self.is3Dloaded()" I get 12 iterations/s from all 3 loops simultaneously So separate scripts on the same object (in this case an NPC) do not block each other.A nice way to speed up response time in scripts (at the expense of the rest of the game no doubt...) Now looks like I need to break up my monolithic NPC script into distinct 'Task' based scripts...And remove a lot of tests - pre-testing now seems pointless as it slows down the script i.e. If (obj.IsEnabled()) ; Delayed and not latent obj.disable() ; Delayed and LatentEndif takes longer than just doing obj.disable() ; delayed and latent Edited September 25, 2021 by PJMail Link to comment Share on other sites More sharing options...
PJMail Posted September 25, 2021 Author Share Posted September 25, 2021 (edited) @DlinnyLag - I am still digesting your summary of the latent vs delayed matrix. I am not sure about :- latent + non-delayed - does not release script's lock on call. Execution is postponed, probably to the next frame or later. Can return some result back to script. Lock remain on script until postponed function is not finished. as doesn't latent mean script lock is released? I have not seen any function with this combination so probably a moot point... Ones documented to be this (such as enable()) I have found to actually be "Latent + delayed" and "enablenowait()" to be "not latent + non-delayed". The other 3 combinations fit the "latent" "non-delayed" and "everything else" lists in the doco. Edited September 25, 2021 by PJMail Link to comment Share on other sites More sharing options...
SKKmods Posted September 25, 2021 Share Posted September 25, 2021 One thing to consider is that by multithreading with each script being a thread your solution can consume an unfair share of papyrus timeslices which can inconvinience other solutions. Sometimes it just has to be done, and if so best to provide clear end user disclosure and warnings: WARNING: THIS IS IMPORTANTThe actor hostile conversion process has a lot of script work to do in a short time between the workshop actors loading and your fight starting. By "sharding" the scripts into multiple "threads" it takes around 20 seconds to process 60 actors (uniqe+settlers+turrets) on a vanilla system running at 60 fps. Which is fine if you dont sprint so there is time to process.Script sharding grabs an unfair share of papyrus processing time to get the job done. If you have other workshop/actor script intensive solutons like Sim Settlements or PANPC your experience will degrade as the script system will not have enough real time slices for everything. Slow down approaching workshops with all this stuff running. (1) Script resources: When this solution first finds a workshop to configure it will be extremely script intensive if there are a large number of workshop registered actors (aka "settlers") it can take 20 seconds for 20 settlers at 60fps. This is amped up by configure weapons/armor options which adds 40 seconds for 20 settlers at 60fps, there are no free lunches in compute resources. This actor configuration may collide with the base game ResetWorkshop update and any other workshop/settlement script intensive mods slowing everything down even more. Once a workshop actor list is loaded only new actors or configuration changes are applied. Link to comment Share on other sites More sharing options...
PJMail Posted September 25, 2021 Author Share Posted September 25, 2021 I just want to emphasize an observation when I was doing all the tests in the same script - Only Sometimes OnEvent functions aren't blocked, yet they are non-native so should never be blocked from starting. Most of the time it seems they don't start if a loop running non-latent calls is running (but not all the time). I had a trace line at the start of the OnTimer event, then after a few initializations there was the "GetCurrentRealTime()" call - which caused the event function to stop and not restart until the other non-latent loop had completed. Sometimes in the log was that trace line from both timer events together (followed by the rest of timer 1 lines, then all of timer 2 lines). What you would expect if the Event functions are not blocked until they run a function that can be blocked.However sometimes (just another run of the same script) all of timer 1 trace lines are followed by all of timer 2 trace lines - as if the ontimer event for timer 2 is blocked from starting. I don't know what to make of this since I would assume those onevent functions are 'not native' so not subject to blocking when they start. Always.Very random... Link to comment Share on other sites More sharing options...
PJMail Posted September 25, 2021 Author Share Posted September 25, 2021 @SKK - I remember seeing this on one of your mods (and the multiple threads trick) - I did my test as I didn't think you had tested this sort of thing on a single actor (your threads/tasks/shards are generated off a Quest I seem to remember). Anyway Bethesda already do this - if unintentionally - as quite a few NPCs have multiple scripts attached.I am considering using this same technique to speed up animation event handling by making it less 'single threaded' so more responsive, not for getting a large chunk of processing done in a short time. Link to comment Share on other sites More sharing options...
SKKmods Posted September 25, 2021 Share Posted September 25, 2021 Yes most of my scripts are quest or quest alias attached. But I did a bunch of script execution, threading, locking, loaded, unloaded, persistent, non persistent testing on scripts directly attached to 4096 wood box ObjectReferences ;) Link to comment Share on other sites More sharing options...
DlinnyLag Posted September 25, 2021 Share Posted September 25, 2021 (edited) doesn't latent mean script lock is released? I guess, no. At least I see that NoWait (non-delayed) flag is the only reason for keeping lock on a script while native function is executing. If I'm right, then explanation of results you've seen for Is3DLoaded function - it is just latent and non-delayed.I can see some reasons why it could be latent. Most likely it is related to thread safety in accessing to 3D data, but probably it is some kind of optimization, I can't say. If I would have access to sources of Creation Engine... it will be much easily to answer %) Edited September 25, 2021 by DlinnyLag Link to comment Share on other sites More sharing options...
Recommended Posts