Как источник времени, используемый в ядре Linux SCHED_DEADLINE, соотносится с источниками времени, доступными в C++ чере ⇐ Linux
-
Anonymous
Как источник времени, используемый в ядре Linux SCHED_DEADLINE, соотносится с источниками времени, доступными в C++ чере
Недавно я попробовал реализовать программу, которая выполняет фрагмент кода каждые 200 мс (само время выполнения варьировалось от 1 мс до 50 мс). Для меня это звучало точно так же, как проблема, для которой был разработан SCHED_DEADLINE.
Однако измерения эталонного времени с использованием std::chrono::steady_lock [и std::chrono::system_lock] показали отклонение SCHED_DEADLINE периоды относительно этих источников времени. И этот дрейф зависел от машины, на которой он запускался:
[*]На одной машине [Ubuntu Mate 22.04, ядро 6.02, Ryzen 7 16C/32T] планировщик запланировал задачу раньше, чем я ожидал, глядя на std::chrono::steady_lock.< /ли> На другом компьютере [Debian 12, ядро 6.1.0, Intel i7-10510U] планировщик запланировал задачу позже, чем я ожидал, посмотрев std::chrono::steady_lock.< /ли>
Я бегло ознакомился с исходным кодом ядра Linux [см. здесь] – однако должен признать, что я не совсем понял, откуда на самом деле происходят jiffies и как часы .c затем объединяет все это вместе с
GTOD (монотонные часы) [*]sched_clock() [*]явные события простоя
для
монотонный
быстрые (время выполнения) часы с высоким разрешением и ограниченным дрейфом между процессорами.
[*]
Может ли кто-нибудь просветить меня, как эти два источника времени связаны друг с другом?
[*]
Что лучше выбрать для моего приложения, которому требуется период 200 мс [в режиме реального времени...]?
PS: Поскольку мне не разрешено загружать код как удобный для пользователя проект tar.gz, и я отказываюсь загружать его на другой веб-сайт и размещаю только ссылку здесь, вот код...
CMakeLists.txt
cmake_minimum_required (ВЕРСИЯ 3.5) проект(TestingRts LANGUAGES CXX) установить (CMAKE_CXX_STANDARD 17) установить (CMAKE_CXX_STANDARD_REQUIRED ON) add_executable (TestingRts main.cpp RealTimeScheduler.cpp RealTimeScheduler.hpp ) включить (GNUInstallDirs) install(ЦЕЛЕВЫЕ TestingRts НАЗНАЧЕНИЕ БИБЛИОТЕКИ ${CMAKE_INSTALL_LIBDIR} НАЗНАЧЕНИЕ ВЫПОЛНЕНИЯ ${CMAKE_INSTALL_BINDIR} ) realTimeScheduler.hpp
#ifndef LINUX_REAL_TIME_SCHEDULER_HPP #define LINUX_REAL_TIME_SCHEDULER_HPP #ifdef WIN32 #warning «Планировщик реального времени существует только в Linux — этот файл не следует включать в Windows». #else // WIN32 #include пространство имен Linux { int setRealTimeSchedulerForThisThread (uint64_t const periodInNanoSeconds, uint64_t const runtimeInNanoSeconds); } // пространство имен Linux #конециф // WIN32 #endif /* LINUX_REAL_TIME_SCHEDULER_HPP */ realTimeScheduler.cpp
#include "realTimeScheduler.hpp" #ifdef WIN32 #warning «Планировщик реального времени существует только в Linux — этот файл не следует включать в Windows». #else // WIN32 #include /* SCHED_DEADLINE */ #include /* struct sched_attr */ #include #include пространство имен Linux { int setRealTimeSchedulerForThisThread (uint64_t const periodInNanoSeconds, uint64_t const runtimeInNanoSeconds) { pid_t const threadId = syscall(SYS_gettid); struct sched_attr SchedulerAttributes = { .size = sizeof(struct sched_attr), .sched_policy = SCHED_DEADLINE, .sched_flags = 0, .sched_nice = 0, .sched_priority = 0, .sched_runtime = runtimeInNanoSeconds, // наносекунды .sched_deadline = periodInNanoSeconds, // наносекунды .sched_ period = periodInNanoSeconds // наносекунды }; return syscall(__NR_sched_setattr, threadId, &schedulerAttributes, 0); } } // пространство имен Linux #конециф // WIN32 main.cpp
#include "realTimeScheduler.hpp" #include #include #include #include #include #include Измерения структуры { Измерения(std::chrono::steady_lock::time_point const startBusyWait, std::chrono::steady_clock::time_point const start, std::chrono::steady_clock::time_point const Finish, std::chrono::system_lock::time_point startLocal, std::chrono::system_lock::time_point FinishLocal) : startBusyWait(startBusyWait) , начать (начать) , закончить (закончить) , startLocal(startLocal) , FinishLocal(finishLocal) { } std::chrono::steady_lock::time_point startBusyWait; std::chrono::steady_lock::time_point start; std::chrono::steady_lock::time_point Finish; std::chrono::system_lock::time_point startLocal; std::chrono::system_lock::time_point FinishLocal; }; статический беззнаковый индекс = 0; статический bool isRunning_ = false; статический std::shared_ptr thread_; static std::vector times_; статический std::vector обработанноеTimes_; статический constexpr size_t NumberOfPeriods = 1000; static constexpr std::chrono::duration periodDuration = std::chrono::milliсекунды(200); статический constexpr std::chrono::duration totalDuration = periodDuration * NumberOfPeriods; статический std::chrono::steady_lock::time_point nextStartTime_; static constexpr std::chrono::steady_lock::duration номинальныйBusyWaitDuration_ = std::chrono::milliсекунды(10); статический встроенный std::chrono::steady_lock::time_point now() { return std::chrono::steady_lock::now(); } двойная задержкаDummy (итерации const size_t) { двойной блаб = 0; for (индекс size_t = 0; индекс
Недавно я попробовал реализовать программу, которая выполняет фрагмент кода каждые 200 мс (само время выполнения варьировалось от 1 мс до 50 мс). Для меня это звучало точно так же, как проблема, для которой был разработан SCHED_DEADLINE.
Однако измерения эталонного времени с использованием std::chrono::steady_lock [и std::chrono::system_lock] показали отклонение SCHED_DEADLINE периоды относительно этих источников времени. И этот дрейф зависел от машины, на которой он запускался:
[*]На одной машине [Ubuntu Mate 22.04, ядро 6.02, Ryzen 7 16C/32T] планировщик запланировал задачу раньше, чем я ожидал, глядя на std::chrono::steady_lock.< /ли> На другом компьютере [Debian 12, ядро 6.1.0, Intel i7-10510U] планировщик запланировал задачу позже, чем я ожидал, посмотрев std::chrono::steady_lock.< /ли>
Я бегло ознакомился с исходным кодом ядра Linux [см. здесь] – однако должен признать, что я не совсем понял, откуда на самом деле происходят jiffies и как часы .c затем объединяет все это вместе с
GTOD (монотонные часы) [*]sched_clock() [*]явные события простоя
для
монотонный
быстрые (время выполнения) часы с высоким разрешением и ограниченным дрейфом между процессорами.
[*]
Может ли кто-нибудь просветить меня, как эти два источника времени связаны друг с другом?
[*]
Что лучше выбрать для моего приложения, которому требуется период 200 мс [в режиме реального времени...]?
PS: Поскольку мне не разрешено загружать код как удобный для пользователя проект tar.gz, и я отказываюсь загружать его на другой веб-сайт и размещаю только ссылку здесь, вот код...
CMakeLists.txt
cmake_minimum_required (ВЕРСИЯ 3.5) проект(TestingRts LANGUAGES CXX) установить (CMAKE_CXX_STANDARD 17) установить (CMAKE_CXX_STANDARD_REQUIRED ON) add_executable (TestingRts main.cpp RealTimeScheduler.cpp RealTimeScheduler.hpp ) включить (GNUInstallDirs) install(ЦЕЛЕВЫЕ TestingRts НАЗНАЧЕНИЕ БИБЛИОТЕКИ ${CMAKE_INSTALL_LIBDIR} НАЗНАЧЕНИЕ ВЫПОЛНЕНИЯ ${CMAKE_INSTALL_BINDIR} ) realTimeScheduler.hpp
#ifndef LINUX_REAL_TIME_SCHEDULER_HPP #define LINUX_REAL_TIME_SCHEDULER_HPP #ifdef WIN32 #warning «Планировщик реального времени существует только в Linux — этот файл не следует включать в Windows». #else // WIN32 #include пространство имен Linux { int setRealTimeSchedulerForThisThread (uint64_t const periodInNanoSeconds, uint64_t const runtimeInNanoSeconds); } // пространство имен Linux #конециф // WIN32 #endif /* LINUX_REAL_TIME_SCHEDULER_HPP */ realTimeScheduler.cpp
#include "realTimeScheduler.hpp" #ifdef WIN32 #warning «Планировщик реального времени существует только в Linux — этот файл не следует включать в Windows». #else // WIN32 #include /* SCHED_DEADLINE */ #include /* struct sched_attr */ #include #include пространство имен Linux { int setRealTimeSchedulerForThisThread (uint64_t const periodInNanoSeconds, uint64_t const runtimeInNanoSeconds) { pid_t const threadId = syscall(SYS_gettid); struct sched_attr SchedulerAttributes = { .size = sizeof(struct sched_attr), .sched_policy = SCHED_DEADLINE, .sched_flags = 0, .sched_nice = 0, .sched_priority = 0, .sched_runtime = runtimeInNanoSeconds, // наносекунды .sched_deadline = periodInNanoSeconds, // наносекунды .sched_ period = periodInNanoSeconds // наносекунды }; return syscall(__NR_sched_setattr, threadId, &schedulerAttributes, 0); } } // пространство имен Linux #конециф // WIN32 main.cpp
#include "realTimeScheduler.hpp" #include #include #include #include #include #include Измерения структуры { Измерения(std::chrono::steady_lock::time_point const startBusyWait, std::chrono::steady_clock::time_point const start, std::chrono::steady_clock::time_point const Finish, std::chrono::system_lock::time_point startLocal, std::chrono::system_lock::time_point FinishLocal) : startBusyWait(startBusyWait) , начать (начать) , закончить (закончить) , startLocal(startLocal) , FinishLocal(finishLocal) { } std::chrono::steady_lock::time_point startBusyWait; std::chrono::steady_lock::time_point start; std::chrono::steady_lock::time_point Finish; std::chrono::system_lock::time_point startLocal; std::chrono::system_lock::time_point FinishLocal; }; статический беззнаковый индекс = 0; статический bool isRunning_ = false; статический std::shared_ptr thread_; static std::vector times_; статический std::vector обработанноеTimes_; статический constexpr size_t NumberOfPeriods = 1000; static constexpr std::chrono::duration periodDuration = std::chrono::milliсекунды(200); статический constexpr std::chrono::duration totalDuration = periodDuration * NumberOfPeriods; статический std::chrono::steady_lock::time_point nextStartTime_; static constexpr std::chrono::steady_lock::duration номинальныйBusyWaitDuration_ = std::chrono::milliсекунды(10); статический встроенный std::chrono::steady_lock::time_point now() { return std::chrono::steady_lock::now(); } двойная задержкаDummy (итерации const size_t) { двойной блаб = 0; for (индекс size_t = 0; индекс
Мобильная версия