I don't understand busy modes of a timer object

13 vues (au cours des 30 derniers jours)
David Szwer
David Szwer le 8 Fév 2023
TL;DR: What is the difference between timers using the BusyMode options drop and queue, and the ExecutionMode options fixedDelay and fixedRate? Different parts of the documentation seem to say different things.
I am trying to understand the details of how the timer object works, but am having trouble. I am using the timer help page, and the more detailed article "Handling Timer Queuing Conflicts".
I understand that ExecutionMode="fixedSpacing" effectively adds the execution time of the timer callback to the timer period*, which also means that the callback can never be called while the callback is running. I also understand that when ExecutionMode="fixedRate", I need to use BusyMode to prevent callbacks colliding, and that I can use BusyMode="error" to throw an error (or take another action) if that would happen.
However, I am confused by the other two BusyModes, drop and queue, and how they compare to ExecutionMode="fixedDelay".
The timer help page says that BusyMode="drop" will "drop" the new task "when a timer has to execute TimerFcn before the completion of previous execution of the TimerFcn" and that "skipping of TimerFcn calls" is possible. To me, this suggests that an instance of TimerFcn will be skipped and that the timer period immediately begins afresh.
In contrast, BusyMode="queue" will "wait for [the execution] queue to clear, and then enter task in queue", and "adjusts Period property to manage tasks in execution queue". To me, this suggests that the new TimerFcn will start as soon as the old one finishes, and that it will increase its period (perhaps hidden from the user) to avoid having too many instances of TimerFcn in the queue.
When I look at the "Handling Timer Queuing Conflicts" article for more information, however, it gives an example where drop and queue behave identically! Both examples set a timer to run five times, with period 1s and a timer function that takes 1.6s to run. What I expect: when BusyMode="queue", the timer callback occurs every 1.6s; when BusyMode="drop", the timer callback occurs every 2s (the odd-numbered tasks being dropped, because the callback is running). What actually happens: in both cases, the timer callback occurs every 1.6s. This isn't just a bug in my version of Matlab - the actual article has a table describing what should happen, and although a few of the internal details are different, it clearly shows TimerFcn being started every 1.6s (+ queue lag). The description of what happens within the timer doesn't help all that much, since there are some details that I am sure must be mistakes (e.g. for drop, the 4th and 5th calls of the timer function are dropped twice each).
About ExecutionMode="fixedDelay", the timer help page says that the timer period starts "when the timer function callback restarts execution after a time lag due to delays in the MATLAB execution queue" (contrasting with "immediately after the timer callback function is added to the MATLAB execution queue" for ExecutionMode="fixedRate"). I would take this description to mean that fixedDelay works much like fixedRate, except that the timing is less precise because fixedDelay includes an unknown amount of queue delay. However, in the BusyMode section, the page also says, "for other values of ExecutionMode [other than fixedRate], there cannot be overlapping attempts to execute the timer callback function because the delay between executions is always relative to the completion of the previous execution". I don't see how this can be true unless Matlab deliberately adjusts the queue lag to make this happen. Even more confusingly, the diagram actually shows fixedDelay's timer function starting just before the previous call finishing (although it is so close that I'm sure that wasn't intentional). When I test fixedDelay, it seems to operate identically to the fixedRate tests described above (within a few milliseconds for the queue lag). I have attached those demos to this file (run testTimers.m to demonstrate them, first with a period less than the timer function time; then with a period greater than the timer function time).
I may just have completely missed something completely obvious, but I would very much welcome enlightenment!
*Although some aspects of fixedSpacing do still puzzle me!
  4 commentaires
Pascal Brunner
Pascal Brunner le 19 Mai 2023
Modifié(e) : Pascal Brunner le 19 Mai 2023
David, thank you for summarizing your questions in this post. I've stumbled upon the same issues understanding the differences in queueing, and for the different execution modes.
A (partial) summary of the post for @Jan from my side would be: Why does queueing only become important for the fixedRate execution mode? What happens in fixedDelay mode, if the time of Period + Queue Lag is shorter than the execution time of TimerFcn? In this case, shouldn't there also occur timer queueing conflicts, which have to be addressed by specifying the BusyMode behavior?
Thank you for your help,
Pascal
David Young
David Young le 21 Fév 2024
There is still a significant issue here. The documentation page "Handling Timer Queuing Conflicts" (link in the original question) has tables showing the same behaviour for "drop" and "queue" - and the examples, when run, confirm that the two options do behave the same. In addition, the behaviour of the "drop" option does not correspond to this statement on the page "If the execution queue is not empty, the timer object skips the execution of the callback." But it doesn't, it queues it!
So the question is: is there a bug in timer, or is there something about the "drop" options that just isn't well explained? How does it actually differ from "queue", and how is it supposed to differ from "queue"?

Connectez-vous pour commenter.

Réponses (2)

Sarthak
Sarthak le 23 Mar 2023
Hi David,
As per my understanding, the BusyMode option controls what happens if a timer's task takes longer to execute than the timer interval. If BusyMode is set to "drop", the timer will drop any pending tasks if the previous task has not yet completed. If BusyMode is set to "queue", the timer will queue any pending tasks and wait for the previous task to complete before executing the pending task(s).
On the other hand, the ExecutionMode option controls how the timer schedules its tasks. If ExecutionMode is set to "fixedDelay", the timer will execute its task at a fixed interval after the previous task has completed. If ExecutionMode is set to "fixedRate", the timer will execute its task at a fixed rate, regardless of how long the previous task took to execute.
And as far as the example in Handling Timer Queuing Conflicts is concerned, we are creating a timer with a period of 1 second, but a callback that requires atleast 1.6 seconds.
  2 commentaires
David Szwer
David Szwer le 23 Mar 2023
Thank you, you have summarised what I think should be true based on the basic documentation. However, this answer doesn't address my specific concerns.
Regarding BusyMode="drop" and "queue", the example shows both modes behaving the same - firing the TimerFcn every 1.6 seconds. If this is intended, why do we need two different modes? Surely the point of "drop" is that we would get TimerFcn at 0s, 2s, 4s, etc., with the odd numbers being dropped?
Regarding ExecutionMode="fixedDelay", you are confusing it with "fixedSpacing". The documentation suggests that "fixedDelay" is identical to "fixedRate" except for starting the timer after the queue lag, not before. But the documentation also says that "fixedDelay" ignores the BusyMode option, which leaves it completely unspecified what happens if the period is less than the time taken by the callback.
In my experience, "fixedRate" & "drop", "fixedRate" & "queue", and "fixedDelay" all behave the same, so why are there three different options that do the same thing?
David Young
David Young le 21 Fév 2024
An answer to the point made almost a year ago by David Szwer regarding BusyMode would be very welcome.

Connectez-vous pour commenter.


Geerten Kramer
Geerten Kramer le 19 Avr 2024
Modifié(e) : Geerten Kramer le 19 Avr 2024
I do fully agree with David that the behaviour of the timer is not what you expect. However there IS a difference between the behaviour of the "drop" and "queue" settings. The thing is that drop only drops taskts after one single attempt to get back on track. Queue does try to keep up with the intended period until it reaches the set rate again (also preserving phase).
To be get more clarity I also made a test script that generates the following image comparing drop with queue:
So task # 4 and 5 have a pause of 1.7 [s] while the rest of the runs take 0.3 [s] the set period is 1 [s]. It is clearly visible thet the drop case drops one task (after task 6). The queue case keeps trying to get back on the original intended starttimes track.
However, in my opinion, it would make more sense if the drop setting would start dropping tasks from task 5, the first that cannot be met. Using a trick, this can be accomplished as is shown in the code below.
function t = mytimer()
t = timer;
t.Period = 1;
t.StartDelay = 1;
t.ExecutionMode = 'fixedRate';
t.TimerFcn = @mytimer_cb;
t.BusyMode = 'drop';
t.TasksToExecute = 12;
t.UserData = 0; % initialize for timekeeping here
start(t)
end
function mytimer_cb(h,~)
startT = tic; % freeze starttime
% only execute the current task if the last task execution time was smaller then the set period.
if(h.UserData<h.Period*0.95) % add 5% slag
% Run the intended timerfn...
end
h.UserData.TaskExecTime = toc(startT); % store the elapsed time of the current task's execution.
end
This will then give the following behaviour in a graph:
In above graph, only task #4 did pause for 3.7 [s] the others 0.3 [s]. Period is set to 1 [s] again.
Now you het the whished behaviour that for the drop+trick case, the start time at #6 is already on the whole second pace again. So effectively 3 tasks got dropped here (Task #3 is started at 3[s], #4 at 4[s], #5 is forced to execute in 0[s] not performing the task using the trick, #6 is excecuted at 8 [s].
Hope this helps understanding timers in Matlab. I would realy advice Mathworks to at least implement the option I now added using the trick at a real nicely implemented option for the BusyMode.

Catégories

En savoir plus sur Code Execution dans Help Center et File Exchange

Produits


Version

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by