Использование обратной связи для синхронного IP C при использовании архитектуры NUMA - PullRequest
0 голосов
/ 25 апреля 2020

(для платформы Linux) Возможно ли (с точки зрения производительности) попытаться установить связь (синхронно) через петлевой интерфейс между процессами на разных узлах NUMA?

Как насчет если процессы находятся на одном узле NUMA? Я знаю, что можно привязать память к процессу и / или установить привязку ЦП к узлу (используя libnuma). Я не знаю, верно ли это и для сетевого интерфейса.

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

1 Ответ

1 голос
/ 25 апреля 2020

Сетевые интерфейсы не находятся на узле; это устройство - виртуальное или реальное - общее для всей машины. Интерфейс обратной связи - это просто буфер памяти где-то или другой, и некоторый код ядра. Код, который работает для поддержки этого устройства, вероятно, отскакивает от ядер ЦП, как и любой другой поток в системе.

Вы говорите об узлах NUMA и пометили вопрос с помощью Linux. Linux не работает на чистой архитектуре NUMA, он работает на архитектуре SMP. Современные процессоры от, скажем, Intel, AMD, ARM синтезируют аппаратную среду SMP с использованием отдельных ядер, различной степени унификации интерфейса кэш-памяти и высокоскоростных последовательных соединений между ядрами или процессорами. По сути, операционная система или программное обеспечение, работающее сверху, не может увидеть базовую архитектуру NUMA; он думает, что работает на классической архитектуре SMP.

Intel / AMD / все остальные сделали это, потому что когда-то успешные машины с несколькими процессорами действительно были SMP; у них было несколько процессоров, которые совместно использовали одну и ту же шину памяти, и имели равный доступ к ОЗУ на другом конце шины. Программное обеспечение было написано, чтобы воспользоваться этим (Linux, Windows, et c).

Затем производители процессоров поняли, что архитектуры SMP отстают, когда речь идет об улучшении скорости. AMD моргнула первой, отказалась от SMP в пользу Hypertransport и оказалась успешной. Intel дольше сохраняла чистую SMP, но вскоре тоже сдалась и начала использовать QPI между процессорами.

Но чтобы обеспечить обратную совместимость старого программного обеспечения (Linux, Windows, et c), разработчикам ЦП пришлось создать аппаратную среду синтетического c SMP поверх Hypertransport и QPI. В принципе, они могли на тот момент решить, что SMP мертв, и предоставили нам чистую архитектуру NUMA. Но это, вероятно, было бы коммерческим самоубийством; Чтобы согласиться на go, потребовалось бы согласие всей отрасли аппаратного и программного обеспечения, но к тому времени было уже слишком поздно переписывать все с нуля.

Думает как сетевые сокеты (в том числе через интерфейс обратной связи), каналы, последовательные порты не являются синхронными. Они являются потоковыми носителями, и отправитель и получатель не синхронизируются в процессе передачи данных. То есть отправитель может write() данные и думать, что это завершено, но в действительности данные все еще где-то застряли в каком-то сетевом буфере и еще не попали в read(), который должен вызывать процесс назначения. получить данные.

То, что Linux будет делать с процессами и потоками, - это попытка запустить их все одновременно, до ограничения количества ядер ЦП на машине. По большому счету это приведет к тому, что ваши процессы будут работать одновременно на разных ядрах. Я думаю, что Linux также будет использовать информацию о том, какая физическая память ЦП хранит большую часть данных процесса, и попытается запустить процесс на этом ЦП; таким образом задержка памяти будет чуть-чуть лучше.

Если ваши процессы пытаются обмениваться данными через сокет, канал или подобное, это приводит к копированию данных из пространства памяти одного процесса в буфер памяти, контролируемый ядром. (это то, что write() делает под капотом), а затем копируется из этого в пространство памяти принимающего процесса (это то, что делает read()). Где этот промежуточный буфер ядра на самом деле не имеет значения, потому что транзакции, происходящие на уровне микроэлектроники c (ниже уровня SMP), в значительной степени одинаковы независимо. Выделение памяти и процессы могут быть связаны с указанными c ядрами ЦП, но вы не можете влиять на то, где ядро ​​помещает свои буферы памяти, через которые должны проходить обмененные данные.

Что касается памяти и сродства ядра процесса - это действительно очень трудно сделать с какой-либо ощутимой выгодой. В настоящее время ОС настолько хороши в понимании поведения процессоров, что почти всегда лучше просто позволить ОС запускать ваши процессы и ядра в любом месте по своему выбору. Такие компании, как Intel, вносят большой вклад в проект Linux, специально для того, чтобы Linux делал это как можно лучше на новейших и лучших чипах.

== РЕДАКТИРОВАТЬ == Дополнения в свете интересных комментариев!

Под "чистой NUMA" я на самом деле имею в виду системы, в которых одно ядро ​​ЦП не может напрямую адресовать память, физически подключенную к другому ядру ЦП. Такие системы включают в себя Transputers и даже процессор Cell, найденный в Sony PS3. Это не SMP, в кремнии нет ничего, что объединяет отдельные запоминающие устройства в единое адресное пространство, так что вопрос о когерентности кеша в него не входит. при подключении к другому транспортному средству прикладное программное обеспечение должно было передавать данные через последовательный канал связи; что делает его CSP тем, что отправляющее приложение завершит отправку до 1060 *, пока получающее приложение не прочитает последний байт.

Для процессора Cell было 8 математических ядер, каждое с 256 КБ ОЗУ. Это была единственная оперативная память, которую могли адресовать ядра математики. Чтобы использовать их, приложение должно было переместить данные и код в эти 256 КБ ОЗУ, указать ядру для запуска, а затем переместить результаты (возможно, обратно в ОЗУ или в другое математическое ядро).

Сегодня существуют некоторые суперкомпьютеры, которые ничем не отличаются от этого. Машина K (Рикен, Кобе в Японии) имеет очень много ядер, очень сложное внутрикристальное межсоединение fabri c, и OpenMPI используется приложениями для перемещения данных между узлами; узлы не могут напрямую обращаться к памяти на других узлах.

Дело в том, что на PS3 именно прикладное программное обеспечение решало, какие данные были в какой памяти и когда, тогда как современные реализации x86 от Intel и AMD делают все данные во всех воспоминаниях (независимо от того, являются ли они общими через кэш L3 или являются удаленными на другом конце гипертранспорта или канала QPI), доступными из любых ядер (это то, что SMP означает в конце концов).

Полная производительность кода, написанного в процессе Cell, была поразительной для количества ватт и количества транзисторов. Проблема была в мире, где программисты обучаются письму для сред SMP, для того, чтобы справиться с тем, что нет, требуется пересадка мозга.

В более новых языках, таких как Rust и Go, вновь появилась концепция передача последовательных процессов, которые все имели с Transputers еще в 1980-х, начале 1990-х. CSP почти идеально подходит для многоядерных систем, поскольку аппаратное обеспечение не требует реализации среды SMP. В принципе это экономит огромное количество кремния.

CSP, реализованный поверх современных когерентных чипов SMP в таких языках, как C, обычно включает в себя поток, записывающий данные в буфер, и который копируется в буфер, принадлежащий другому потоку (Rust может сделать это немного иначе, потому что Rust знает о владении памятью, и поэтому может передавать владение вместо копирования памяти. Я не знаком с Go - возможно, он может сделать то же самое).

Если посмотреть на уровень микроэлектроники c, копирование данных из одного буфера в другой на самом деле не отличается от того, что происходит, если данные совместно используются 2 ядрами, а не копируются (особенно в гипертранспортных процессорах AMD, где каждый имеет собственную систему памяти). Чтобы обмениваться данными, удаленное ядро ​​должно использовать гипертранспорт для запроса данных из памяти другого ядра и больше трафика c для поддержания когерентности кэша. Это примерно столько же гипертранспортного трафика c, как если бы данные копировались из одного ядра в другое, но затем нет последующего трафика когерентности кэша c.

...