a while loop runs alot smoother than a periodic event. the whole event (signal) system creates some overhead. try if possible to avoid general events. for example if you need damage response on a certain unit give it a behaviour with damage response and use the response effect as event.
To answer the original question, yes, those still register in the game as a trigger firing, so will create a tiny amount of lag. However I think most people over-estimate just how many triggers are needed to fire at once to create noticeable lag. In my experiments you need a trigger firing at about 80 times per second before I got any performance issues and I have a pretty crappy computer
Unit property change, stay away from for sure. Because even on a single unit, it will run 20+ times per second. Things like a custom lifebar, use a loop with a wait.
Damage response isn't bad, if the return is small.
Something like floating text to show the damage a unit is taking, won't cause lag in most cases.
Unit dies isn't bad either, especially if you have conditions.
Just some random numbers
Unit takes damage, firing 50 times per second, in 6 player game, doesn't cause lag for anyone, if it is just creating floating text.
Using a periodic trigger to update a dialog very quickly (like life bars) uses about 40% more resources than using a loop with a wait.
Using action definitions with create thread checked can cause a lot of lag, if they are not used properly. The definition will be forced to wait for other uses of the object to stop.
Use the trigger debugger to figure out which options are the fastest. File preferences test windowed mode enable trigger debugger.
Behavior count can also contribute a lot to lag. 8000 behaviors in the map will create noticeable lag.
Map size, terrain deformations, complex pathing, shadows, all also contribute heavily.
Often times it is a combination of things that finally push a map to lag, not a single heavy trigger.
Using action definitions with create thread checked can cause a lot of lag, if they are not used properly. The definition will be forced to wait for other uses of the object to stop.
Can you elaborate more on threaded action definitions and their improper use? Some examples of proper scenarios and improper scenarios would be great.
I have alot of AD's in my triggers and I would like to know more about when they would cause lag waits and how to properly use them. -Thanks
Eric? Where are you eric? He would know better than me. I know of a few examples. Things I did when first learning definitions.
If you use a definition within a definition, with create flag, and have a parameter used in both, then the two definitions cannot continue in their own threads until the other thread finishes using the object. I'm not sure which one takes priority.
Another thing I personally encountered, is using acreate thread to reference something, and the action fires too frequently. Frequently enough that the next fire starts before the previous thread is complete. Same concept as above, where 2 threads are trying to change the same thing.
An easy way to think of it would be like, uhhh... A boat travelling down a channel. A new thread is a new channel, allowing more boats to travel. A single, specific boat cannot exist in two channels at the same time though.
Eric? Where are you eric? He would know better than me. I know of a few examples. Things I did when first learning definitions.
If you use a definition within a definition, with create flag, and have a parameter used in both, then the two definitions cannot continue in their own threads until the other thread finishes using the object. I'm not sure which one takes priority.
Another thing I personally encountered, is using acreate thread to reference something, and the action fires too frequently. Frequently enough that the next fire starts before the previous thread is complete. Same concept as above, where 2 threads are trying to change the same thing.
An easy way to think of it would be like, uhhh... A boat travelling down a channel. A new thread is a new channel, allowing more boats to travel. A single, specific boat cannot exist in two channels at the same time though.
You have a few misconceptions. Let me try to explain how threads work in SC2:
1. The execution of threads is deterministic. The order can be determined beforehand and thus taken advantage of. Thus, there are no race conditions which you can easily run into in powerful programming languages (Java, ...).
2. There is a thread limit. I believe it currently resides at 2048 threads. Further threads would not be created and the trigger debugger should spit out an error message. If you have a lot of triggers suddenly not working anymore (e.g. unit entering region -> order...), this can be the problem.
3. Creating threads has an overhead, some extra work that has to be done because it is more than just a function call. However, it is rather small, so you need a lot of threads to cause lag. So, instead of having 10 triggers with the identical event, you can just create a single trigger that then calls appropriate functions, for example. Else, you will have 10 threads firing and terminating after the first check.
4. The create thread action does not cause the calling thread to wait. It creates a thread which is added to the end of the thread queue of the current game loop. It will be executed after all other active threads/triggers firing of the current game update. I don't think a thread execution would ever wait on another thread due to a resource being used. Maybe you would need to use critical sections for that, but I don't know if they really serve any purpose atm. I just don't need them due to everything being deterministic.
5. Functions cannot create threads although the editor displays the flag.
Thread's order of execution (incomplete):
- You might be aware that most aspects of the game update 16 times per game second. Triggers update twice as fast: 32 times per game second.
- The order of execution can be seen as two queues: one for the first phase, one for the second phase.
- First, old threads are executed.
- Second, new threads created by trigger events firing are executed in order of appearance of the trigger in the script code. Remember, the editor puts library's code above the map script, so triggers firing in mods should always execute first.
- Waiting 0.0 seconds causes the thread to be pushed at the end of the second phase's queue. Other wait durations cause the thread to be delayed to later trigger updates causing it to be executed as an existing thread. Waiting 0.0 in the second phase just causes the thread to be executed in the next update's first phase again, similar to waiting 0.0625.
- The second phase is executed after the first phase. There might be a tiny delay, but as far as I am aware, it just executes immediately after the first phase. I never noticed a delay.
- I assume that units created by triggers in the first phase might cause triggers to fire in the second phase, e.g. entering region. I did not test this; this is just a thought.
- As you might have noticed, this order is incomplete. It reflects my current state of knowledge and it is sufficient for my style of triggering to take advantage of the order of execution. For example, I don't know how triggers waiting for other triggers to complete is executed, how new threads created by unit spawns during the first phase's triggers are handled, what critical sections do, etc.
Knowing this order is really helpful if you create a WASD movement system. You would want to delay the movement logic by 0.0 game seconds to execute it in the second trigger phase. At that moment, all button input threads fired and were executed. Thus, you properly use all button inputs and cause changes to happen before the next game update starts.
Also, the order of trigger definitions in the script can be important. For example, if a player lags, he/she is able to press a button like A down and up within the same update cycle. If your system does not handle that situation properly, you will easily get stuck in one of the modes, e.g. walking to the left because you defined releasing A before pressing A down. Btw, a proper system might keep track of the keyboard button state and try to adjust accordingly.
I'm using both of these things I mentioned in my FPS shooter engine test.
Triggers do not lag at all. The map size and the numbers of doodas/units into your map is the N1 reason of lag.
Errors in triggers can do that. Trigger can eat up FPS, which might cause a feeling of lag, if the FPS are too low. But the impact of new threads is tiny, thus Blizzard creates new threads left and right in Heroes of the Storm's triggers even when action definition calls would be sufficient.
1) SC2 does have deterministic thread ordering, in the sense that if 5 threads are started in the same game loop, they will execute in the same order each time they fire off in the same game loop. SC2 is NOT parallel, so there is a threadpool which is basically a queue. The game simply runs through the queue each game loop and executes.
2) There is blocking and non blocking thread execution, and it all revolves around thread scheduling. Threads can be delay by wait, wait is no different then normal sleeps in threads. As a result, you CAN have threads that can block other threads. Furthermore, race conditions do exist, since each trigger thread can reference a global variable and if neither thread sleeps, you can end up in an incorrect state (NOTD 1 had this issue in a few places).
When Thread A creates thread B (either from a Run Trigger action, or from an Action that is done a Create Thread), it can choose to block or not block. Now, what this really ends up meaning is that Thread A can choose to wait until Thread B completes and returns before continuing, this is blocking.
But it can also choose to only wait AS LONG AS Thread B is actually alive. This means the moment Thread B sleeps (Wait of any kind), A will resume executing.
3) Critical sections do address the issues that can arise from the above, because you can have code that sleeps an unknown amount of time. So you can easily have code in Thread A that executes, that should not wait for thread B to return, but later on, DOES need to wait for Thread B to return. Critical sections in SC2 are done as spinlocks
while(lockvariable==true){wait(1.0);}lockvariable=true;// Your codelockvariable=false;
It just spins in place (evaluates variable then sleeps) until the lock is released.
4) All of the above is bounded by the fact that the game engine itself enforces a live/deadlock detection by capping how long a thread is running and terminating a thread if it exceeds that duration (Shows as an error of "Thread XXX took too long to complete/execute". In that regard, it is almost impossible to cause a deadlock that will hang the game.
Thank you, all of you guys. That was extremely informative. I have a much stronger grasp of threading within the blizzard editor. (had to read it 3 times)
This information is crucial for interface input implementations such as WASD. For me, it helped me to conclude that my threaded AD's are at peak performance and that all wait periods and all global variable accesses are accounted for using the critical section locks.
This can also explain potential out of order executions when issuing unit commands in triggers versus issuing the orders in data.
For the scope of this thread topic, It gives detailed logic for the actual impact of triggers on game lag.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
Short question.
If you have alot of triggers, and lets say they don't meet the conditions at the top so it doesn't run, does this still create lag?
Here are some event examples I've heard of that contribute to lag....
1. any unit property changes
2. any unit dies
3. any unit takes damage from any effects
4. periodic event
If their conditions expired would they still create lag? If so, would it simply work to turn the trigger off when it has fulfilled its purpose?
a while loop runs alot smoother than a periodic event. the whole event (signal) system creates some overhead. try if possible to avoid general events. for example if you need damage response on a certain unit give it a behaviour with damage response and use the response effect as event.
@onlyleviathan: Go
To answer the original question, yes, those still register in the game as a trigger firing, so will create a tiny amount of lag. However I think most people over-estimate just how many triggers are needed to fire at once to create noticeable lag. In my experiments you need a trigger firing at about 80 times per second before I got any performance issues and I have a pretty crappy computer
<Click Here> To See My Epic Single Player Campaign (LifeForceCampaign.com)
Unit property change, stay away from for sure. Because even on a single unit, it will run 20+ times per second. Things like a custom lifebar, use a loop with a wait.
Damage response isn't bad, if the return is small. Something like floating text to show the damage a unit is taking, won't cause lag in most cases.
Unit dies isn't bad either, especially if you have conditions.
Just some random numbers Unit takes damage, firing 50 times per second, in 6 player game, doesn't cause lag for anyone, if it is just creating floating text. Using a periodic trigger to update a dialog very quickly (like life bars) uses about 40% more resources than using a loop with a wait. Using action definitions with create thread checked can cause a lot of lag, if they are not used properly. The definition will be forced to wait for other uses of the object to stop.
Use the trigger debugger to figure out which options are the fastest. File preferences test windowed mode enable trigger debugger.
Behavior count can also contribute a lot to lag. 8000 behaviors in the map will create noticeable lag.
Map size, terrain deformations, complex pathing, shadows, all also contribute heavily.
Often times it is a combination of things that finally push a map to lag, not a single heavy trigger.
Skype: [email protected] Current Project: Custom Hero Arena! US: battlenet:://starcraft/map/1/263274 EU: battlenet:://starcraft/map/2/186418
@GlornII: Go
Can you elaborate more on threaded action definitions and their improper use? Some examples of proper scenarios and improper scenarios would be great.
I have alot of AD's in my triggers and I would like to know more about when they would cause lag waits and how to properly use them. -Thanks
Eric? Where are you eric? He would know better than me. I know of a few examples. Things I did when first learning definitions.
If you use a definition within a definition, with create flag, and have a parameter used in both, then the two definitions cannot continue in their own threads until the other thread finishes using the object. I'm not sure which one takes priority.
Another thing I personally encountered, is using acreate thread to reference something, and the action fires too frequently. Frequently enough that the next fire starts before the previous thread is complete. Same concept as above, where 2 threads are trying to change the same thing.
An easy way to think of it would be like, uhhh... A boat travelling down a channel. A new thread is a new channel, allowing more boats to travel. A single, specific boat cannot exist in two channels at the same time though.
Skype: [email protected] Current Project: Custom Hero Arena! US: battlenet:://starcraft/map/1/263274 EU: battlenet:://starcraft/map/2/186418
Triggers do not lag at all. The map size and the numbers of doodas/units into your map is the N1 reason of lag.
You have a few misconceptions. Let me try to explain how threads work in SC2:
1. The execution of threads is deterministic. The order can be determined beforehand and thus taken advantage of. Thus, there are no race conditions which you can easily run into in powerful programming languages (Java, ...).
2. There is a thread limit. I believe it currently resides at 2048 threads. Further threads would not be created and the trigger debugger should spit out an error message. If you have a lot of triggers suddenly not working anymore (e.g. unit entering region -> order...), this can be the problem.
3. Creating threads has an overhead, some extra work that has to be done because it is more than just a function call. However, it is rather small, so you need a lot of threads to cause lag. So, instead of having 10 triggers with the identical event, you can just create a single trigger that then calls appropriate functions, for example. Else, you will have 10 threads firing and terminating after the first check.
4. The create thread action does not cause the calling thread to wait. It creates a thread which is added to the end of the thread queue of the current game loop. It will be executed after all other active threads/triggers firing of the current game update. I don't think a thread execution would ever wait on another thread due to a resource being used. Maybe you would need to use critical sections for that, but I don't know if they really serve any purpose atm. I just don't need them due to everything being deterministic.
5. Functions cannot create threads although the editor displays the flag.
Thread's order of execution (incomplete):
- You might be aware that most aspects of the game update 16 times per game second. Triggers update twice as fast: 32 times per game second.
- The order of execution can be seen as two queues: one for the first phase, one for the second phase.
- First, old threads are executed.
- Second, new threads created by trigger events firing are executed in order of appearance of the trigger in the script code. Remember, the editor puts library's code above the map script, so triggers firing in mods should always execute first.
- Waiting 0.0 seconds causes the thread to be pushed at the end of the second phase's queue. Other wait durations cause the thread to be delayed to later trigger updates causing it to be executed as an existing thread. Waiting 0.0 in the second phase just causes the thread to be executed in the next update's first phase again, similar to waiting 0.0625.
- The second phase is executed after the first phase. There might be a tiny delay, but as far as I am aware, it just executes immediately after the first phase. I never noticed a delay.
- I assume that units created by triggers in the first phase might cause triggers to fire in the second phase, e.g. entering region. I did not test this; this is just a thought.
- As you might have noticed, this order is incomplete. It reflects my current state of knowledge and it is sufficient for my style of triggering to take advantage of the order of execution. For example, I don't know how triggers waiting for other triggers to complete is executed, how new threads created by unit spawns during the first phase's triggers are handled, what critical sections do, etc.
Knowing this order is really helpful if you create a WASD movement system. You would want to delay the movement logic by 0.0 game seconds to execute it in the second trigger phase. At that moment, all button input threads fired and were executed. Thus, you properly use all button inputs and cause changes to happen before the next game update starts.
Also, the order of trigger definitions in the script can be important. For example, if a player lags, he/she is able to press a button like A down and up within the same update cycle. If your system does not handle that situation properly, you will easily get stuck in one of the modes, e.g. walking to the left because you defined releasing A before pressing A down. Btw, a proper system might keep track of the keyboard button state and try to adjust accordingly.
I'm using both of these things I mentioned in my FPS shooter engine test.
Errors in triggers can do that. Trigger can eat up FPS, which might cause a feeling of lag, if the FPS are too low. But the impact of new threads is tiny, thus Blizzard creates new threads left and right in Heroes of the Storm's triggers even when action definition calls would be sufficient.
Few additions to what Ahli wrote
1) SC2 does have deterministic thread ordering, in the sense that if 5 threads are started in the same game loop, they will execute in the same order each time they fire off in the same game loop. SC2 is NOT parallel, so there is a threadpool which is basically a queue. The game simply runs through the queue each game loop and executes.
2) There is blocking and non blocking thread execution, and it all revolves around thread scheduling. Threads can be delay by wait, wait is no different then normal sleeps in threads. As a result, you CAN have threads that can block other threads. Furthermore, race conditions do exist, since each trigger thread can reference a global variable and if neither thread sleeps, you can end up in an incorrect state (NOTD 1 had this issue in a few places).
When Thread A creates thread B (either from a Run Trigger action, or from an Action that is done a Create Thread), it can choose to block or not block. Now, what this really ends up meaning is that Thread A can choose to wait until Thread B completes and returns before continuing, this is blocking.
But it can also choose to only wait AS LONG AS Thread B is actually alive. This means the moment Thread B sleeps (Wait of any kind), A will resume executing.
3) Critical sections do address the issues that can arise from the above, because you can have code that sleeps an unknown amount of time. So you can easily have code in Thread A that executes, that should not wait for thread B to return, but later on, DOES need to wait for Thread B to return. Critical sections in SC2 are done as spinlocks
It just spins in place (evaluates variable then sleeps) until the lock is released.
4) All of the above is bounded by the fact that the game engine itself enforces a live/deadlock detection by capping how long a thread is running and terminating a thread if it exceeds that duration (Shows as an error of "Thread XXX took too long to complete/execute". In that regard, it is almost impossible to cause a deadlock that will hang the game.
Thank you, all of you guys. That was extremely informative. I have a much stronger grasp of threading within the blizzard editor. (had to read it 3 times)
This information is crucial for interface input implementations such as WASD. For me, it helped me to conclude that my threaded AD's are at peak performance and that all wait periods and all global variable accesses are accounted for using the critical section locks.
This can also explain potential out of order executions when issuing unit commands in triggers versus issuing the orders in data.
For the scope of this thread topic, It gives detailed logic for the actual impact of triggers on game lag.