Nano Hash - криптовалюты, майнинг, программирование

Как эффективно реализовать асинхронный ввод-вывод в ядре

Этот вопрос касается низкоуровневых системных вызовов асинхронного ввода-вывода, таких как send + epoll/aio_read и других. Я спрашиваю как о сетевом вводе-выводе, так и о дисковом вводе-выводе.

Наивным способом реализации этих асинхронных вызовов было бы создание потока для каждого асинхронного запроса ввода-вывода, который затем выполнял бы запрос синхронно. Очевидно, что это наивное решение плохо масштабируется при большом количестве параллельных запросов. Даже если бы использовался пул потоков, нам все равно нужно было бы иметь один поток для каждого параллельного запроса.

Поэтому я предполагаю, что это делается следующим более эффективным способом:

Для записи/отправки данных:

  • Добавьте запрос на отправку в некоторую внутреннюю очередь асинхронного ввода-вывода ядра.

  • Выделенные «потоки записи» принимают эти запросы на отправку таким образом, что целевое оборудование полностью используется. Для этого может использоваться специальный планировщик ввода/вывода.

  • В зависимости от целевого оборудования запросы на запись в конечном итоге отправляются, например. через прямой доступ к памяти (DMA).

Для чтения/получения данных:

  • Аппаратное обеспечение инициирует прерывание ввода-вывода, которое переходит в обработчик прерывания ввода-вывода ядра.

  • Обработчик прерывания добавляет уведомление в очередь чтения и быстро возвращается.

  • Выделенные «потоки чтения» получают уведомления очереди чтения и выполняют две задачи: 1) При необходимости копируют прочитанные данные в целевой буфер. 2.) При необходимости каким-либо образом уведомить целевой процесс (например, epoll, signal,..).

Для всего этого нет необходимости иметь больше потоков записи или чтения, чем количество ядер ЦП. Следовательно, проблема масштабируемости параллельных запросов будет решена.

Как это реализовано в реальных ядрах ОС? Какие из этих предположений верны?


  • Как это реализовано в реальных ядрах ОС? - Слишком широкая тема для переполнения стека. Вы используете тег linux-kernel, не пробовали ли вы читать о вводе-выводе в ядре Linux? См., например. Документация Драйверы блочных устройств о написании драйверов для блочных устройств. 23.12.2019

Ответы:


1

Эти «асинхронные» операции ввода-вывода — еще одна иллюзия KERNEL и службы драйверов. Я возьму пример драйвера Wi-Fi. (то есть сеть).

  1. RX

1) Если пакеты приходят, Wi-Fi H/W будет генерировать прерывания и DMA кадра dot11 или dot3 в DRAM (это зависит от Wi-Fi H/W. В настоящее время большинство современных Wi-Fi HW преобразует пакеты в HW - на самом деле FW на ХВ).

2) Драйвер Wi-Fi (работающий в ядре) должен обрабатывать несколько вещей, связанных с Wi-Fi, но, скорее всего, он сформирует буфер сокета (skb), а затем отправит skbs в ядро ​​​​Linux. Обычно это происходит в NET_RX_SOFTIRQ или вы можете создать свой собственный поток.

3) Пакеты приходят в стек Linux. Вы можете отправить его в пространство пользователя. Это происходит в "__netif_receive_skb_core", и если пакет "IP", первый rx_handler будет "ip_rcv()".

4) IP-пакеты перемещаются к обработчику транспортного уровня, который называется udp_rcv() / tcp_rcv(). Чтобы отправить пакеты на транспортный уровень, вам нужно пройти через уровень сокетов, и в конечном итоге вы сформируете связанный список пакетов (вы можете сказать Q) на конкретном сокете.

5) Насколько я понимаю, этот "Q" - это очередь на подачу пакета в пространство пользователя. Здесь вы можете сделать «асинхронный» или «синхронный» ввод-вывод.

  1. TX

1) Пакеты проходят через транспортный уровень KERNEL и уровень IP, и, в конце концов, вызывается ваш обработчик TX netdev (hard_start_xmit или ndo_xmit_start). По сути, если ваш netdev (например, eth0 или wifi0) является сетевым устройством, он подключен к вашей функции драйвера Ethernet «TX» или функции драйвера Wi-Fi «TX». Это обратный вызов, и он обычно настраивается при запуске драйвера.

2) На данном этапе ваши пакеты уже преобразованы в "skb"

3) В обратном вызове он подготовит все заголовки и дескрипторы и сделает DMA.

4) Как только TX передается на HW, HW генерирует прерывание, и вам нужно освободить пакет.

Я хочу сказать, что ваш сетевой ввод-вывод уже работает как «асинхронный» на уровне прямого доступа к памяти и драйвера. Большинство современных драйверов могут иметь для этого отдельный контекст. Для TX он будет использовать поток, тасклет или NET_TX_SOFTIRQ. Для RX, если мы используем «NAPI», он будет использовать NET_RX_SOFTIRQ. или он также может использовать поток и тасклет.

Все это происходит независимо на основе «прерывания» или какого-либо другого триггера.

«Синхронный ввод-вывод» в основном моделируется на верхнем прикладном уровне. Итак, если вы переписываете свой уровень сокетов в ядре, вы можете делать все, что хотите, поскольку нижний уровень уже работает так, как вы хотите.

25.12.2019
Новые материалы

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

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

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

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..