Suspended stack count is over our warning threshold...

Post » Tue Dec 24, 2013 12:19 am

(I'm putting this here for reference. But please contribute to the discussion. Note that what I state here is from what I experienced during my gaming and modding. I'm not technically savvy and others may have a better understanding on the subject. Also, there may be other threads about the subject already, so just link to it in a comment. If the contents of this and that thread are similar, then I'll abandon this thread in preferences to that.)

Question: Does your game feel like it is slow to respond to events?

The game world (i.e. the 3d world) feels fine. And there's nothing wrong with it. You walk at normal speed. Your horse's gait seems ok. NPC characters look as if they're moving normally while going through their AI Package. The weather is not stuck and it changes as you expect.

But sometimes, you expect something to happen but it doesn't happen immediately. (E.g. the next sequence of an event that will trigger the next phase of a quest, or that a mod doesn't respond to a keypress that is bound a custom function.) But then it does. But a few seconds after you thought it wasn't going to happen. A delay of 1 to 3 seconds is ok. But a delay of more than 5 seconds could be a problem.

If so, your game may be suffering from the "Suspended stack count is over our warning threshold, dumping stacks:" process.

Dumping stacks:

"Suspended stack count is over our warning threshold, dumping stacks:" generally happens when a process (i.e. function or event - even a "set" or "get" event) from a Script fails to complete. And depending on how the Script was written, it may fail to unload itself from the game - which causes that process to be suspended as it waits to be unloaded. Unfortunately, he game will keep trying to use the Script - causing more failures to stack on top of previous failures. And the number of processes the game can suspend and stack is limited. Once that limit is reached, the game will dump it.

Sometimes the game will be able to completely dump all suspended process and your game recovers from this process. But sometimes, the game won't because the broken process is continually adding to the stack while the stack is getting dumped.

(For the player:) Recovery process
Spoiler
  • Enable Script logging in your game. (This is a blurb in the Troubleshooting section of all my mods' read-mes.)
    "To enable script logging, set bEnableLogging, bEnableTrace and bLoadDebugInformation in the Skyrim.INI file. More information about this is in this thread in the official Bethesda Creation Kit Forum: http://www.gamesas.com/topic/1345130-having-papyrus-trouble-here-are-some-things-to-try/.
  • Go into the game. Play for about 5 minutes or so - enough to generate a good amount of in-game events: e.g. fights, moving from in and out of interior cells, etc.
  • Open the Script log which is located in Documents\My Games\Skyrim\Logs\Script\Papyrus.0.log. If your game is suffering from this problem, then the file size of the log would be over 200kb. But its normal to have a Script log of more than 200kb - especially for a game with many mods that's been tried and uninstalled. Games that suffer from the "dumping stacks" problem will have Script logs that have file sizes that are 1MB or more.
  • Search for "Suspended stack count is over our warning threshold, dumping stacks:" or for "Dumping stack".
  • A dumped process looks like this:
    Spoiler

    [10/03/2013 - 12:46:53AM] Dumping stack 4194315:[10/03/2013 - 12:46:53AM]     Frame count: 2 (Page count: 2)[10/03/2013 - 12:46:53AM]     State: Waiting on other stack for return (Freeze state: Freezing)[10/03/2013 - 12:46:53AM]     Type: Normal[10/03/2013 - 12:46:53AM]     Return register: None[10/03/2013 - 12:46:53AM]     Has stack callback: No[10/03/2013 - 12:46:53AM]     Stack trace:[10/03/2013 - 12:46:53AM]         [DLC2Pillar (0301C4E4)].dlc2pillarscript.SetBuilderFactionFriendliness() - "DLC2PillarScript.psc" Line 90[10/03/2013 - 12:46:53AM]             IP: 163    Instruction: 6    Line: 90[10/03/2013 - 12:46:53AM]             [ActorToSet]: [DLC2PillarBuilderActorScript < (0301843D)>][10/03/2013 - 12:46:53AM]             [IsSleepBuildTemplate]: True[10/03/2013 - 12:46:53AM]             [::temp15]: True[10/03/2013 - 12:46:53AM]             [IsInBuilderFaction]: True[10/03/2013 - 12:46:53AM]             [::nonevar]: None[10/03/2013 - 12:46:53AM]         [ (0301843D)].DLC2PillarBuilderActorScript.OnPackageStart() - "DLC2PillarBuilderActorScript.psc" Line 18[10/03/2013 - 12:46:53AM]             IP: 172    Instruction: 5    Line: 18[10/03/2013 - 12:46:53AM]             [akNewPackage]: [Package < (03032318)>][10/03/2013 - 12:46:53AM]             [::temp1]: [Package < (02017004)>][10/03/2013 - 12:46:53AM]             [::temp2]: [Package < (02017004)>][10/03/2013 - 12:46:53AM]             [::temp3]: True[10/03/2013 - 12:46:53AM]             [::temp4]: [DLC2PillarBuilderActorScript < (0301843D)>][10/03/2013 - 12:46:53AM]             [::nonevar]: None
  • See the line "Stack trace" above? The line after that pinpoints the Script process (or function call) that's been suspended and dumped. In this example, that dumped process is "[DLC2Pillar (0301C4E4)].dlc2pillarscript.SetBuilderFactionFriendliness() - "DLC2PillarScript.psc" Line 90".

    Generally, modders tag their Script names at the beginning of the name. In this example, the Script name is "dlc2pillarscript" - which is from the Dragonborn DLC. As I previously stated, this doesn't mean that this Script caused the problem. Some other Script may have caused it and then the Dragonborn DLC was affected after. (I specifcally chose this example of a this log entry (from a Google search) because (1) I didn't want to implicate other mods and (2) I wanted to show that this problem could happen with any mod.)
  • My suggested fix for this problem is to completely deactivate and uninstall all affected mods. Scan through the log to get an idea of which mods are affected. There'll be many of those dumped processes.
    • Some mods have an uninstall process that stops it cleanly from inside the game. Try it this first. But, it will like fail because the offending Script is likely to be from the offending mod. If you were able to stop the mod from inside the game, then save the game.
    • From outside the game, deactivate and uninstall completely the mod with your mod manager. Make sure that no file that the mod uses is left in your file system.
    • Go back in the game, load your last game. And save it again. At this point, because the game could not connect data from your game to the mods that you removed, it would set the data to zero or null.

      This new save file is what I call a "clean save". Note, however, that others may argue that there is no such thing as a clean save in Skyrim. That is partly true because this file will still have all the data of the removed mods in it. All data is baked into your file. However, at this point, they are zeroed or nulled.

      Because they are zero or null, they are basically unsuable by the game. And so, I still call it a "clean save". More in the next step.

      Anyway, having zero or null data is both good and bad. Good because data from the offending Script would be disconnected from the event that was continually trying to use it. Bad because you will lose data in your game. This data would be 3d world objects or data that the mod keeps for its operation.

      Something to keep in mind...Other mods may have attached their effects on these 3d world objects. Because they are now NULL, Scripts attached to these NULL objects will fail. And depending on how those Scripts were written, their disappearance may cause another round of suspended stacks. You'll need to check the logs again after your next play-through.
    • Anyway, after the clean save, you can reinstall the offending mods and try again. It will start as if it was never installed before. Its previous data is now zero and null, and so it should start as "fresh". I don't know if the reinstalled mod will use the same physical space that its previous installation used in your saved file. I.e. your save file may or may not increase in file size. But it will definitely not decrease because data from all mods are baked into it.
    • Play from your "clean save".
    • Reinvestigate the Script log. And find more modes to uninstall. You have eventually have to uninstall all your mods to get a proper "clean save". But most times, the "suspended stacks" are cleared after the removal of only a handful of mods.
And yes, I've recovered from many "Dumping stacks" problem. I'm only in my 2nd play-through of Skyrim. My first lasted almost 18 months. And in that game, I loaded a fairly popular (back then. I don't think it is now.) "overhaul". And I played with that for a good 10 months or so. Then I decided to remove it. Because that overhaul had many Scripts attached to actors from the base game - both to unique and respawnable actors, it caused a lot of problems in quite a lot of my mods. It also affected a 3rd-party combat mod. I had to remove that as well. But, I recovered my game after the removal of the overaul. And I updated my mods as I learned how to deattach my Scripts from invalid objects.

Nowadays, I still experience the "Dumping stacks" problem. But those problems are usually caused as I edit or delete records from my ESP - to keep the ESP clean. I leaave obsolete and obsolete objects in my mod for a couple of version updates - to ensure that even if they are not used, they are still in the ESPs records. But after about two updates and when I'm sure they've been removed from the player's game world (which they generally would have been after two updates without their use), I delete them from the ESP - to keep the ESP clean.


(For the modder:) Scripting to detect invalid objects
Spoiler

When an object is removed from the game, its id is zeroed. However, I noticed, that its class isn't - if it's attached to an Alias.

For example...

Mod A is an actors mod. It adds actors to your game.

Mod B is a script mod that finds actors near the player and attaches its effects to those actors. Mod B could be doing this with several methods. The most common method is via Quests and Aliases. If a Quest requires a random target from the world, it will likely pick an actor by random and attach it to one of its Aliases.

If an actor from Mod A is attached to an Alias with a Script in Mod B, and mod A is removed, that Script from Mod B may cause the game to put in the stack as it waits to be completed. If processes in that Script are triggered with external events (e.g. an OnUpdate () process), that process will fail because the actor has become invalid. The Alias is valid because it still exists in Mod B - even if the actor attached to it is invalid. Because the Alias is valid, the OnUpdate () Event will continue to try to process itself.

The OnUpdate () process needs to detect this invalid actor, and Clear the Alias of it.

When an object is removed from the game, its id is zeroed. But its class in any Alias its occupies isn't zeroed, nulled, or set to None. It's still an Actor, Object Reference or Location.

The actor in this Alias looks like this: [Actor < (00000000)>]. The function "GetActorReference ()" returns an Actor class, "[Actor < (00000000)>]". The condition "GetReference () is Actor" will return True. But all other functions (e.g. GetFormId (), GetActorValue (), GetDistance (), etc.) will fail and will be put in the suspended stacks. So, this actor is an Actor class but is invalid because it fails all Actor and Object Reference functions.

I'm sure that a lot of Scripts use these types of conditions "If itemForm is Weapon", "If itemForm is Poison...", "If objRef is ObjectReference", "If actorRef is Actor", etc. For Scripts attached to objects of the same mod, this is sufficient.

However, for mods that attach their Scripts via Aliases to objects from other mods, this may not be sufficient.

I use GetFormId () as second condition, like this: "If itemForm is Poison && itemForm.GetFormId ()...", "If actorRef is Actor && actorRef.GetFormId ()...". This will produce a Papyrus error (that shows in logs). But at least, the condition returns as False.

Now...I don't know if the "Else" block is triggered when the game errors-out in the "If" condition. For example, in an OnUpdate () Event in a ReferenceAlias...
Event OnUpdate ()If actorRef is Actor && actorRef.GetformId ()    Debug.Trace ("ok")Else    Debug.Trace ("not ok")    self.Clear ()EndIfDebug.Trace ("If...EndIf complete.")RegisterForSingleUpdate (1)
If the example above, the game errors-out in the "actorRef.GetFormId ()" function call. Because "Else" is a part of the "If...Else...EndIf" process, the game may skip the "Else" block completely and go directly to 'Debug.Trace ("If...EndIf complete.")'. Therefore, the "self.Clear ()" will not be triggered. And so, the Script will continue to fail at "actorRef.GetformId ()" - which eventually will fill-up the stack.

So, my method is:
Event OnUpdate ()Int formId = actorRef.GetFormId ()If formId && actorRef is Actor	Debug.Trace ("ok")Else    Debug.Trace ("not ok")    self.Clear ()EndIfRegisterForSingleUpdate (1)
At least, if the game fails at "actorRef.GetFormId ()", it will continue and process the full "If...Else...EndIf" block.

Because the majority of my mods uses objects from other mods very frequently, I found that I was constantly having to check for the objects' validity. And this was the best method I found.

Examples of my mods and how objects from other mods are used:
  • Eat and sleep: In this mod, there are two food types: cooked and uncooked. The mod knows which foods from the base game are cooked. However, foods from 3rd-party mods, are all typed as uncooked. Rather than creating "compatiblity patches" for all these 3rd-party mods, I simply let the player change the food type. Foods that have changed are added to an internal array. Foods in this array will become invalid if the mods they were from are removed. Though the food may never appear in the player's inventory (because they've been removed), internally, their invalid remnants still exist in the array. Checking for their validity is essential in my mod.
  • Fight or fly: In this mod, actors will flee before their death. I have 3 sets of Aliases that actors are put into. Combatant Aliases, Fliers Aliases, and Ignoreds Aliases. Actors from any mod may be put into one of these Aliases. Checking for their validity is essential.
  • Ditto with Battle fatigue and injuries, Horse commands, Skill-based damage modifiers, Simple multiple followers, etc...
User avatar
Amanda savory
 
Posts: 3332
Joined: Mon Nov 27, 2006 10:37 am

Return to V - Skyrim