HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Why are loops so much slower than repeated trigger executions?

05-24-2004, 10:04 AM#1
PitzerMike
Two versions of the same code. First one:

Code:
function Blah takes some arguments returns nothing
loop
  do some angle math
  move unit to polar offset, blah blah
  call TriggerSleepAction(0.01)
endloop
endfunction


Second one:

Code:
function Blah takes nothing returns nothing
do some angle math
move unit to polar offset, blah blah
call TriggerSleepAction(0.01)
call TriggerExecute(GetTriggeringTrigger())
endfunction

function InitBlah takes nothing returns nothing
local trigger T = CreateTrigger()
call TriggerAddAction(T,function Blah)
call TriggerExecute(T)
endfunction


As you can see the first one runs a loop, and the second one constantly keeps executing the same trigger when finished. Both use the same wait delay. Why is it that the first version (with the loop) is so damn slow that you can watch the unit move instantly from one spot to the next. And the second version creates a fluid movement?

I could use the second version, I know, but as you see it requires many global variables, as I can't pass any arguments through the fuction's interface. (I also don't want to use game cache for good reasons)

Any suggestions how I could solve that prob?
05-24-2004, 12:19 PM#2
The Gearhead
Calling a wait in a loop causes a huge delay, multiple times what you type it as.
05-24-2004, 01:58 PM#3
Cubasis
Nah,

This is a known issue, TriggerSleepAction just simply has a minimum wait of about ~0.25 seconds. Try it out for yourself, it's horribly silly. It's argued what the minimum is, and if one can do different abuses to it like Sleeping(0) (is rumored to sleep less than 0.25).

When I tested it once, I couldn't though get it any lower than ~0.25 seconds. However Lord Vexorian spoke about ~0.04 ... depending on game-speed.

So basicly, TriggerSleepActions are in-reliable when doing this kind of stuff, sadly. So, periodic timers are the way to go. I have though yet to notice a apparent slowdown using GameCache to store up to 5 parameters each time.

~Cubasis
05-24-2004, 02:24 PM#4
PitzerMike
Quote:
Originally Posted by The Gearhead
Calling a wait in a loop causes a huge delay, multiple times what you type it as.

Yeah, that's what I already stated. The question is why it causes such a huge delay and doesn't cause that delay in a repetitive trigger.


Cubasis: It's not about TriggerSleepAction. If you look at the second piece of code I've posted, it also uses the same TriggerSleepAction. The question is why it sleeps much longer in a loop than in a trigger that keeps executing itself.
05-24-2004, 03:21 PM#5
Cubasis
Oh wait .,... sorry, I misread.

This is indeed really wierd/interesting.

*goes to test*

~Cubasis
05-24-2004, 09:06 PM#6
The Gearhead
I believe its simply an attribute of loops. A painful, horrible, crappy attribute of loops.

It pisses us all off.


It might have to do with the fact that loops have a specific time-out value which, if exceeded, will cause the function to cease. You can prevent time-out by forcing a wait, which may be why it lasts so long.
05-24-2004, 10:26 PM#7
Cubasis
Gearhead, that limit is not related to loops. It's a internal system which counts the number of expressions you do. So you could loop only 100 times, calling some giant trigger every time and still meet the limit.

~Cubasis
05-24-2004, 10:39 PM#8
AIAndy
It might be that the thread system has priorities for each thread. If it awakens too often in short time, it gets lower priority so it indirectly sleeps longer which causes the perceived minimum sleep.
The trigger that repeatedly executes itself creates new threads each time so it does not run into that problem because each thread only sleeps and awakens once.
05-24-2004, 10:49 PM#9
Vexorian
Quote:
Originally Posted by AIAndy
It might be that the thread system has priorities for each thread. If it awakens too often in short time, it gets lower priority so it indirectly sleeps longer which causes the perceived minimum sleep.
The trigger that repeatedly executes itself creates new threads each time so it does not run into that problem because each thread only sleeps and awakens once.
I am sure it is about threads somehow
05-25-2004, 11:20 AM#10
PitzerMike
Quote:
Originally Posted by AIAndy
It might be that the thread system has priorities for each thread. If it awakens too often in short time, it gets lower priority so it indirectly sleeps longer which causes the perceived minimum sleep.
The trigger that repeatedly executes itself creates new threads each time so it does not run into that problem because each thread only sleeps and awakens once.

Interesting theory, seems logical...
I'll go test the same problem with a trigger that has a periodic event of 0.01 seconds. My guess is that this will be as slow as the loop.
05-25-2004, 12:34 PM#11
The Gearhead
Wouldn't the event call a new thread, but the same code?
05-25-2004, 01:32 PM#12
AIAndy
Exactly, it needs to start a new thread each time an event fires because you can sleep a thread and in the meantime the same trigger is run again and so you now have two threads of the same trigger.
So the timed event works fine and without slowdown.
05-25-2004, 11:05 PM#13
The Gearhead
Yeah, so its just the whole sleep-awaken thing that causes it to slow down.

That's really unfortunate, because it really slows down my SHA-1 and Rijndael code, waits are necessary due to the number of operations performed over and over.

Edit:
Would calling a function which had a wait, such as:
Code:
function Waiterizer takes real Duration returns nothing
	call TriggerSleepAction( Duration )
endfunction
Would that provide the necessary delay, and would it prevent the trigger from timing out after so many evaluations?
05-26-2004, 11:07 AM#14
AIAndy
No, that would not change anything.
The only way you could accelerate your computations is to actually use multiple threads.
05-26-2004, 10:45 PM#15
The Gearhead
Damn... such as:

Code:
Function SHAmain takes string Input returns string Output
	local integer i = 0
	local integer array K
	local integer array W
	set Input = AppendString(Input)
	loop
		exitwhen i == 16
		set W[i] = Bin2Hex(SubString(Input,i*32,i*32+32)))
		set i = i + 1
	endloop
	set i = 16
	loop
		exitwhen i == 80
		set W[i] = [b]Bitmixing[/b](W[i-16],W[i-14],W[i-8],W[i-3],i)

So, by using Bitmixing instead of:
Code:
			loop
				exitwhen i == 80
				set W[i] = ROTATE(XORBIN(W[i-16],XORBIN(W[i-14],XORBIN(W[i-8],W[i-3]))),1)
				set i = i + 1
				if( ModuloInteger(i,16) == 0 ) then
					call TriggerSleepAction( 0.001 )
				endif
			endloop

I would be more efficient, by starting a seperate thread which would return the value?

If so, that'd be remarkable. But I have an inkling that when you return something, and when you call something, it counts the evaluations differently. When I call say, "Waiterizer" it isnt counting its evaluations, and it also isnt waiting for it to finish (to return a value). So when I call it, it doesnt matter how inefficient it is because its completely seperate. But when I make it return a value, it counts the evaluations within the function I call for a return value.

Is this correct?