Как запланировать задачу в реальном времени с абсолютным временем запуска? - PullRequest
0 голосов
/ 17 января 2019

Для стека и структуры протокола связи с поддержкой TSN мне нужно иметь возможность выполнять потоки в реальном времени не только с очень точными интервалами, но и с точными временными интервалами, вычтенными из ptpd.

В настоящее время я сделал это, задержав / выполнив задание до времени начала. Для PoC моего TSN-соединения этого было достаточно, но с расширениями Linux в реальном времени должен быть лучший / более эффективный способ. Введенный джиттер составил около 800 мкс между двумя Beaglebone (под управлением Linux 4.14.71-ti-r80 # 1 PREEMPT).

Используя циклический pthread, я синхронизировал запуск задачи сетевого производителя (Примечание: префикс vos_ обозначает мои методы абстракции ОС, фактически совпадающие с вызовами POSIX):

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
    }
}

Приведенный выше код создает дрожание около 800 мкс с интервалом в 5 мс (при использовании Linux 4.14 без RT-расширения и политики Round-Robin), что довольно неплохо, но неэффективно, когда речь идет о нескольких потоках, выполняющих запланированный трафик. ..

В Linux 4.1.15-ti-rt-r43 # 1 SMP PREEMPT RT я планирую использовать SCHED_DEADLINE в качестве политики, но struct sched_attr не предоставляет параметра времени начала. Проверка во время выполнения в приведенном выше коде не требуется. Но:

Как я могу эффективно использовать расширения реального времени Linux, чтобы поток работал в точном абсолютном времени, скажем, например, каждые 1 мс, начиная с абсолютного реального времени «сейчас» + 0,0075 с (например, сейчас 0085, сейчас 0095, сейчас.0105 ...), без накладных расходов на приведенный выше код?

1 Ответ

0 голосов
/ 21 января 2019

Функция clock_nanosleep() POSIX имеет режим абсолютного крайнего срока:

#define NSEC_PER_SEC 1000000000
/* Initial delay, 7.5ms */
const long start_delay_ns = 7500000;
/* Cycle time, 1ms */
const long cycle_time_ns = 1000000;
struct timespec deadline;

clock_gettime(CLOCK_MONOTONIC, &deadline);
deadline.tv_nsec += start_delay_ns;
deadline.tv_sec += deadline.tv_nsec / NSEC_PER_SEC;
deadline.tv_nsec %= NSEC_PER_SEC;

for (;;)
{
    struct timespec now;

    /* Sleep until deadline */
    while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL) != 0)
        if (errno != EINTR)
            return; /* error handling here */

    pFunction(pArguments);    /* thread function: send data */

    /* Calculate next deadline */
    deadline.tv_nsec += cycle_time_ns;
    deadline.tv_sec += deadline.tv_nsec / NSEC_PER_SEC;
    deadline.tv_nsec %= NSEC_PER_SEC;

    clock_gettime(CLOCK_MONOTONIC, &now);
    if (now.tv_sec > deadline.tv_sec || (now.tv_sec == deadline.tv_sec && deadline.tv_nsec > now.tv_nsec))
        return; /* time overrun error handling here */
}
...