System Key Timers 2

Jesus4Lyf

Good Idea™
Reaction score
397
Why not just forbid silly periods like 0.05177?
I mean if some deranged mind needs something like that he can use some other sys.
Or 0.03125?
That's my dilemmar though, for a very slight overhead I can remove the rest of the restrictions.

I'm starting to really like 800 resolution though. 0.03125 is a good, valid period, after all, and it allows a granularity of 0.00125 and a maximum of 10.23875. I think I should change that, regardless, perhaps. But I also think that perhaps you're right, and I should simply disallow periods that don't have a granularity of 0.00125. Or above 10.23875. To encourage multi-instancing.

It's just a few people roared about there being too many constraints on the period, and I've removed half but could remove all of them! :p

Actually, if periods get more retarded than 0.00125 they're probably better off with another system anyway... Not that it matters. o.o
 

Cohadar

master of fugue
Reaction score
209
Actually, if periods get more retarded than 0.00125 they're probably better off with another system anyway... Not that it matters. o.o

If they get more retarded than that they need a doc. :D

As far as I can remember the only periods I ever used were:
0.03125
0.04
0.1
0.25
1.0
 

Jesus4Lyf

Good Idea™
Reaction score
397
Yeah. I agree.

I agree that KT2 should support 0.03125 for the period. That's what I'd like to use. So next version I need to add safety and make the resolution 800 (still hard coded).
No hash.

So restrictions will be 0.00125 granularity, and under 10.24 for the period. :)

And did you agree with not using a pivot-pointer for efficiency? I'd like to know that I understood you correctly.
 

Cohadar

master of fugue
Reaction score
209
I have read your Timer Systems in Wc3 document and I have some comments.

First impression was you suck at writing documentation:
Too big font, no distinct paragraph separation.

>> Structs are integers. Period.
Yes, but more importantly structs are array indexes.

>>Why have 3 timers going in the background when you can have 1?
Because sometimes it is more efficient. :eek:

>>Section 2.3 Multi-Instance Timers
You should have explained what do you mean by multi-instance timers before jumping into discussion.
Section is also too abstract, there are no examples.

>>Trigger Execute Count attachment
Ok you made this long ago, but it proved to be a bad idea, so why mention it when it is not relevant to the topic?

>> H2I attachment
Again no explanation. Don't just assume people have studied every possible timer system.

Start function comparision:
So, from fastest to slowest…
Key Timers 1
Without a shadow of a doubt, the fastest, at 1.3 microseconds.
Timer Ticker
A distant second at 5.9 microseconds (+354% execution time).
Key Timers 2
A close third at 6.5 microseconds (+10% execution time on TT).
ABCT
A fourth. I assume hashing has slowed it down, and I may revisit this to fiddle with constants, but there was no documentation to suggest I should do this. Using the package straight out of the box, the average time for creating each of 4,000 instances was ~160 microseconds (+2362% on KT2).

This is not a valid test concerning ABCT because preload limit is set to 128 by default.
If you had set the PRELOAD constant to 4000 (or measured the executions after first init) it would be as fast as others.
ABCT_Start is only slow "on the first cast"

Besides start functions are irrelevant for the overall performance of the system, I am surprised you even bothered to test this.

Executions per second (main loop speed/GetData speed)
This test demonstrates how fast the timer is in action. The test is as stated at the start of this chapter. The executions in 10 seconds have been counted (using 100 instances of a single period), then divided by 10 to give a fairly consistent results with a fairly low margin of error. I have executed the test about 5-10 times again, taking the average.
From fastest to slowest…
Key Timers 1
Without a doubt the fastest again, with 59,300 executions per second.
Key Timers 2
This surprised me. I’ve made some unconventional optimizations on this system when I recently upgraded it, and they seem to have payed off. This system averaged 31,500 executions per second. About half the speed of KT1.
Timer Ticker
This is why KT2 surprised me. This was only technically slower, at 31,400 executions per second. This is an 0.5% difference, so I consider this to be the same speed as KT2.
ABCT
18,800 executions per second. 31% the speed of KT1, and 60% the speed of KT2/TT. Proof that multi-instance timer systems are more efficient.

Firstly you cannot test KT1 with others because it is not a timer system.
It is an external macro, so it appears faster when you have only one instance of it. If you made for example 20 spells with KT1 it's performance would get down because it would create 20 timers.

Secondly why the hell you were surprised by 0.5% (half percent) difference between TT and KT2?
They both use TriggerEvaluate and the other stuff is just minor numeric manipulation, so I expected them to be exactly the same.
So I guess now we know the measure of your personal bias - 0.5% :D
Not bad at all.

Thirdly ABCT is a low-frequency sys, it was not supposed to be tested with others (not the same category)
Nonetheless 18,800/31,400 ~60% of TT is quite good score for low-frequency timer. I was pleasantly surprised, I thought it was slower.

Then you have a benchmark with some other systems:
Key Timers 2
32,000
TimerUtils Red
30,100
TimerUtils Blue
26,500
HSAS (used on timer)
24,800
I Swear it’s the Fastest!
31,400

Again HSAS does not belong here for the same reason as KT1, it is not a timer system.
It is external macro and it gives a false impresion of good performance with one instance and degrades if you make more spells with it.

Timer utils red was a big disappointment, I expected it to be faster considering how unsafe it is.

In the end of your document you made some conclusions about which timer systems are "best" which I will not repeat here because it is not true.

And it is not true because you only tested speed and "forgot" about two other aspects: safety and ease of use
(And it is a common fact my systems beat all others when it comes to those two categories)

If I were to make ordered list of "best" systems it would look quite different.
But I am not going to do that because some of them are mine (and I am by definition prone to be biased).

So the only list I would believe in would be some made by a jury of 10 jass experts where non of them are system makers.
On the other hand system popularity is a good judge by itself.
 

Viikuna

No Marlo no game.
Reaction score
265
On the other hand system popularity is a good judge by itself

I always loved TT because it was so easy to use. Then I developed this habbit of using struct arrays + one timer per spell, or TimerStack in some cases.


Is there still KeyTimers1 code here in somewhere?
 

Cohadar

master of fugue
Reaction score
209
I always loved TT because it was so easy to use. Then I developed this habbit of using struct arrays + one timer per spell, or TimerStack in some cases.

So you like to do things the harder way and make them less efficient?
(struct arrays are slower than TT if you have more than 20 triggered spell.)
((because than you have 20 different timers...))
 

Romek

Super Moderator
Reaction score
963
> So you like to do things the harder way and make them less efficient?
I don't think it's less efficient. It's easier to implement anyway...

> ((because than you have 20 different timers...))
With TT, you'll have even more trigger handles than that.

Personally, I think they're about as good/bad as eachother. It's either a lot of timers or triggers, though I think you'll end up with more triggers with TT than you would timers with a Timer per spell. TT is easier to use, Timer per spell is easier to implement.
In the end, it's just personal preference.
 

Cohadar

master of fugue
Reaction score
209
> So you like to do things the harder way and make them less efficient?
I don't think it's less efficient. It's easier to implement anyway...

> ((because than you have 20 different timers...))
With TT, you'll have even more trigger handles than that.
Handle count does not affect performance.
It is the number of timers running simultaneously.

Personal preference.... well I guess everyone has a right to be a masohist.
 

Romek

Super Moderator
Reaction score
963
> Handle count does not affect performance. It is the number of timers running simultaneously.
I'm sure having 20+ triggers being evaluated every 0.03125 seconds is going to affect the performance just as much as 20 timers running simutaniously.
Though if there are 20 instances of Spell A, there's still only 1 timer being ran in the Timer/Spell method; there would still be 20 triggers being evaluated using TT though.

I don't know exactly what is faster or more efficient, more timers, or loads of triggers.
Regardless, there would probably be more triggers than timers.
 

Viikuna

No Marlo no game.
Reaction score
265
Well, Cohadar is kinda right.

We should only use one timer per period. At least for fast period timers.
 

Cohadar

master of fugue
Reaction score
209
I'm sure having 20+ triggers being evaluated every 0.03125 seconds is going to affect the performance just as much as 20 timers running simutaniously.
Oh really and why are you so sure?

Though if there are 20 instances of Spell A, there's still only 1 timer being ran in the Timer/Spell method; there would still be 20 triggers being evaluated using TT though.
Yes there would be 20 triggers being evaluated agains 20 timers being also evaluated
The only difference being that 20 timers will spend more time ordering themselves into global timer heap

I don't know exactly what is faster or more efficient, more timers, or loads of triggers.
I just told you.

Regardless, there would probably be more triggers than timers.
Really, and again how do you know that?

My guess is there will be the exact same number,
maybe because the fact that I am not guessing...
 

Romek

Super Moderator
Reaction score
963
> Oh really and why are you so sure?
I'm not sure at all. It's a logical guess though.

> My guess is there will be the exact same number,
There'll always be at least the same amount of triggers as timers.
If there are 20 spells, each with 1 instance, there'll be 20 triggers, and 20 timers running.
If only 10 of those spells are running, then 10 of the timers will be paused.
However, if each of the spells have 2 active instances, there'll be 40 triggers, and still 20 timers.

Have you got any benchmarks or some sort of data that will prove either of us wrong?
 

Cohadar

master of fugue
Reaction score
209
> Oh really and why are you so sure?
I'm not sure at all. It's a logical guess though.

> My guess is there will be the exact same number,
There'll always be at least the same amount of triggers as timers.
If there are 20 spells, each with 1 instance, there'll be 20 triggers, and 20 timers running.
If only 10 of those spells are running, then 10 of the timers will be paused.
However, if each of the spells have 2 active instances, there'll be 40 triggers, and still 20 timers.

Have you got any benchmarks or some sort of data that will prove either of us wrong?

Ah I see what is the confusion now.
You were assuming TT_StartEx was compared against struct arrays.
(Why would you assume that?)

Well, Cohadar is kinda right.

We should only use one timer per period. At least for fast period timers.



Struct arrays can only be used for small periods so it is natural to compare them with TT_Start.

Don't mix dogs and frogs (or something like that...)

PS: There are no triggers running in TT.

EDIT:
Omg Jesus4Lyf I'm sorry we hijacked your thread.
(althou previous discussion can as well be applied to KT2)
 

Romek

Super Moderator
Reaction score
963
I was comparing a timer/spell to the old TT functions.
The one-timer-for-everything. Nothing to do with the ABCT stuff.

In those examples, the timers I was referring to are from using a timer per spell.
The triggers are for the TT stuff.

> PS: There are no triggers running in TT.
Evaluating triggers. Still not to be ignored.
 

Cohadar

master of fugue
Reaction score
209
I was comparing a timer/spell to the old TT functions.
The one-timer-for-everything. Nothing to do with the ABCT stuff.

In those examples, the timers I was referring to are from using a timer per spell.
The triggers are for the TT stuff.

> PS: There are no triggers running in TT.
Evaluating triggers. Still not to be ignored.

and before that...
However, if each of the spells have 2 active instances, there'll be 40 triggers, and still 20 timers.
I should have read your previous post more carefully.
Yes there will be 40 timers, but those timers are not created for every instance, they are preloaded.

So there will be 40 TriggerEvaluate calls vs 20 timers x 2 loops per instance.
So yes in that case TT would not be in advantage any more.

TriggerEvaluate might seem like a scary and time consuming but it really is not,
it is a simple function call through a pointer

JASS:

//pseudocode
native TriggerEvaluate takes trigger whichTrigger returns boolean
    return whichTrigger.condition
endnative


it is TriggerExecute that is heavy:
JASS:

//pseudocode
native TriggerExecute takes trigger whichTrigger returns nothing
    call CreateNewThread(whichTrigger.action)
endnative

And I don't use any of those.

So the question is do you really want to spend time coding 20 spells the hard way for a small performance benefit (maybe)
 

Romek

Super Moderator
Reaction score
963
> Yes there will be 40 timers, but those timers are not created for every instance, they are preloaded.
20 timers. :)

> So yes in that case TT would not be in advantage any more.
It seems that way in most cases. Though a timer per spell isn't at an advantage either.
Which brings me back to the point of personal preference.
And whether ease of use is more important than being system independent.

> it is a simple function call through a pointer
The other method doesn't use function calls to run the actions though.

> So the question is do you really want to spend time coding 20 spells the hard way for a small performance benefit (maybe)
I don't even think there's a performance boost. :p
 

Jesus4Lyf

Good Idea™
Reaction score
397
Haha... Yea nice thread-jack, but that's ok. Actually, when I posted the documentation, I wanted it to have it's own thread as it's own resource, for reasons like this, but Daxtreme said I should put it in here anyway. So I did.

Anyway... Romek is right when talking about struct/stack loops in that if you have 5 spells each running with 4 instances, all on the same period, TT gives 1 timer, 20 triggers and a struct/stack loop or KT1 gives 5 timers and 0 triggers. As to which is faster, I haven't bench tested. I'm thinking maybe I should! :)

Cohadar is right in regards to TriggerEvaluate being faster than a timer thread. The bench tests for KT2 proove this. So if you have 50 timers vs 1 timer and 50 triggers, 1 timer and 50 triggers wins out fairly easily, by about the margin that KT2 beats TU red, depending on your timer system. :)

It's all in the documentation! ;)

About which...

Cohadar, firstly, your comments are great, and I agree with you on virtually all of them.

>Secondly why the hell you were surprised by 0.5% (half percent) difference between TT and KT2?
I was suprised because it was in favour of KT2. TT should be faster, because it does less. I assume you have a couple of optimizations you could make.

>Firstly you cannot test KT1 with others because it is not a timer system.
Eh. I know what you mean, but I use it all the time as one, basically.
In fact, it sets some sort of contex for what the fastest possible solution is.

>They both use TriggerEvaluate and the other stuff is just minor numeric manipulation, so I expected them to be exactly the same.
Hehe... But KT2 cuts out a bit of what TT does. I never understood why you set a global to the data in the array and then returned that for GetData, for example. You may find the 0.5% is legitimate.

>Timer utils red was a big disappointment, I expected it to be faster considering how unsafe it is.
Ha! Well... It can't be faster. KT2 is faster than raw H2I when you stack up on periods. :)
Actually, TU Red it only has a 4% overhead on raw H2I, which is pretty good for a timer sys I'd say. :)

>And it is not true because you only tested speed and "forgot" about two other aspects: safety and ease of use
Yeah. I would probably swap in ABCT instead of TU Red fairly comfortably there, for those reasons. But KT2 is now very stable, and extremely easy to use. For making timed effects in spells, which is what it was designed for, I'd say fairly comfortably IMO that it's the best. And I'd say I have substantial evidence. :shades:

>So the only list I would believe in would be some made by a jury of 10 jass experts where non of them are system makers.
>On the other hand system popularity is a good judge by itself.
Yeah, agreed there. XD

The reason for the documentation, by the way, is that I thought KT2 was the best, and I wanted to see if I was right before I got shot down by others. The documentation is documentation of my comparisons between KT2 and everything else, and explanations of my logic as to what led me to make it in the first place.

It wasn't really written for end users. They can read the comments at the top of the code. It was written for people like yourself, or other inquisitive JASSers, to convey some reasoning and evidence behind my claims, and how I came to them. :D

Is there still KeyTimers1 code here in somewhere?
Yes. I'm pretty sure it's on the first page, as one of the downloads. If not though, or you want more details on using KT1, might as well post here and I'll let you know. KT1, lol, at the end of the day, is the system I still use. But I'd like to test it against KT2 for running 10 spells at one instance each on one period. KT2 may be faster.
 

Jesus4Lyf

Good Idea™
Reaction score
397
So you like to do things the harder way and make them less efficient?
(struct arrays are slower than TT if you have more than 20 triggered spell.)
((because than you have 20 different timers...))

Question of the day: How right is this?

That's what I've been wondering.

Firstly, when I say spells, I mean timed effects in general. Just these are usually spells, in my mind.

There is one timer per spell type (example: One for flamestrike, one for blizzard, even if they have the same period - and if these were custom spells).

Compared to:

KT2 (or multi-instancing timer systems in general, such as TT). There is one timer per period (although KT2 is the only system to date that actually can do more than one period dynamically and efficiently at run-time, so I'll simply say KT2) even if there are different spells using the period.

So the conclusion is if a spell is only cast once at a time, it is basically the same as attaching to timers in speed. Only when the spell is cast several times at once does it become worthwhile to use KT1 or a struct stack over KT2 or a multi-instancing timer system.

How right is this and at what point is the switch in efficiency? I bench tested KT1, KT2 and TU Red to draw some reasonable conclusions. My test, in effect, was to use 1 instance per 1, 2, 3, 4, 5, 10, 20, 30 different spells running concurrently, and count the executions per second. Then I repeated the test with 3 instances each, per 1, 5, 10, 20 different spells running concurrently. Obviously to KT2 and TU red, the different spells factor is irrelevant, and only the total number of instances is considered.

I can't be bothered formally documenting this, this time, because really I did the tests for myself to see if I should switch from KT1 to KT2 in my maps. But for interests' sake, here's the outcome...

  • KT1 or a struct/stack is slower than TU Red for only 1 instance per spell (+10% speed).
  • After 4-5 different spells, the number of spells becomes completely irrelevant to these systems.
  • KT1 or a struct/stack operates on my computer at 28,100 executions per second for 1 instance.
  • TU Red operates on my computer at 30,800 executions per second for 1 instance.
  • For more than one instance, KT1 or a struct stack is SUDDENLY faster. By a lot. For 3 instances, TU Red was still 30,800 executions per second while KT1 was 43,100 executions per second (+40% speed).
  • For one instance, KT2 is slower than both before 5 different spells (which is actually an unreliable test) by about 4%.
  • At 5 different spells, KT2 meets the speed of KT1 (approximately 1% slower).
I haven't compared KT2 and TU Red there because to them the number of spells is irrelevant. However, comparing these systems on a period of 0.0 for irrelevant interest's sake... Before 15 instances, TU Red is faster, and after 15 instances, KT2 is faster. We knew that for 100 instances KT2 was faster, but now you know that even on a low number of instances KT2 is faster. (Lower than that, who cares anyway.)

So yeah. Answering Cohadar's statement. Is that a fact?

Actually, a struct/stack loop is only slower if there is only 1 instance going. Otherwise it's faster than everything. Basically regardless of how many different spells are actually going.

Now for generic hero abilities on an AoS, usually there are 0 instances, and 1 max, perhaps 2 (of each spell). For this, a system that agregates over period rather than a struct/stack loop is the best answer, as all the spells can be clustered together.

Consider that spells may also have more than one timed effect. For example, Sharl has up one timed effect for every spark spawned.

PS. To clarify, that switch is definitely not at 20 different timed effects. It's at whether or not each timed effect has more than one instance going at once. :)

If people really really care, they can PM me for the full results. Or something.

And that's your bench test for the day. :)
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top