как обеспечить, чтобы ядровые потоки не обращались к изолированному ЦПУ

Вопрос или проблема

У меня есть программный стек пользовательского уровня реального времени, работающий на ядре RT Ubuntu.

Linux ran416 5.15.0-1061-realtime #69-Ubuntu SMP PREEMPT_RT Пн Апр 15 18:56:55 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Я также настроил изоляцию процессора и использую API установки привязки к ядрам, чтобы некоторые критические потоки работали на изолированном процессоре.

Я убедился, что никакие другие приложения/потоки не работают на этих изолированных ядрах (будь то установка привязки к ядру или taskset).

Таким образом, это исключает любые пользовательские приложения/потоки из доступа к моему изолированному ядру.

Я убедился, что не выполняю никаких операций ввода-вывода, сетевых операций или блокировок какого-либо рода в критических потоках.

Тем не менее, я наблюдаю, что некоторые потоки ядра иногда обращаются к изолированному ядру CPU. В такой ситуации, когда мой поток не уступает ядровому потоку, это приводит к зависанию системы. В других случаях это заставляет мой критический поток пропускать события, что имеет катастрофические последствия для моего стека.

Я пробовал поиграть с /proc/sys/kernel/sched_rt_period_us и /proc/sys/kernel/sched_rt_runtime_us, как рекомендовали в поддержке Ubuntu, но это, похоже, не помогает или иногда создает дополнительную нестабильность.

Поддержка Ubuntu также указала, что “привязка CPU не изолирует потоки ядра. Только другие приложения пользовательского пространства гарантированно не запускаются на изолированных ядрах.”

Итак, мой вопрос: существует ли другая версия Linux, которая может дать мне эту гарантию? Если нет, каков идеальный подход к работе с этим ограничением, учитывая тот факт, что я хочу, чтобы несколько потоков моего приложения пользовательского пространства абсолютно не конкурировали за процессор.

Я не ожидал бы, что какая-либо версия Linux будет работать иначе, чем Ubuntu, потому что это уровень ядра, а ядро используется всеми версиями Linux. В любой момент может быть более новая версия ядра на каком-то конкретном бренде Linux, которая будет включать изменения, позволяющие такое поведение. Но я ожидаю, что эти изменения будут быстро включены в другие дистрибутивы.

Итак, если вы хотите, чтобы некоторые потоки не имели абсолютно никакой конкуренции, я думаю, вам не повезло. Если компьютер зависает, это означает, что в ядре происходят вещи, которые просто нельзя игнорировать.

Существуют некоторые веб-сайты, которые обсуждают проблемы изоляции CPU, например этот: https://lwn.net/Articles/816298/; я не уверен, была ли когда-либо выпущена патч.

В этой статье обсуждаются проблемы с NVME-дисками; было принято решение обеспечить, чтобы прерывания происходили на том же CPU, где был сделан запрос: https://serverfault.com/questions/1052448/how-can-i-override-irq-affinity-for-nvme-devices. Этот URL ссылается на прерывания NVME, а не на потоки ядра, но вы начинаете понимать суть проблем.

Здесь https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_for_real_time/7/html/tuning_guide/isolating_cpus_using_tuned-profiles-realtime#Isolating_CPUs_Using_tuned-profiles-realtime есть кое-что интересное:

Изоляция CPU обычно включает:

  • удаление всех потоков пользовательского пространства;
  • удаление любых не привязанных потоков ядра (привязанные потоки ядра связаны с конкретным CPU и не могут быть перемещены);
  • удаление прерываний путем изменения свойства /proc/irq/N/smp_affinity каждого номера прерывания (IRQ) N в системе.

где вы можете увидеть, что они обсуждают “привязанные потоки ядра”, хотя они не обсуждают проблему с прерываниями NVME.

В этой статье они говорят о уменьшении осцилляций из-за потоков ядра: https://www.kernel.org/doc/html/latest/admin-guide/kernel-per-CPU-kthreads.html Но я не вижу способа устранить их. Если вы хотите, чтобы CPU был только у вас, возможно, вам потребуется приобрести микроcontroller и подключить его к вашей системе через шину PCIe или другой интерфейс.

Мне было бы интересно увидеть, как кто-то другой укажет на метод, который делает именно то, что вы просите.

Ответ или решение

Обеспечение изоляции потоков ядра от изолированного ЦПУ в Linux

Работа с реальным временем в среде Ubuntu RT Kernel требует особого внимания к деталям, особенно когда речь идет об изоляции потоков и недопущении их взаимодействия с потоками ядра и другими приложениями. Давайте разберем некоторые шаги и рекомендации для достижения вашей цели по полной изоляции критических потоков.

1. Изучение ограничений изоляции ЦПУ

Согласно вашим наблюдениям и рекомендациям поддержки Ubuntu, важно понимать, что использование изоляции ЦПУ, как правило, гарантирует лишь отсутствие запуска пользовательских потоков на изолированных ядрах. Это значит, что потоки ядра и потоки, не привязанные к определенному ядру, все еще могут быть запущены на изолированных ЦПУ, что вы и наблюдаете.

Вам необходимо взаимодействовать с ядром и другими системными настройками, чтобы уменьшить или устранить доступ потоков ядра к изолированным ядрам.

2. Конфигурация и управление прерываниями

Одним из основных шагов для уменьшения влияния потоков ядра является управление прерываниями:

  • Настройка привязки прерываний: Каждое устройство в системе, генерирующее прерывания, имеет связанный номер IRQ. Вы можете настроить маску принадлежности IRQ, чтобы ограничить рендеринг прерываний на изолированных ЦПУ. Это делается с помощью изменения файла /proc/irq/N/smp_affinity, где N — номер прерывания. Убедитесь, что прерывания привязаны к другим ядрам, а не к вашим изолированным ядрам.
echo 3 > /proc/irq/N/smp_affinity  # Пример для привязки прерывания к ядрам 0 и 1
  • Удаление небазирующихся потоков ядра: Если вы можете идентифицировать потоки ядра, которые не привязаны к конкретным ядрам (unbound kernel threads), возможно, вам потребуется отключить или перенастроить их. В некоторых случаях это может потребовать изменения конфигурации ядра.

3. Использование настроек планировщика

Вы упомянули о настройках sched_rt_period_us и sched_rt_runtime_us. Хотя эти параметры могут быть контрольными для использования ресурсов планировщиком, не стоит ожидать, что они полностью изолируют ваши критические потоки. Вместо этого лучше обратить внимание на следующие настройки:

  • Использование ограничений приоритетов: Убедитесь, что ваши критические потоки запущены с высоким приоритетом (например, SCHED_FIFO) и что другие неважные потоки имеют более низкие приоритеты.
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &param);

4. Проверка привязки потоков ядра

Для понимания того, на каких ядрах работают потоки ядра, вы можете использовать ps и top с расширенной информацией или команды, такие как htop, чтобы визуализировать загруженность ядер. Это позволит вам лучше отслеживать, как распределяются потоки по вашим ядрам.

5. Альтернативные варианты

В качестве последнего варианта, если данные решения не приносят необходимого результата, рассмотрите возможность:

  • Изменения на уровне ядра: Обратите внимание на патчи или форки ядра, которые могут быть специально разработаны для лучшей изоляции потоков для приложений реального времени. Некоторые дистрибутивы могут предлагать такие версии на уровне разработки.

  • Оборудование с поддержкой реального времени: Если все перечисленные методы не работают, возможно, стоит рассмотреть использование специализированного аппаратного обеспечения или RTOS (Real-Time Operating System), которые обеспечивают более строгое управление затратами на контекстные переключения и потоками.

Заключение

Хотя полное исключение потоков ядра на изолированных ЦПУ невозможно сделать стандартными средствами в текущих версиях ядра Linux, использование подходов настройки прерываний, управление приоритетами и правильная конфигурация могут помочь вам минимизировать влияние этих потоков на ваши критические задачи. Настоятельно рекомендуем тщательно протестировать все изменения на отдельной среде перед внедрением в продакшн.

Оцените материал
Добавить комментарий

Капча загружается...