Неожиданная продолжительность QT5 QTimer на ARM

Я работаю над консольным приложением QT для выполнения на процессоре ARM, и я столкнулся с очень странным поведением QTimer: вместо запланированных 100 мс таймер истек через 1946 мс. Я изменил продолжительность, но наблюдаемое поведение не изменилось (около нескольких миллисекунд, например, 1958 мс вместо 40 мс). Когда тот же код выполняется на x86_AMD64 (я заглушил вызов конкретной функции HW API; выполнение этой функции без слота QTimer требует менее 3 мс), длительность таймера, как и ожидалось, составляет +/- 100 мс.

Примечание: версия встроенного QT — 5.4.1; версия ПК QT 5.9.5

Я пробовал разные длительности, в том числе 0. Срок действия примерно такой же продолжительности.

Я отслеживал загрузку ЦП (менее 30%) и среднюю нагрузку (менее 0,15).

Я также написал небольшое консольное приложение QT, которое запускает несколько таймеров разной продолжительности и регистрирует прошедшее время. Результаты правильные (прошедшее время дрейфует, как «ожидалось»;), поэтому я думаю, что buildchain и встроенная установка QT хороши.

Я добавил к своему исходному коду QElapsedTimer и зарегистрировал прошедшее время в методе слота 40 мс QTimer.

Я получил трассировку на ПК:

mDebugMessage = ("elapsed time = 42 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=true - time = 46", "elapsed time = 81 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=true - time = 81", "elapsed time = 122 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=true - time = 122", "elapsed time = 162 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 163", "elapsed time = 201 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 201", "elapsed time = 242 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=true - time = 242", "elapsed time = 281 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 281", ...

На ARM трассировка другая, вместо ожидаемых +/- 40 мс продолжительность около 2 секунд:

mDebugMessage = ("elapsed time = 1958 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 1961", "elapsed time = 3916 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 3919", "elapsed time = 5873 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 5876", "elapsed time = 7830 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 7833", "elapsed time = 9787 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 9790", "elapsed time = 11744 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 11747", "elapsed time = 13700 ms - INPUT_DOOR_LOCKED_SENSOR=false - INPUT_DOOR_UNLOCKED_SENSOR=false - time = 13705", ...

Мне нужна ваша помощь, чтобы понять, почему мой QTimer не истекает, как ожидалось, или любая подсказка, чтобы исследовать цель, что может помешать истечению моего таймера.

Спасибо за вашу идею.

С наилучшими пожеланиями,

РЕДАКТИРОВАТЬ: как и требовалось, код

const int CDoorManagement::I_DOOR_LOCKING_DURATION_MS = 40;
const int CDoorManagement::I_DOOR_LOCKING_ALARM_DURATION_MS = 12000;
CDoorManagement::CDoorManagement(CInputOutputManagerPtr ioPtr)
 : QObject(nullptr)
 , mIOManagerPtr(ioPtr)
 , mOperationElapsedTimer()
 , mDoorLockingTimer()
 , mDebugMessages()
{
    connect(&mDoorLockingTimer, SIGNAL(timeout()), this, SLOT(slotDoorLocking()), Qt::UniqueConnection);
}
void CDoorManagement::slotDoorLocking()
{
    const auto elapsedTime = mOperationElapsedTimer.elapsed();
    if (elapsedTime > I_DOOR_LOCKING_ALARM_DURATION_MS)
    {
        mDoorLockingTimer.stop();
        mIOManagerPtr->setActuator(OUTPUT_DOOR_LOCKING_ACTUATOR, false);
        mDebugMessages << QString("elapsed time = %1 ms - INPUT_DOOR_LOCKED_SENSOR=%2 - INPUT_DOOR_UNLOCKED_SENSOR=%3 - time = %4")
                          .arg(elapsedTime)
                          .arg(mIOManagerPtr->getTorInputState(INPUT_DOOR_LOCKED_SENSOR)?"true":"false")
                          .arg(mIOManagerPtr->getTorInputState(INPUT_DOOR_UNLOCKED_SENSOR)?"true":"false")
                          .arg(mOperationElapsedTimer.elapsed());
        qDebug() << "door locking - mDebugMessage =" << mDebugMessages;
        abort(QSTR_LOCKING_ABORTED);
    }
    if(mIOManagerPtr->getTorInputState(INPUT_DOOR_LOCKED_SENSOR))
    {
        mDoorLockingTimer.stop();
        mIOManagerPtr->setActuator(OUTPUT_DOOR_LOCKING_ACTUATOR, false);
        syslog(LOG_INFO, "%s::%s() - locked: elapsedTime = %lld, max time=%d",
               LOG_PREFIX, __FUNCTION__, elapsedTime, I_DOOR_LOCKING_ALARM_DURATION_MS);
        mDebugMessages << QString("elapsed time = %1 ms - INPUT_DOOR_LOCKED_SENSOR=%2 - INPUT_DOOR_UNLOCKED_SENSOR=%3 - time = %4")
                          .arg(elapsedTime)
                          .arg(mIOManagerPtr->getTorInputState(INPUT_DOOR_LOCKED_SENSOR)?"true":"false")
                          .arg(mIOManagerPtr->getTorInputState(INPUT_DOOR_UNLOCKED_SENSOR)?"true":"false")
                          .arg(mOperationElapsedTimer.elapsed());
        qDebug() << "door locking - mDebugMessage =" << mDebugMessages;

        emit signalDoorLocked();
    }
    else
    {
        mDebugMessages << QString("elapsed time = %1 ms - INPUT_DOOR_LOCKED_SENSOR=%2 - INPUT_DOOR_UNLOCKED_SENSOR=%3 - time = %4")
                          .arg(elapsedTime)
                          .arg(mIOManagerPtr->getTorInputState(INPUT_DOOR_LOCKED_SENSOR)?"true":"false")
                          .arg(mIOManagerPtr->getTorInputState(INPUT_DOOR_UNLOCKED_SENSOR)?"true":"false")
                          .arg(mOperationElapsedTimer.elapsed());
    }
}

void CDoorManagement::startLocking()
{
    mDebugMessages.clear();
    qDebug() << "start of mDoorLockingTimer using " << I_DOOR_LOCKING_DURATION_MS << " ms delay";
    mOperationElapsedTimer.start();
    mDoorLockingTimer.start(I_DOOR_LOCKING_DURATION_MS);
    if(!mIOManagerPtr->setActuator(OUTPUT_DOOR_LOCKING_ACTUATOR, true))
    {
        mIOManagerPtr->setActuator(OUTPUT_DOOR_LOCKING_ACTUATOR, false);
        syslog(LOG_WARNING, "%s::%s() - failed to activate OUTPUT_DOOR_LOCKING_ACTUATOR", LOG_PREFIX, __FUNCTION__);
        abort(QSTR_LOCKING_ACTIVATION_FAILURE);
    }
}

person avf    schedule 16.07.2019    source источник
comment
Является ли ваша x86_AMD64 системой SMP, а ARM — нет? Вы не показываете свой код или лучше минимальный код для воспроизведения. Видимо, если что-то в контексте "слота" крадет ЦП, то слот не вызывается. У вас должен быть своевременный цикл событий. Вполне возможно, что система SMP будет вести себя совсем иначе. Может не ваш случай, но вы точно НЕ предоставили эту информацию.   -  person artless noise    schedule 16.07.2019
comment
Привет @artlessnoise, я добавил код запуска таймера и метод слота. Вы правы, мое ядро ​​​​Linux x86 - это SMP, а ARM - нет. Я не думаю, что это имеет влияние, мой файл приложения timersdryrun работает. Основные параметры моего приложения и малого приложения идентичны: ` int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Таймеры CTimersRun; QTimer::singleShot(0, &timers, SLOT(start())); вернуть a.exec(); } `   -  person avf    schedule 16.07.2019


Ответы (1)


Я нашел основную причину наблюдаемого поведения: в слоте примера я прочитал цифровой вход, и для этого чтения требуется 3 мс. в другом слоте я считываю два входа RTD и эти показания требуют до 2000 мс. чтение цифровых входов и входов RTD использует ту же библиотеку, где есть мьютекс для доступа к HW, либо доступ к цифровым, либо к RTD :(

person avf    schedule 17.07.2019
comment
Если вы нашли решение самостоятельно, примите ваш ответ вместо того, чтобы писать в заголовке решение! Ознакомьтесь с руководством по ответу на свой вопрос. - person Nino Filiu; 17.07.2019