По ту сторону NUMA API

По ту сторону NUMA API

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

Итак, при включении ком­пью­те­ра, пос­ле за­вер­ше­ния про­це­ду­ры BIOS POST, в ре­зуль­та­те ини­ци­а­ли­за­ции кар­ти­ру­ю­щей ло­ги­ки, все мо­ду­ли DIMM мно­го­про­цес­сор­ной плат­фор­мы, сгруп­пи­ро­ва­ны по ка­на­лам и раз­ме­ще­ны в еди­ном и ог­ром­ном 64-бит­ном фи­зи­че­ском ад­рес­ном про­ст­ран­стве. Каж­дый из кон­т­рол­ле­ров па­мя­ти по­лу­чил свой ад­рес­ный ди­а­па­зон. Пос­ле за­груз­ки ОС, ме­ха­низ­мы вир­ту­аль­ной па­мя­ти и стра­нич­ной тран­сля­ции скры­ва­ют от прик­лад­но­го про­грам­мно­го обес­пе­че­ния фраг­мен­ти­ро­ва­ние фи­зи­че­ских ре­сур­сов. Ка­за­лось бы, сис­те­ма пол­но­стью проз­рач­на, и про­г­рам­мис­ту не нуж­но за­ду­мы­вать­ся над тем, к ка­ко­му про­цес­со­ру под­клю­че­на ис­поль­зу­е­мая па­мять.

В чем проблема?

Нетрудно понять, что для каждого из процессоров, доступ к собственной памяти осуществляется быстрее, чем к па­мя­ти, обслуживаемой соседним процессором, так как во втором случае информация должна пройти по шинам меж­про­цес­сор­ной связи. Именно поэтому, такая архитектура получила название NUMA или Non-Uniform Memory Access, что в переводе означает система с неоднородным доступом к памяти.

NUMA API

Очевидно, производительность платформы будет максимальной, если для параллельно работающих программных по­то­ков, информация, интенсивно используемая каждым потоком будет размещена в памяти, подключенной к про­цес­со­ру, на котором выполняется данный поток. Для оптимизации программного обеспечения с учетом специфики NUMA, в сре­де опе­ра­ци­он­ных систем Windows предусмотрены специальные функции, заменяющие либо дополняющие классический набор функций управления памятью.

Для выделения памяти предусмотрена функция VirtualAllocExNuma, которая одним из входных параметров при­ни­ма­ет номер узла (фактически процессорного сокета или физического процессора), на котором следует выделить память, поскольку, этот узел будет интенсивно использовать вы­де­ля­е­мый ди­а­па­зо­н.

При выполнении каждого программного потока может быть вызвана функция SetThreadAffinityMask, задающая 64-битный вектор в котором каждому из 64 возможных логических процессоров соответствует 0 (если потоку не ре­ко­мен­ду­ет­ся использовать этот процессор) или 1 (если потоку рекомендуется использовать этот процессор). Векторы дол­ж­ны быть сформированы таким образом, чтобы каждый из потоков использовал логические процессоры, вхо­дя­щие толь­ко в тот узел, с которым ассоциирован диапазон памяти, используемый этим потоком, ранее вы­де­лен­ный фун­к­ци­ей VirtualAllocExNuma.

Для платформ, содержащих более 64 логических процессоров, требуется специальная поддержка. Такие системы разделяются на группы (Processor Groups), при этом в каждой группе может быть не более 64 процессоров. Ранее на­пи­сан­ное программное обеспечение, не поддерживающее процессорные группы, сможет использовать только под­мно­же­ство процессоров, принадлежащих одной группе.

При этом важно понимать, что указания, которые мы даем операционной системе используя NUMA API, носят не обя­за­тель­ный, а рекомендательный характер, поскольку игнорирование этих указаний операционной системой при­ве­дет не к сбою выполнения программы, а только некоторому замедлению. Например, если мы запрашиваем выделение памяти, ассоциированной с узлом 0, а вся память узла 0 занята, то операционной системой будет выделена память, не ассоциированная с узлом 0. При этом несколько упадет скорость, но программа сохранит работоспособность.

ACPI System Resource Affinity Table

Рассмотренные выше функции NUMA API обеспечивают взаимодействие операционной системы и NUMA-оп­ти­ми­зи­ро­ван­но­го приложения. Опустимся на ступеньку ниже в иерархии программных интерфейсов и рассмотрим механизм передачи топологической информации от Firmware платформы к ОС. Для этого, в рамках интерфейса ACPI (Advanced Configuration and Power Interface) предусмотрена специальная таблица SRAT (System Resource Affinity Table или, по другой версии Static Resource Affinity Table). Платформа представляется в виде набора узлов или доменов (proximity domains).

С аппаратной точки зрения, домен - это совокупность физического процессора (сокета) и подключенной к нему под­сис­те­мы памяти. При этом физический процессор, в силу использования многоядерности и технологии Hyper-Threading может содержать группу логических процессоров. В свою очередь, каждый контроллер оперативной памяти пред­ос­тав­ля­ет диапазон или группу диапазонов адресного пространства, обеспечивающих доступ к памяти.

С программной точки зрения, в каждый домен входит группа логических процессоров и группа диапазонов адресного пространства.

Заголовок таблицы System Resources Affinity Table (SRAT)

Рис.1Заголовок таблицы System Resources Affinity Table (SRAT)

 
Элемент таблицы SRAT — Processor Affinity Structure, структура, декларирующая принадлежность заданного логического процессора к заданному доменуРис.2Элемент таблицы SRAT — Processor Affinity Structure, структура, декларирующая принадлежность заданного логического процессора к заданному домену. Логические процессоры адресуются идентификатором Local APIC ID, по таким же правилам, как при межпроцессорном взаимодействии посредством подсистемы APIC (Advanced Programmable Interrupt Controller)
 
Элемент таблицы SRAT — Memory Affinity Structure, структура, декларирующая принадлежность заданного диапазона памяти к заданному доменуРис.3Элемент таблицы SRAT — Memory Affinity Structure, структура, декларирующая принадлежность заданного диапазона памяти к заданному домену

Пример

Рассмотрим содержимое ACPI-таблицы System Resource Affinity Table (SRAT) на типовой двух­про­цес­сор­ной плат­фор­ме, оснащенной 64 гигабайтами оперативной памяти. Для этого нам потребовалось написать небольшую утилиту dump.ACPI.SRAT, обеспечивающую доступ к структурам Firmware из среды Win64.
 

амп ACPI-таблицы SRAT, полученный на типовой двухпроцессорной платформе с суммарным объемом оперативной памяти 64 гигабайта


Рис.4Дамп ACPI-таблицы SRAT, полученный на типовой двухпроцессорной платформе с суммарным объемом оперативной памяти 64 гигабайта


Текстовый файл дампа содержит шестнадцатеричный дамп ACPI-таблицы SRAT, а файл расшифровки — результат анализа ее со­дер­жи­мо­го. Как и ожидалось, декларировано два домена, по количеству процессорных сокетов. Каждый из доменов содержит 16 логических процессоров. В адресации оперативной памяти наблюдается асимметрия, об­ус­лов­лен­ная стрем­ле­ни­ем разработчиков разместить memory-mapped I/O ресурсы периферийных устройств ниже границы 4GB, для того, чтобы сделать их доступными 32-битным операционным системам. Вряд ли кому-то придет в голову использовать такие системы на данной платформе, но традиция должна быть соблюдена. 32 гигабайта домена 0 доступны виде двух фрагментов (0-2 GB и 4-34 GB). 32 гигабайта домена 1 доступны в диапазоне 34-66 GB. «Дырка» в диапазоне 2-4GB необходима для доступа 32-битных операционных систем к memory-mapped I/O. Заметим, что 32-битные ОС не могут адресовать память второго процессора (домена 1), но могут его использовать, размещая код и данные в памяти, подключенной к первому процессору (домену 0).

Вместе с тем, 32-битные приложения, работающие в среде 64-битной ОС, лишены указанных неудобств, так как ме­ха­низм трансляции страниц в режиме PAE (Physical Address Extension) позволяет отобразить любую страницу 32-битного виртуального адресного про­стран­ст­ва приложения на любую страницу 64-битного физического адресного про­ст­ран­ст­ва платформы. То же самое справедливо для 32-битных гостевых ОС, запущенных с применением 64-битных средств аппаратной виртуализации.

Современные тенденции

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

Исследование производительности оперативной памяти с помощью утилиты NCRB. Односокетная система на основе AMD EPYC 7351

Рис. 5. Исследование производительности оперативной памяти с помощью утилиты NCRB. Односокетная система на основе AMD EPYC 7351

В примере (Рис 5.) 256-битное AVX-чтение выполняется одним потоком, демонстрируя скорость около 21.2 GBPS, близ­кую к показателям двух каналов одного NUMA-домена. Заметим, в исследуемой платформе четыре NUMA-домена, поэтому общее количество каналов памяти равно 8.

Итак, согласно информации, полученной в результате анализа содержимого таблицы ACPI SRAT (красный пря­мо­у­голь­ник на Рис 5), серверная платформа на основе одного процессора AMD EPYC 7351 содержит в общей слож­но­сти 32 логических процессора (CPUs=32), распределенных по четырем NUMA-доменам (Domains=4), по числу крис­тал­лов многочиповой конструкции. Количество декларируемых диапазонов памяти (RAMs=6), превышает ко­ли­че­ство до­ме­нов, в силу фрагментации адресного пространства, обусловленной созданием диапазонов совместимости в пределах нижних 4 гигабайт. Такие диапазоны делают возможной 32-битную адресацию memory-mapped ресурсов. Здесь проявилась инерционность разработчиков UEFI firmware, ведь использование 32-битных ОС на платформе с указанным процессором, мягко говоря, не целесообразно.

Топологическая информация, декларируемая NUMA API операционной системы (зеленый прямоугольник на Рис 5), позволяет выделить группы логических процессоров. Переведя в двоичный код содержимое Affinity-масок и выделяя группы битов, установленных в «1», нетрудно определить подмножества логических процессоров, от­но­ся­щих­ся к каждому из NUMA-доменов.

node 0, mask = 00000000000000FFh, processors [7-0]
node 1, 000000000000FF00h, processors [15-8]
node 2, 0000000000FF0000h, processors [23-16]
node 3, 00000000FF000000h, processors [31-24]

Отметим, что количество доменов, декларируемых операционной системой (NUMA Nodes=8) удвоено в сравнении с информацией, предоставляемой firmware платформы посредством ACPI (Domains=4). Предположительно, наличие неиспользуемых доменов является результатом предпринятой унификации, усложняющей упрощающей отладку и оптимизацию программного обеспечения для односокетных и двухсокетных платформ.

Резюме

Увы, любое равноправие иллюзорно. И в жизни, и в обществе, и в мультипроцессорной системе. Неоднородность до­сту­па к ресурсам в современной платформе требует специальной оптимизации программного обеспечения на уров­не Firmware, ОС и приложений.