For a TSN-aware communication protocol stack and framework, I need to be able to execute real-time threads not only running at very exact intervals, but starting at precise timeslots deducted from ptpd.
Currently, I did that by delaying / yielding the task until the start time. For a PoC of my TSN communication this was sufficient, but with the Linux real-time extensions, there must be a better / more effective way. The jitter introduced was about 800us between two Beaglebones (running Linux 4.14.71-ti-r80 #1 SMP PREEMPT).
Using a cyclic pthread, I synchronised the start of my network producer task (Note: vos_ prefix denotes my OS abstraction methods, actually matching POSIX calls):
for (;; )
{
/* Synchronize with starttime */
vos_getTime(&now); /* get initial time */
vos_subTime(&now, &startTime);
/* Wait for multiples of interval */
execTime = ((UINT32)now.tv_usec % interval);
waitingTime = interval - execTime;
if (waitingTime >= interval)
{
...error checks omitted
}
/* Idle for the difference */
vos_threadDelay(waitingTime); /* pthread_testcancel() inside */
vos_getTime(&priorCall); /* get initial time */
pFunction(pArguments); /* thread function: send data */
vos_getTime(&afterCall); /* get time after function has returned */
/* get the runtime of pFunction() */
vos_subTime(&afterCall, &priorCall);
/* afterCall holds now the time difference... */
if (afterCall.tv_sec <= MAXSEC_FOR_USECPRESENTATION)
{
...runtime / error handling omitted
}
}
The above code produces a jitter of about 800us at interval times of 5ms (using Linux 4.14 without RT-extension and policy Round-Robin), which is fairly good - but ineffective when it comes to multiple threads all doing scheduled traffic...
With Linux 4.1.15-ti-rt-r43 #1 SMP PREEMPT RT, I'm planning to use SCHED_DEADLINE as policy, but struct sched_attr provides no start-time-parameter. The runtime-checking in the above code is not needed, then. But:
How can I effectively use Linux's real-time extensions to have a thread running at exact absolute times, say for example at every 1ms starting at absolute real time 'now' + 0.0075s (e.g. now.0085, now.0095, now.0105 ...), without the overhead of the above code?