Page 1 of 1
Terminating main with one task running
Posted: 29 February 2008, 14:05 PM
by pjc30943
I'm measuring the execution time of a section of this task in two different ways. For now, ignore why I'm exiting a sub instead of letting it end naturally.
Method 1:
Code: Select all
sub main()
...
calltask task, taskStack
exit sub
...
end
Method 2:
Code: Select all
sub main()
...
task
...
end
Method one will at first have multitasking, but then quickly will become the only code running. Method two will call the task as a subroutine, so there should be no task switching as it is all that runs.
With method one, that code section takes ~4ms (for unknown reasons, as it's just some lines of algebra).
With method two, that code section takes either 0.0 (i.e. <1.95ms) or 1.95ms, the task switching time.
Any thoughts on why different times are reported? Only task() is running both with both methods.
EDIT: I wrote "--thus it is also odd that execution time would be a multiple of task switch time", which is actually due to the Timer resolution; this statement is thus irrelevant.
Re: Terminating main with one task running
Posted: 29 February 2008, 14:27 PM
by mikep
pjc30943 wrote:I'm measuring the execution time of a section of this task in two different ways.
How are you measuring the time for a task? The timer() function as you surmised only has a resolution of 1.95ms. The normal way to measure performance with ZBasic is either to wrap the function in a loop of say 1000 iterations or to use a high resolution timer and setup the chip registers yourself. Some people also twiddle an I/O pin and use an oscilloscope or logic analyzer to measure the time.
I think you have to post more code. Only a little algebra taking 4 ms is suspicious. Perhaps we should start there with a simple loop and see how long the algebra routine really takes (after dividing by 1000).
Posted: 29 February 2008, 15:19 PM
by pjc30943
Yes, those results were from Timer().
There is also a scope observing the loop times:
With the task invoked, then main exited, the loop time is 95 Hz.
When the same routine is called in main, the loop time is 200 Hz.
In both cases the sub is the only thing running, yet there appears to still be some sort of task-switching going on, even though there's no multitasking.
I can see the waveform periodically pausing for 1.95ms as the scheduler takes command...
Re: Terminating main with one task running
Posted: 29 February 2008, 16:15 PM
by dkinzer
pjc30943 wrote:Method one will at first have multitasking, but then quickly will become the only code running.
Although this is a reasonble assumption, it is not actually true. The Main() task is special in several ways, not least because it is launched automatically. Another way in which it is special is that it never really terminates. Consider the code generated for an empty Main():
Code: Select all
0000 104001 LODSP 0x0140 (320)
0003 1b1100 PSHI_W 0x0011 (17)
0006 1b4001 PSHI_W 0x0140 (320)
0009 1b0000 PSHI_W 0x0000 (0)
000c fe4a SCALL TASK_START
000e 01fdff BRA 000e
Public Sub Main()
End Sub
0011 06 RET
Although both Main() and other ordinary task main routines end with a RET instruction, only the Main() task actually returns to the instruction immediately following the corresponding TASK_START instruction. When a non-Main() task returns, the fact that it is not the Main() task is detected and the task is removed from the task list.
If you want to free up most of the task time being "wasted" by Main(), modify your program thusly:
Code: Select all
Sub Main()
...
CallTask task, taskStack
...
Do
Call Sleep(0)
Loop
End
Re: Terminating main with one task running
Posted: 29 February 2008, 17:18 PM
by mikep
dkinzer wrote:pjc30943 wrote:Method one will at first have multitasking, but then quickly will become the only code running.
Although this is a reasonable assumption, it is not actually true.
I had thought it worked this way too with the infinite loop being in the ZVM scheduler i.e. no runnable tasks so sleep until next timer tick or interrupt. Putting the code here would facilitate powering down the AVR when idle. Of course you would need a way to turn off the timer tick as well.
Posted: 11 March 2008, 13:52 PM
by pjc30943
It's still not completely clear to me what is going on inside the VM.
Consider the following example with one encoder, whose output pulses (pulse width varies with absolute position) are measured using waitForInterrupt.
This subroutine is an infinite loop of waitForInterrupt() used to watch for falling and rising edges. Sleep 0.0 is placed in each loop iteration.
On each edge transition, TMR5 values are stored, a pin is togged after the falling transition and again at the end of the loop, and some FP calculations are made.
The task is being called as a subroutine to ignore multitasking effects.
However even then there exists a delay of 2.03ms between the encoder's falling edge, and the first pin toggle placed immediately after the first WaitForInterrupt(falling) .
After that toggle--since the encoder pulse already went high due to the long delay when WFInt() triggered--the second rising WaitForInterrupt() immediately triggers, and so the loop completes in about 56us.
It is unclear why it takes 2ms to capture the falling edge, when there are no tasks running, and this loop is effectively in Main().
I would have thought the RTC doesn't play any role in this case; and the delay is not 1.95ms, but 2.03ms (though the difference could be overhead for executing the interrupt, and toggling the output pin).
Any thoughts?
Posted: 11 March 2008, 14:33 PM
by dkinzer
pjc30943 wrote:It's still not completely clear to me what is going on inside the VM.
Any thoughts on how I might mock this up to observe the same phenomenon? It might work to use another ZX to produce a simulated encoder signal, triggering off of an output of the first ZX with a fixed or random delay.
If you could provide setup instructions and some minimal code that manifests the issue that would be quite helpful.
Posted: 11 March 2008, 16:04 PM
by pjc30943
dkinzer wrote:If you could provide setup instructions and some minimal code that manifests the issue that would be quite helpful.
I'll produce an example that is simple to set up, and that requires minimal code.
It's possible that while reducing the code I'll figure out what I've done wrong--but that's an equally desirable outcome of course...