Не удалось собрать данные об использовании физической памяти numa
Помогите разобраться. Есть Windows server 2012 R2. В настройках Hyper-v есть настройка на уровне хоста Allow Numa spanning - этим самым мы разрешаем использование remote access memory. То есть если у нас 2-сокетная материнка и 64 GB оперативы на оба сокета и мы не ставим эту галку то ВМ не может использовать более 32 GB так как NUMA не будет использован. Правильно?
Так вот что за настройка в Configuratuion ВМ, Processor - Numa Configuratuion?
Если можно простым языком или подробно на каком-нибудь ресурсе :)
Создание архитектуры Soft-NUMA вручную
Чтобы вручную настроить SQL Server для использования архитектуры Soft-NUMA, отключите автоматическую настройку архитектуры Soft-NUMA и добавьте в реестре маску сходства для настройки узла. Маска архитектуры Soft-NUMA в этом случае указывается как запись реестра с двоичным типом данных, типом данных DWORD (шестнадцатеричным или десятичным) или QWORD (шестнадцатеричным или десятичным). Чтобы настроить большее количество процессоров (больше чем первые 32), используйте значения реестра QWORD или BINARY. (Значения QWORD нельзя использовать до SQL Server 2012 (11.x)). Отредактировав реестр, перезапустите Компонент Database Engine, чтобы конфигурация архитектуры Soft-NUMA вступила в силу.
Нумерация процессоров начинается с 0.
Неправильное изменение реестра может вызвать серьезные проблемы. Перед внесением изменений в реестр рекомендуется создать резервную копию всех важных данных.
Рассмотрим пример компьютера с восемью ЦП, который не имеет оборудования NUMA. Настраиваются три узла программной архитектуры NUMA.
Экземпляр А компонента Компонент Database Engine настраивается для использования процессоров в количестве от 0 до 3. Второй экземпляр компонента Компонент Database Engine установлен и настроен для использования процессоров с 4 до 7. Визуально пример может быть представлен следующим образом.
CPUs 0 1 2 3 4 5 6 7
Экземпляр А, испытывающий значительную нагрузку ввода-вывода, теперь имеет два потока ввода-вывода и один поток модуля отложенной записи. Экземпляр В, выполняющий операции с интенсивным использованием процессора, имеет только один поток ввода-вывода и один поток модуля отложенной записи. Экземплярам может быть выделено различное количество памяти, но в отличие от оборудования NUMA, они оба получают память из одного блока памяти операционной системы, и здесь нет соответствия памяти и процессора.
Поток модуля отложенной записи связан с представлением физических узлов памяти NUMA в SQLOS. Поэтому любое число физических узлов NUMA, представленное оборудованием, будет равно числу создаваемых потоков модуля отложенной записи. Дополнительные сведения см. в разделе Как это работает: программная архитектура NUMA, поток завершения ввода-вывода, рабочие потоки модуля отложенной записи и узлы памяти.
Разделы реестра Soft-NUMA не копируются при обновлении экземпляра SQL Server.
Поддержка NUMA в системах с более чем 64 логическими процессорами
В системах с более чем 64 логическими процессорами узлы назначаются группам процессоров в соответствии с емкостью узлов. Емкость узла — это количество процессоров, которые присутствуют при запуске системы вместе с любыми дополнительными логическими процессорами, которые можно добавить во время работы системы.
Windows Server 2008, Windows Vista, Windows Server 2003 и Windows XP: группы процессоров не поддерживаются.
Каждый узел должен быть полностью содержится в группе. Если емкости узлов относительно малы, система назначает несколько узлов одной группе, выбирая узлы, которые физически близки друг к другу для повышения производительности. Если емкость узла превышает максимальное количество процессоров в группе, система разбивает узел на несколько небольших узлов, каждый из которых достаточно мал, чтобы поместиться в группу.
Идеальный узел NUMA для нового процесса можно запросить с помощью расширенного атрибута PROC_THREAD_ATTRIBUTE_PREFERRED_NODE при создании процесса. Как и идеальный обработчик потока, идеальный узел является указанием планировщику, который назначает новый процесс группе, содержащей запрошенный узел, если это возможно.
Расширенные функции NUMA GetNumaAvailableMemoryNodeEx, GetNumaNodeProcessorMaskEx, GetNumaProcessorNodeEx и GetNumaProximityNodeEx отличаются от их несконструированных аналогов в том, что номер узла является значением USHORT , а не UCHAR, для размещения потенциально большего числа узлов в системе с более чем 64 логическими процессорами. Кроме того, процессор, указанный расширенными функциями или извлекаемый из нее, включает группу процессоров; Процессор, указанный или извлекаемый несдернутыми функциями, является относительным к группе. Дополнительные сведения см. в справочных разделах по отдельным функциям.
Приложение, поддерживающее группу, может назначать все его потоки определенному узлу аналогично описанному выше в этом разделе с помощью соответствующих расширенных функций NUMA. Приложение использует GetLogicalProcessorInformationEx для получения списка всех процессоров в системе. Обратите внимание, что приложение не может задать маску сходства процессов, если процесс не назначен одной группе и предполагаемый узел находится в этой группе. Обычно приложение должно вызывать SetThreadGroupAffinity , чтобы ограничить его потоки предполагаемым узлом.
Установка маски схожести ЦП
Выполните следующую инструкцию в экземпляре А, чтобы настроить его для использования процессоров 0, 1, 2 и 3 путем задания маски схожести ЦП.
Выполните следующую инструкцию в экземпляре В, чтобы настроить его для использования процессоров 4, 5, 6 и 7 путем задания маски схожести ЦП.
Метаданные
Для просмотра текущего состояния и конфигурации архитектуры Soft-NUMA можно использовать указанные ниже динамические административные представления.
sp_configure (Transact-SQL): отображает текущее значение (0 или 1) для SOFTNUMA
sys.dm_os_sys_info (Transact-SQL): в столбцах softnuma_configuration и softnuma_configuration_desc показаны текущие значения конфигурации.
Можно просмотреть текущее значение для автоматического создания программной архитектуры NUMA с помощью инструкции sp_configure (Transact-SQL), но изменить это значение с помощью sp_configure невозможно. Необходимо использовать инструкцию ALTER SERVER CONFIGURATION (Transact-SQL) с аргументом SET SOFTNUMA .
Традиционная модель для поддержки нескольких процессоров является симметричным мультипроцессором (SMP). В этой модели каждый процессор имеет равный доступ к памяти и вводу-выводу. По мере добавления дополнительных процессоров шина процессора становится ограничением производительности системы.
Системные конструкторы используют неоднородный доступ к памяти (NUMA) для увеличения скорости процессора без увеличения нагрузки на шину процессора. Архитектура неоднородна, так как каждый процессор близок к некоторым частям памяти и дальше от других частей памяти. Процессор быстро получает доступ к памяти, к которому он близок, в то время как он может занять больше времени, чтобы получить доступ к памяти, которая находится дальше.
В системе NUMA процессоры располагаются в небольших системах, называемых узлами. Каждый узел имеет собственные процессоры и память, а также подключается к более крупной системе через шину, согласованную с кэшем.
Система пытается повысить производительность, запланируя потоки на процессорах, которые находятся на том же узле, что и используемая память. Он пытается удовлетворить запросы на выделение памяти из узла, но при необходимости выделяет память из других узлов. Он также предоставляет API, чтобы сделать топологию системы доступной для приложений. Вы можете повысить производительность приложений с помощью функций NUMA для оптимизации планирования и использования памяти.
Во-первых, необходимо определить макет узлов в системе. Чтобы получить самый высокий нумерованный узел в системе, используйте функцию GetNumaHighestNodeNumber . Обратите внимание, что это число не гарантируется равным общему количеству узлов в системе. Кроме того, узлы с последовательными числами не гарантированно закрываются. Чтобы получить список процессоров в системе, используйте функцию GetProcessAffinityMask . Узел для каждого процессора в списке можно определить с помощью функции GetNumaProcessorNode . Кроме того, чтобы получить список всех процессоров на узле, используйте функцию GetNumaNodeProcessorMask .
Определив, какие процессоры принадлежат к каким узлам, можно оптимизировать производительность приложения. Чтобы убедиться, что все потоки для процесса выполняются на одном узле, используйте функцию SetProcessAffinityMask с маской сходства процессов, которая указывает процессоры в одном узле. Это повышает эффективность приложений, потоки которых должны получать доступ к одной и той же памяти. Кроме того, чтобы ограничить количество потоков на каждом узле, используйте функцию SetThreadAffinityMask .
Приложения с интенсивным использованием памяти должны оптимизировать использование памяти. Чтобы получить объем свободной памяти, доступный для узла, используйте функцию GetNumaAvailableMemoryNode . Функция VirtualAllocExNuma позволяет приложению указать предпочтительный узел для выделения памяти. VirtualAllocExNuma не выделяет физические страницы, поэтому он будет успешным независимо от того, доступны ли страницы на этом узле или в другом месте системы. Физические страницы выделяются по запросу. Если предпочтительный узел заканчивается страницами, диспетчер памяти будет использовать страницы с других узлов. Если память выкачена, то при возврате в нее используется тот же процесс.
Поведение, начиная с Windows 10 сборки 20348
Начиная с Windows 10 сборки 20348, поведение этой и других функций NUMA было изменено для улучшения поддержки систем с узлами, содержащими больше 64 процессоров.
Создание "поддельных" узлов для размещения сопоставления между группами и узлами привело к путанице в ситуациях, когда сообщалось непредвиденное число узлов NUMA, и поэтому, начиная с Windows 10 сборки 20348, ОПЕРАЦИОННая система изменилась, чтобы разрешить связь нескольких групп с узлом, и поэтому теперь можно сообщить о истинной топологии NUMA системы.
В рамках этих изменений в ОС несколько API NUMA были изменены для поддержки создания отчетов о нескольких группах, которые теперь могут быть связаны с одним узлом NUMA. Обновленные и новые API помечены в таблице в разделе API NUMA ниже.
Так как удаление разбиения узлов может повлиять на существующие приложения, доступно значение реестра, позволяющее вернуться к устаревшему поведению разделения узлов. Разделение узлов можно повторно включить, создав значение REG_DWORD с именем SplitLargeNodes со значением 1 под HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\NUMA. Чтобы изменения этого параметра вступили в силу, потребуется перезагрузка.
Приложения, обновленные для использования новых функциональных возможностей API, сообщающих об истинной топологии NUMA, будут продолжать работать правильно в системах, где разделение больших узлов было повторно добавлено с помощью этого раздела реестра.
В следующем примере сначала демонстрируются потенциальные проблемы, связанные с сборками процессоров сопоставления таблиц с узлами NUMA, с помощью устаревших API-интерфейсов сходства, которые больше не обеспечивают полное покрытие всех процессоров в системе, что может привести к неполной таблице. Последствия такой неполноты зависят от содержимого таблицы. Если в таблице просто хранится соответствующий номер узла, скорее всего, это проблема с производительностью, из-за которой обнаруженные процессоры остаются в составе узла 0. Однако если таблица содержит указатели на структуру контекста для каждого узла, это может привести к разыменовкам NULL во время выполнения.
Далее в примере кода показано два обходных решения проблемы. Сначала необходимо перейти на API сопоставления узлов с несколькими группами (режим пользователя и режим ядра). Второй — использовать KeQueryLogicalProcessorRelationship для прямого запроса узла NUMA, связанного с заданным номером процессора.
Ответы
В Hyper-V на базе Windows Server 2012 и Windows Server 2012 R2 гипервизор старается по умолчанию выделить ресурсы ВМ в рамках одного NUMA-узла. В 2008 R2 это приходилось делать специально обученным скриптом.
Однако, если ресурсов требуется больше, можно задействовать обращение к памяти других сокетов. Собственно, закладка NUMA Configuration и позволяет настроить параметры обращения: к скольки сокетам можно обращаться, за каким количеством памяти. Кроме того, для виртуальной машины можно выстроить представление NUMA-узлов, скопировав его с физической архитектуры, используя кнопку.
allow numa spaning from Physical Node позволяет включить возможность "брать" память для одной из Numa Node ,используя ресурсы другой Numa Node ~ непрямой доступ к памяти. К примеру, если настроена дин.память для ВМ и ВМ требует доп.ресурсы в плане памяти, но доступного количества на ноде нет (прямого доступа) , то он использует ресуры другой numa-ноды (indirect memory access)
Processor - Numa Configuratuion = настройка архитектуры Numa на уровне ВМ ( к примеру, 2 vCPU <> 1 Numa Node <> 1 Socket)
Практически всё описано в оф.статье:
Правильно ли я понимаю, что Numa-узел это сокет и его оперативная память? Или речь идет о ядрах физического процессора? То есть на двухсокетной материнской плате 2 Numa-узла?
Если у меня два 6-ядерных процессора и на каждом включен HT, сколько Numa-узлов у меня в таком случае?
И еще не очень понятно что такое Virtual NUMA node?
Virtual Numa Node - это как раз то, что Денис отметил (Numa Configuration в св-ах ВМ). ВМ в 2012/R2 использует позволяет "копировать" архитектуры Numa ноды, на которой она находится, что позволяет более эффективно работать с CPU/memory именно на уровне ВМ, т.е. Hyper-V
Долго и упорно читаю статью которую дал Roman Levchenko, но еще больше запутался по-моему.
Есть двухсокетная материнская плата каждый процессор имеет 6 ядер и HT и 32 GB у каждого процессора, суммарная ОП = 64 GB, таким образом в настройках виртуальной машины мы можем выставить до 24 виртуальных процессоров для каждой и до 64 GB. Если зайти в настройки процессора - Numa configuration и нажать на Use hardware topology получаем ресурсы одного NUMA-узла (?) то есть 12 процессоров и 32 GB памяти. Что я сделал указав эти значения? Превысив эти значения ОС внутри ВМ будет думать, что она вышла из единной VNumaNode?
Если в настройках ВМ указать значения процессора и оперативной памяти больше чем указано в настройках NUMA для этой ВМ, вылезает предупреждение - что включена Dynamic Memory. Читаю в статье что нельзя одновременно использовать Virtual Numa и Dynamic Memory, после этого понимаю, что запутался окончательно.
по-моему достаточно доступно написано :)
упоминул в первом ответе, что использование динамики для высоконагруженных ресурсов повлечет привлечения доступной памяти из другой NUMA ноды (если включено Numa spanning), что,конечно, отразится в производительности memory/cpu. Поэтому общая рекомендация - для высокотребовательных к памяти ресурсов использовать статическую память,нежели динамику.
As a result, the NUMA spanning setting must be enabled when you have virtual machines that are large enough to be split between two or more physical NUMA nodes. If the NUMA spanning setting is disabled, the virtual machine must fit entirely within a single physical NUMA node, or the virtual machine will not start, or be restored or migrated
When trying to decide which feature to use, you should take the following questions into consideration. If the answer to both is yes, enable virtual NUMA and do not enable Dynamic Memory.
Современные процессоры имеют несколько ядер на одном сокете. Каждый сокет обычно представлен одним узлом NUMA. Ядро базы данных SQL Server секционирует разные внутренние структуры и потоки служб в узлы NUMA. Если используются процессоры с 10 и более ядрами на сокет, распределение нагрузки между аппаратными узлами NUMA с помощью программной архитектуры NUMA зачастую позволяет повысить масштабируемость и производительность системы. До SQL Server 2014 (12.x) с пакетом обновления 2 (SP2) для использования программной архитектуры NUMA (Soft-NUMA) нужно было редактировать реестр, чтобы добавить маску сходства для настройки узла. Такая настройка выполнялась на уровне узла, а не для экземпляра. Начиная с SQL Server 2014 (12.x) с пакетом обновления 2 (SP2) и SQL Server 2016 (13.x); архитектура Soft-NUMA настраивается автоматически на уровне экземпляра базы данных при запуске службы Компонент SQL Server Database Engine.
Архитектура Soft-NUMA не поддерживает процессоры с "горячей" заменой.
Автоматическое создание архитектуры Soft-NUMA
По умолчанию в SQL Server 2016 (13.x);Компонент SQL Server Database Engine автоматически создает узлы архитектуры Soft-NUMA, если во время запуска обнаруживает более восьми физических ядер на один сокет или узел NUMA. Процессорные ядра с технологией Hyper-Threading не различаются при подсчете физических ядер на узле. Если обнаружено больше восьми физических ядер на один сокет, Компонент SQL Server Database Engine создает узлы архитектуры Soft-NUMA. В идеале узлы содержат по восемь ядер, но поддерживают и другое количество: от пяти до девяти логических ядер на один узел. Размер аппаратного узла может быть ограничен маской сходства ЦП. Количество узлов NUMA не может превышать максимальное количество поддерживаемых узлов NUMA.
Использование архитектуры Soft-NUMA можно отключать и включать с помощью инструкции ALTER SERVER CONFIGURATION (Transact-SQL) с аргументом SET SOFTNUMA . Чтобы изменение этого параметра вступило в силу, потребуется перезапустить ядро базы данных.
На рисунке ниже показан пример сведений об архитектуре Soft-NUMA, которые вы увидите в журнале ошибок SQL Server, если SQL Server обнаружит аппаратные узлы NUMA с более чем восемью физическими ядрами на каждый узел или сокет.
Начиная с SQL Server 2014 (12.x) SP2 используйте флаг трассировки 8079, чтобы разрешить SQL Server использовать автоматическую программную архитектуру NUMA. Начиная с версии SQL Server 2016 (13.x); эта реакция управляется подсистемой, и флаг трассировки 8079 не оказывает влияния. Дополнительные сведения см. в разделе DBCC TRACEON — флаги трассировки.
Установка соответствия программной архитектуры NUMA нескольким процессорам
С помощью программы "Редактор реестра" (regedit.exe) добавьте приведенные ниже разделы реестра, чтобы установить соответствие между узлом 0 программной архитектуры NUMA и ЦП 0 и 1, узлом 1 программной архитектуры NUMA и ЦП 2 и 3, а также узлом 2 и ЦП 4, 5, 6 и 7.
Чтобы указать процессоры с 60 по 63, используйте значение QWORD F000000000000000 или значение BINARY 1111000000000000000000000000000000000000000000000000000000000000.
В приведенном ниже примере предположим, что имеется сервер DL580 G9 с 18 ядрами на сокет (в четырех сокетах) и каждый сокет находится в собственной K-группе. Создаваемая конфигурация программной архитектуры NUMA может быть следующей: шесть ядер на узел, три узла на группу, четыре группы.
Пример для сервера SQL Server 2016 (13.x); с несколькими K-группами | Тип | Имя значения | Данные |
---|---|---|---|
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node0 | DWORD | CPUMask | 0x3F |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node0 | DWORD | Группа | 0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node1 | DWORD | CPUMask | 0x0fc0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node1 | DWORD | Группа | 0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node2 | DWORD | CPUMask | 0x3f000 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node2 | DWORD | Группа | 0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node3 | DWORD | CPUMask | 0x3F |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node3 | DWORD | Группа | 1 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node4 | DWORD | CPUMask | 0x0fc0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node4 | DWORD | Группа | 1 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node5 | DWORD | CPUMask | 0x3f000 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node5 | DWORD | Группа | 1 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node6 | DWORD | CPUMask | 0x3F |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node6 | DWORD | Группа | 2 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node7 | DWORD | CPUMask | 0x0fc0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node7 | DWORD | Группа | 2 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node8 | DWORD | CPUMask | 0x3f000 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node8 | DWORD | Группа | 2 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node9 | DWORD | CPUMask | 0x3F |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node9 | DWORD | Группа | 3 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node10 | DWORD | CPUMask | 0x0fc0 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node10 | DWORD | Группа | 3 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node11 | DWORD | CPUMask | 0x3f000 |
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\130\NodeConfiguration\Node11 | DWORD | Группа | 3 |
NUMA API
В следующей таблице описывается API NUMA.
Компонент | Описание |
---|---|
AllocateUserPhysicalPagesNuma | Выделяет страницы физической памяти для сопоставления и отмены сопоставления в любой области расширений адресного окна (AWE) указанного процесса и указывает узел NUMA для физической памяти. |
CreateFileMappingNuma | Создает или открывает именованный или неименованный объект сопоставления файлов для указанного файла и указывает узел NUMA для физической памяти. |
GetLogicalProcessorInformation | Обновлено в Windows 10 сборке 20348. Извлекает сведения о логических процессорах и связанном оборудовании. |
GetLogicalProcessorInformationEx | Обновлено в Windows 10 сборке 20348. Извлекает сведения о связях логических процессоров и связанного оборудования. |
GetNumaAvailableMemoryNode | Извлекает объем памяти, доступный в указанном узле. |
GetNumaAvailableMemoryNodeEx | Извлекает объем памяти, доступный в узле, указанном в качестве значения USHORT . |
GetNumaHighestNodeNumber | Извлекает узел, имеющий наибольшее число. |
GetNumaNodeProcessorMask | Обновлено в Windows 10 сборке 20348. Извлекает маску процессора для указанного узла. |
GetNumaNodeProcessorMask2 | Новые возможности в Windows 10 сборки 20348. Извлекает маску процессора с несколькими группами указанного узла. |
GetNumaNodeProcessorMaskEx | Обновлено в Windows 10 сборке 20348. Извлекает маску процессора для узла, указанного в качестве значения USHORT . |
GetNumaProcessorNode | Извлекает номер узла для указанного процессора. |
GetNumaProcessorNodeEx | Извлекает номер узла в виде значения USHORT для указанного процессора. |
GetNumaProximityNode | Извлекает номер узла для указанного идентификатора близкого взаимодействия. |
GetNumaProximityNodeEx | Извлекает номер узла в виде значения USHORT для указанного идентификатора близкого взаимодействия. |
GetProcessDefaultCpuSetMasks | Новые возможности в Windows 10 сборке 20348. Извлекает список наборов ЦП в наборе по умолчанию процесса, заданном SetProcessDefaultCpuSetMasks или SetProcessDefaultCpuSets. |
GetThreadSelectedCpuSetMasks | Новые возможности в Windows 10 сборке 20348. Задает назначение выбранных наборов ЦП для указанного потока. Это назначение переопределяет назначение по умолчанию процесса, если оно задано. |
MapViewOfFileExNuma | Карты представление сопоставления файлов в адресное пространство вызывающего процесса и указывает узел NUMA для физической памяти. |
SetProcessDefaultCpuSetMasks | Новые возможности в Windows 10 сборке 20348. Задает назначение наборов ЦП по умолчанию для потоков в указанном процессе. |
SetThreadSelectedCpuSetMasks | Новые возможности в Windows 10 сборке 20348. Задает назначение выбранных наборов ЦП для указанного потока. Это назначение переопределяет назначение по умолчанию процесса, если оно задано. |
VirtualAllocExNuma | Резервирует или фиксирует область памяти в виртуальном адресном пространстве указанного процесса и задает узел NUMA для физической памяти. |
Функцию QueryWorkingSetEx можно использовать для получения узла NUMA, на котором выделена страница. Пример см. в разделе "Выделение памяти" из узла NUMA.
NUMA (Non-Uniform Memory Access — «Неравномерный доступ к памяти» или Non-Uniform Memory Architecture — «Архитектура с неравномерной памятью») — технология совсем не новая. Я бы даже сказала, что совсем старая. То есть, в терминах музыкальных инструментов, это уже даже не баян, а, скорее, варган.
Но, несмотря на это, толковых статей, объясняющих, что это, а главное, как с этим эффективно работать, нет. Данный пост, исправляющий эту ситуацию, предназначен прежде всего для тех, кто ничего не знает про NUMA, но также содержит кое-что интересное и для знатоков-NUMизматов, а главное, он облегчает жизнь мне, инженеру Intel, так как отныне всех интересующихся NUMA русскоязычных разработчиков буду отсылать к нему.
Три Богатыря
И начнем с отрицания отрицания. То есть, посмотрим на Uniform Memory Access (Однородный доступ к памяти), известный также так SMP (Symmetric Multi Processing – Симметричная Многопроцессорная Обработка).
SMP – это архитектура, в которой процессоры соединены с общей системной памятью при помощи шины или подобного соединения)симметрично, и имеют к ней равный однородный доступ. Именно так, как показано на схеме ниже (на примере двух CPU), были устроены все многопроцессорные машины Intel, когда контроллер памяти (MCH/MGCH), больше известный как «Северный Мост» (“NorthBridge”) находился в чипсете.
Недостаток SMP очевиден — при росте числа CPU, шина становится узким местом, значительно ограничивая производительность приложений, интенсивно использующих память. Именно поэтому SMP системы почти не масштабируются, два-три десятка процессоров для них – это уже теоретический предел.
Альтернатива SMP для производительных вычислений – это MPP (Massive Parallel Processing).
MPP — архитектура, разделяющая систему на многочисленные узлы, процессоры в которых имеют доступ исключительно к локальным ресурсам. MPP прекрасно масштабируется, но не столь прекрасно программируется. А именно — не обеспечивает встроенного механизма обмена данными между узлами. То есть, реализовывать коммуникации, распределение и планировку задач на узлах должен выполняемый на MPP софт, что подходит далеко не для всех задач и их программистов.
И, наконец, NUMA (Non-Uniform Memory Access). Эта архитектура объединяет положительные черты SMP и MPP. NUMA система разделяется на множественные узлы, имеющие доступ как к своей локальной памяти, так и к памяти других узлов (логично называемой «удаленной»). Естественно, доступ к удаленной памяти оказывается гораздо медленнее, чем к локальной. Оттуда и название – «неоднородный доступ к памяти». Это – не только название, но и недостаток архитектуры NUMA, для смягчения которого может потребоваться специальная оптимизация софта, о которой — дальше.
Вот как выглядит двухсокетная NUMA система Intel Xeon (а именно там дебютировала Intel NUMA) с контроллерами памяти, интегрированными в CPU.
Процессоры здесь соединены QPI — Intel QuickPath соединением «точка-точка» с высокой пропускной способностью и низкой задержкой передачи.
На рисунке не показан кеш процессоров, но все три уровня кеш памяти, конечно же, там есть. А значит, есть и особенность NUMA, о которой необходимо сказать: NUMA, используемая в системах Intel, поддерживает когерентность кешей и разделяемой памяти (то есть, соответствие данных между кешами разных CPU), поэтому ее иногда называют ccNUMA — cache coherent NUMA. Это означает наличие специального аппаратного решения для согласования содержимого кешей, а также и памяти, когда более чем один кеш хранит одну и ту же ее часть. Конечно, такое общение кешей ухудшает общую производительность системы, но без него программировать систему с непредсказуемым текущим состоянием данных было бы крайне интересно затруднительно. Для уменьшения влияния этого эффекта, следует избегать ситуаций, когда несколько процессоров сразу работают с одним блоком памяти (не обязательно с одной переменной!). Именно так и пытаются поступить продукты, поддерживающие NUMA.
Таким образом, от железа мы плавно перешли к программному обеспечению и производительности NUMA систем.
Итак, NUMA поддерживается следующими OS:
Windows Server 2003, Windows XP 64-bit и Windows Vista – до 64 логических процессоров,
Windows 7, Windows Server 2008 R2 – полная поддержка.
Linux OS kernel: 2.6 и выше, UNIX OS — Solaris и HP-Unix.
Если говорить о базах данных, то NUMA поддерживается Oracle8i, Oracle9i, Oracle10g и Oracle11g, а также SQL Server 2005 и SQL Server 2008.
Именно поэтому в BIOS мультисокетных серверов с NUMA есть специальный пункт «Разрешить\запретить NUMA». Конечно же, от запрета NUMA в BIOS топология системы никак не изменится — удаленная память не приблизится. Произойдет только следующее – система не сообщит ОС и ПО о том, что она NUMA, а значит, распределение памяти и планировка потоков будут «обычными», такими как на симметричных многопроцессорных системах.
Если BIOS разрешает NUMA, то операционная система сможет узнать о конфигурации NUMA узлов из System Resource Affinity Table (SRAT) в Advanced Configuration and Power Interface (ACPI). Приложения могут получить такую информацию, используя библиотеку libnuma в Linux, а сами понимаете, на каких системах — Windows NUMA interface.
Эта информация – начало поддержки NUMA вашим приложением. За ним должна следовать непосредственно попытка максимально эффективно использовать NUMA. Общие слова на эту тему уже сказаны, для дальнейших пояснений перейду к частному примеру.
Допустим, вы выделяете память при помощи malloc. Если дело происходит в Linux, то malloc только резервирует память, а ее физическое выделение происходит только при фактическом обращении к данной памяти. В этом случае память автоматически выделится на том узле, который ее и использует, что очень хорошо для NUMA. В Windows же malloc работает по-другому, он выделяет физическую память непосредственно при аллоцировании, то есть, на узле выделяющего память потока. Поэтому она вполне может оказаться удаленной для других потоков, ее использующих. Но есть в Windows и дружественное к NUMA выделение памяти. Это VirtualAlloc, который может работать точно также, как malloc в Linux. Еще более продвинутый вариант — VirtualAllocExNuma из Windows NUMA API.
Следующий простой пример, использующий OpenMP,
можно подружить с NUMA, обеспечив инициализацию данных каждым потоком, вызывающую соответствующую привязку физической памяти к использующему ее узлу:
Отдельным пунктом здесь надо упомянуть Affinity — принудительную привязку потоков к конкретным процессорам, предотвращающую возможную переброску операционной системой потоков между процессорами и могущую вызвать потенциальный «отрыв» потоков от своей используемой локальной памяти.
Для установки Affinity имеются соответствующие API как в Linux, так и в Windows ( стандартный Windows API, и NUMA WinAPI). Также функциональность для установки привязки присутствуют во многих параллельных библиотеках (например, в показанном выше примере OpenMP за это отвечает переменная окружения KMP_AFFINITY ).
Но надо понимать, что во-первых, affinity срабатывает не всегда (для системы это, скорее, намек, чем приказ), а во-вторых, положительный эффект от установки Affinity будет только в том случае, когда вы полностью контролируете систему, то есть, на ней работает исключительно ваше приложение, а сама ОС не сильно нагружает систему. Если же, как это чаще всего бывает, приложений несколько, причем, они интенсивно используют CPU и память, пытаясь при этом привязаться к одному процессору, ничего не зная друг о друге, да и ОС конкурирует за те же ресурсы, то от использования Affinity может быть больше вреда, чем пользы
Производительность.
А теперь самое интересное. Попробуем узнать, насколько же в реальности доступ к памяти в NUMA неоднороден, а производительность реальных приложений, соответственно, зависит от этой неоднородности.
Прежде всего, посмотрим теоретические данные. Согласно презентациям Intel, «задержка доступа к удаленной памяти ~ 1.7x доступа к локальной памяти, а пропускная способность локальной памяти может быть до двух раз больше, чем удаленной»
Данные реального сервера на Xeon 5500 приводятся в техническом описании Dell -“задержка доступа к локальной памяти составляет 70 наносекунд, к удаленной – 100 наносекунд (т.е. ~1.4 раза), пропускная способность локальной памяти превосходит удаленную на 40% ”.
На вашей реальной системе эти приблизительные данные могут быть получены при помощи бесплатной утилиты Microsoft Sysinternals — CoreInfo, оценивающей относительную «стоимость» доступа к памяти разных узлов NUMA. Результат, конечно, сильно приблизительный, но некоторые выводы сделать позовляет.
Пример результата Coreinfo:
- Использование исключительно локальной памяти (все запросы обрабатываются на первом NUMA узле, в памяти которого лежит тестовая таблица)
- Использование исключительно удаленной памяти (все запросы обрабатываются на втором узле NUMA, с использованием той же таблицы в памяти первого узла.
Как видите, разница составляет всего чуть более 5%! Результат приятно удивительный. И это – случай максимальной разницы, достигаемый при 32 одновременно работающих потоках с запросами (при другом количестве потоков разница еще меньше).
Так нужно ли оптимизировать для NUMA? Зайду издалека. Хотя у меня нет времени убираться дома, зато есть время читать советы по уборке :). И один из полезных, виденных мной советов такой — чтобы меньше убираться, надо избежать потенциального беспорядка, для чего старайтесь хранить все вещи как можно ближе к месту их использования.
Теперь замените «вещи» на «данные», а «квартиру» на «программу» и увидите один из способов достичь порядка в ваших программах. Но это как раз и будет NUMA-оптимизация, о которой вы сейчас и прочли.
Недавно в нашем блоге появилась статья о NUMA-системах, и я хотел бы продолжить тему, поделившись своим опытом работы в Linux. Сегодня я расскажу о том, что бывает, если неправильно использовать память в NUMA и как диагностировать такую проблему с помощью счётчиков производительности.
Итак, начнем с простого примера:
Это простой тест, который в цикле суммирует элементы массива. Запустим его в несколько потоков на двухсокетном сервере, у которого в каждый сокет установлен четырехядерный процессор. Ниже приведен график, на котором мы видим времена выполнения программы в зависимости от числа потоков:
Мы видим, что время выполнения на восьми потоках всего в 1.16 раза короче чем на четырех потоках, хотя при переходе с двух на четыре потока прирост производительности заметно выше. Теперь сделаем простую трансформацию кода: добавим директиву распараллеливания перед инициализацией массива:
И соберем еще раз времена выполнения:
И вот, на восьми потоках произошло улучшение производительности почти в 2 раза. Таким образом, наше приложение практически линейно масштабируется на всём диапазоне потоков.
Итак, давайте разберемся, что же произошло? Каким образом простое распараллеливание цикла инициализации привело к почти двукратному приросту? Рассмотрим устройство двухпроцессорного сервера с поддержкой NUMA:
За каждым четырёхядерным процессором закреплен определенный объем физической памяти, с которым он общается через интегрированный контроллер памяти и шину данных. Такая связка процессор + память называется узел или нода (node). В NUMA-системах (Non Uniform Memory Access) доступ в память чужой ноды занимает намного больше времени, чем доступ в память своей ноды. Когда приложение в первый раз обращается к памяти, то происходит закрепление виртуальных страниц памяти за физическими. Но в NUMA-системах под управлением ОС Linux у этого процесса есть своя специфика: физические страницы, за которыми будут закреплены виртуальные, выделяются на той ноде, с которой произошло первое обращение. Это так называемый “first-touch policy”. Т.е. если с первой ноды произошло обращение к какой либо памяти, то виртуальные страницы этой памяти будут отображаться на физические, которые тоже будут выделены на первой ноде. Поэтому здесь важно правильно инициализировать данные, ведь от того как данные закрепятся за нодами будет зависеть производительность приложения. Если говорить о первом примере, то весь массив был проинициализирован на одной ноде, что привело к закреплению всех данных за первой нодой, после чего половина этого массива была считана другой нодой, а это и привело к ухудшению производительности.
Внимательный читатель должен был уже задаться вопросом «А разве выделение памяти через malloc не является первым доступом?». Конкретно в этом случае – нет. Дело вот в чем: при выделении больших блоков памяти в Linux, функция glibc malloc (а также calloc и realloc) по умолчанию вызывает сервисную функцию ядра mmap. Эта сервисная функция делает лишь отметки о количестве выделенной памяти, но физическое выделение происходит только при первом доступе к ним. Этот механизм реализуется через прерывания (exceptions) Page-Fault и Copy-On-Write, а также через маппирование на «нулевую» страницу (“zero” page). Кому интересны детали, могут почитать книгу «Understanding the Linux Kernel». А вообще, возможна ситуация, когда функция glibc calloc выполнит первый доступ к памяти для того, чтобы её «занулить». Но опять же, такое произойдет, если calloc решит вернуть пользователю ранее освобожденную память на куче (heap), а такая память уже будет существовать на физических страницах. Поэтому во избежании лишних головоломок рекомендуется использовать так называемые NUMA-aware менеджеры памяти (например TCMalloc), но это уже другая тема.
А теперь давайте ответим на главный вопрос этой статьи: «Как узнать правильно ли приложение работает с памятью в NUMA-системе?». Этот вопрос будет для нас всегда самым первым и главным при адаптации приложений для серверов с поддержкой NUMA, независимо от операционной системы.
Для ответа на этот вопрос нам понадобится VTune Amplifier, который умеет считать события для двух счётчиков производительности (performance counters): OFFCORE_RESPONSE_0.ANY_REQUEST.LOCAL_DRAM и OFFCORE_RESPONSE_0.ANY_REQUEST.REMOTE_DRAM. Первый счётчик считает количество всех запросов, данные для которых были найдены в оперативной памяти своей ноды, а второй – в памяти чужой ноды. Можно на всякий случай еще собрать счётчики для КЭШ’а: OFFCORE_RESPONSE_0.ANY_REQUEST.LOCAL_CACHE и OFFCORE_RESPONSE_0.ANY_REQUEST.REMOTE_CACHE. Вдруг окажется что данные находятся не в памяти, а в КЭШ’е процессора на чужой ноде?
Итак, запустим наше приложение без распараллеливания инициализации на восемь потоков под VTune и посчитаем количество событий для указанных выше счетчиков:
Мы видим, что поток, выполнявшийся на cpu 0, работал в основном со своей нодой. Хотя время от времени модуль vmlinux на этом ядре зачем-то заглядывал в чужие ноды. А вот поток на cpu 1, делал всё наоборот: только для 0.13% всех запросов данные нашлись в его собственной ноде. Здесь я должен пояснить, каким образом ядра закреплены за нодами. Ядра 0,2,4,6 принадлежат первой ноде, а ядра 1,3,5,7 – второй. Топологию можно узнать с помощью утилиты numactl:
numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6
node 0 size: 12277 MB
node 0 free: 10853 MB
node 1 cpus: 1 3 5 7
node 1 size: 12287 MB
node 1 free: 11386 MB
node distances:
node 0 1
0: 10 20
1: 20 10
Обратите внимание, что здесь перечислены логические номера, в реальности же ядра 0,2,4,6 принадлежат одному четырехядерному процессору, а ядра 1,3,5,7 – другому.
Теперь посмотрим на значение счетчиков для примера с параллельной инициализации:
Картина почти идеальная, мы видим, что все ядра работают в основном со своими нодами. Обращения в чужие ноды, составляют не больше полпроцента от всех запросов, за исключением cpu 6. Это ядро примерно 4.5% всех запросов отправляет в чужую ноду. Т.к. обращение в чужую ноду занимает в 2 раза дольше времени чем в свою, то 4.5% таких запросов не сильно ухудшают производительность. Поэтому, можно сказать, что теперь приложение правильно работает с памятью.
Таким образом, используя эти счётчики вы всегда можете определить есть ли возможность ускорить приложение для NUMA-системы. На практике у меня были случаи когда правильная инициализация данных ускоряла приложения в 2 раза, причем в некоторых приложениях приходилось параллелить все циклы, немного ухудшая производительность для обычной SMP-системы.
Вот так формируется счётчик OFFCORE_RESPONSE_0 в процессоре Nehalem:
Для того чтобы понять кто именно отправляет свои запросы в чужую ноду нужно разложить ANY_REQUEST на составные запросы: DEMAND_DATA_RD, DEMAND_RFO, DEMAND_IFETCH, COREWB, PF_DATA_RD, PF_RFO, PF_IFETCH, OTHER и собрать для них события по отдельности. Таким образом «виновник» был найден:
OFFCORE_RESPONSE_0.PREFETCH.REMOTE_DRAM
cpu 0: 6405
cpu 1: 597190
cpu 2: 2503
cpu 3: 229271
cpu 4: 2035
cpu 5: 190549
cpu 6: 19364266
cpu 7: 228027
Но почему prefetcher именно на 6 ядре заглядывал в чужую ноду, в то время как prefetcher’ы остальных ядер работали со своими нодами? Дело в том, что перед запуском примера с параллельной инициализацией, я дополнительно установил жесткую привязку потоков к ядрам следующим образом:
Согласно этой привязке первые четыре потока работают на первой ноде, а вторые четыре потока – на второй. Отсюда видно, что 6-ое ядро – это последнее ядро принадлежащее первой ноде (0,2,4,6). Обычно prefetcher всегда пытается закачать память с упреждением, которая находится далеко впереди (или позади, зависит от направления, в котором программа обращается к памяти). В нашем случае prefetcher шестого ядра закачивал память, которая находилась впереди той, с которой в тот момент работал поток Internal thread 3. Вот здесь то и произошло обращение в чужую ноду, так как впереди стоящая память частично принадлежала первому ядру чужой ноды (1,3,5,7). А это и привело к появлению 4.5% обращений в чужую ноду.
Замечание: тестовая программа была собрана компилятором Intel с опцией –no-vec, чтобы получить скалярный код вместо векторного. Это было сделано с целью получения «красивых данных» для облегчения понимания теории.
Ответы
В Hyper-V на базе Windows Server 2012 и Windows Server 2012 R2 гипервизор старается по умолчанию выделить ресурсы ВМ в рамках одного NUMA-узла. В 2008 R2 это приходилось делать специально обученным скриптом.
Однако, если ресурсов требуется больше, можно задействовать обращение к памяти других сокетов. Собственно, закладка NUMA Configuration и позволяет настроить параметры обращения: к скольки сокетам можно обращаться, за каким количеством памяти. Кроме того, для виртуальной машины можно выстроить представление NUMA-узлов, скопировав его с физической архитектуры, используя кнопку.
allow numa spaning from Physical Node позволяет включить возможность "брать" память для одной из Numa Node ,используя ресурсы другой Numa Node ~ непрямой доступ к памяти. К примеру, если настроена дин.память для ВМ и ВМ требует доп.ресурсы в плане памяти, но доступного количества на ноде нет (прямого доступа) , то он использует ресуры другой numa-ноды (indirect memory access)
Processor - Numa Configuratuion = настройка архитектуры Numa на уровне ВМ ( к примеру, 2 vCPU <> 1 Numa Node <> 1 Socket)
Практически всё описано в оф.статье:
Правильно ли я понимаю, что Numa-узел это сокет и его оперативная память? Или речь идет о ядрах физического процессора? То есть на двухсокетной материнской плате 2 Numa-узла?
Если у меня два 6-ядерных процессора и на каждом включен HT, сколько Numa-узлов у меня в таком случае?
И еще не очень понятно что такое Virtual NUMA node?
Virtual Numa Node - это как раз то, что Денис отметил (Numa Configuration в св-ах ВМ). ВМ в 2012/R2 использует позволяет "копировать" архитектуры Numa ноды, на которой она находится, что позволяет более эффективно работать с CPU/memory именно на уровне ВМ, т.е. Hyper-V
Долго и упорно читаю статью которую дал Roman Levchenko, но еще больше запутался по-моему.
Есть двухсокетная материнская плата каждый процессор имеет 6 ядер и HT и 32 GB у каждого процессора, суммарная ОП = 64 GB, таким образом в настройках виртуальной машины мы можем выставить до 24 виртуальных процессоров для каждой и до 64 GB. Если зайти в настройки процессора - Numa configuration и нажать на Use hardware topology получаем ресурсы одного NUMA-узла (?) то есть 12 процессоров и 32 GB памяти. Что я сделал указав эти значения? Превысив эти значения ОС внутри ВМ будет думать, что она вышла из единной VNumaNode?
Если в настройках ВМ указать значения процессора и оперативной памяти больше чем указано в настройках NUMA для этой ВМ, вылезает предупреждение - что включена Dynamic Memory. Читаю в статье что нельзя одновременно использовать Virtual Numa и Dynamic Memory, после этого понимаю, что запутался окончательно.
по-моему достаточно доступно написано :)
упоминул в первом ответе, что использование динамики для высоконагруженных ресурсов повлечет привлечения доступной памяти из другой NUMA ноды (если включено Numa spanning), что,конечно, отразится в производительности memory/cpu. Поэтому общая рекомендация - для высокотребовательных к памяти ресурсов использовать статическую память,нежели динамику.
As a result, the NUMA spanning setting must be enabled when you have virtual machines that are large enough to be split between two or more physical NUMA nodes. If the NUMA spanning setting is disabled, the virtual machine must fit entirely within a single physical NUMA node, or the virtual machine will not start, or be restored or migrated
When trying to decide which feature to use, you should take the following questions into consideration. If the answer to both is yes, enable virtual NUMA and do not enable Dynamic Memory.
Современные процессоры имеют несколько ядер на одном сокете. Каждый сокет обычно представлен одним узлом NUMA. Ядро базы данных SQL Server секционирует разные внутренние структуры и потоки служб в узлы NUMA. Если используются процессоры с 10 и более ядрами на сокет, распределение нагрузки между аппаратными узлами NUMA с помощью программной архитектуры NUMA зачастую позволяет повысить масштабируемость и производительность системы. До SQL Server 2014 (12.x) с пакетом обновления 2 (SP2) для использования программной архитектуры NUMA (Soft-NUMA) нужно было редактировать реестр, чтобы добавить маску сходства для настройки узла. Такая настройка выполнялась на уровне узла, а не для экземпляра. Начиная с SQL Server 2014 (12.x) с пакетом обновления 2 (SP2) и SQL Server 2016 (13.x); архитектура Soft-NUMA настраивается автоматически на уровне экземпляра базы данных при запуске службы Компонент SQL Server Database Engine.
Архитектура Soft-NUMA не поддерживает процессоры с "горячей" заменой.
Читайте также: