Main menu

Векторизация вычислений (SIMD): аппаратное ускорение численных алгоритмов

Когда закон Мура перестает ускорять код

На протяжении десятилетий программисты и математики привыкли к простому правилу: чтобы программа для численного интегрирования или умножения матриц заработала быстрее, нужно просто подождать пару лет, пока Intel или AMD выпустят процессор с более высокой тактовой частотой. Этот феномен, подпитываемый законом Мура, позволял писать неоптимальный код и все равно получать рост производительности. Однако в начале 2000-х годов рост тактовых частот уперся в непреодолимый физический барьер — тепловой предел кремниевых чипов (частота застыла на уровне 3-5 ГГц). Чтобы продолжать наращивать вычислительную мощь, создателям процессоров пришлось менять архитектуру, внедряя многоядерность и, что еще более важно для математики, векторные инструкции.

Концепция SIMD (Single Instruction, Multiple Data — одна инструкция, множество данных) является фундаментом высокопроизводительных вычислений (HPC). В классической, скалярной модели процессора (SISD), чтобы сложить два массива из четырех чисел (A1+B1, A2+B2, A3+B3, A4+B4), процессору нужно выполнить цикл: загрузить два числа, сложить их, записать результат, и повторить это 4 раза. Архитектура SIMD внедряет в процессор сверхширокие регистры. Загрузив сразу 4 числа из массива A в один 256-битный регистр, и 4 числа из массива B во второй регистр, процессор за один единственный такт времени выполняет сложение сразу всех четырех пар чисел одновременно! Это обеспечивает мгновенный 4-кратный (или даже 8-кратный) прирост чистой математической производительности.

Наборы инструкций AVX и выравнивание памяти

Современные процессоры оснащены мощнейшими блоками векторной математики. Инструкции SSE (128 бит) позволяют складывать 4 числа типа float за такт. Инструкции AVX и AVX2 (256 бит) удваивают этот показатель до 8 чисел. Новейшие серверные процессоры с инструкциями AVX-512 оперируют колоссальными 512-битными регистрами, выполняя по 16 операций сложения или умножения 32-битных чисел с плавающей запятой за один микроскопический такт процессора. Более того, существует специальная инструкция FMA (Fused Multiply-Add), которая за один такт выполняет сразу две операции (A * B + C), удваивая пиковую производительность алгоритма матричного умножения.

Но эта фантастическая аппаратная мощь недоступна программам автоматически. Чтобы векторные блоки заработали, данные в оперативной памяти компьютера должны быть расположены (упакованы) строго последовательно, без разрывов, и желательно быть выровненными (aligned) по границам 32-байтовых или 64-байтовых кеш-линий. Если вы написали алгоритм метода конечных разностей, который скачет по памяти (собирая данные из разных классов или объектов), процессор просто не сможет загрузить их широким вектором. Он откатится к медленным скалярным вычислениям (потеряв до 90% скорости).

Компиляторы, раскрутка циклов и библиотеки BLAS

Чтобы заставить численный код летать, разработчики применяют агрессивную раскрутку циклов (Loop Unrolling) и прагмы для компиляторов (например, #pragma omp simd в OpenMP). Важнейшим требованием для векторизации является отсутствие логических ветвлений (операторов if/else) внутри тяжелого математического цикла, так как ветвление разрушает векторный конвейер.

В мире профессиональной вычислительной математики никто не пишет циклы умножения матриц вручную. Вся базовая алгебра (нахождение скалярных произведений, умножение матрицы на вектор, разложение матриц) делегируется стандартизированным библиотекам BLAS (Basic Linear Algebra Subprograms) и LAPACK. Такие реализации, как Intel MKL (Math Kernel Library) или OpenBLAS, написаны на глубоком ассемблерном уровне. Они досконально учитывают размер L1/L2 кэша процессора и микроархитектуру AVX регистров, нарезая матрицы на микро-блоки. Именно благодаря идеальной SIMD-векторизации внутри библиотек BLAS, скрипты на языке Python (использующие NumPy) умудряются работать со скоростью скомпилированного языка C++ при решении гигантских систем дифференциальных уравнений.

Подробнее

Ускорение граничных элементов: Быстрый мультипольный метод (FMBEM)

Преодоление барьера плотных матриц в акустике и электродинамике

Метод граничных элементов (МГЭ, или BEM) обладает колоссальным преимуществом перед объемными методами: он снижает размерность физической задачи на единицу. Для расчета распределения электромагнитного поля вокруг огромного самолета инженеру нужно покрыть сеткой только поверхность обшивки фюзеляжа, а не кубические километры окружающего пространства. Однако за это математическое изящество приходится платить суровую цену. Переход к поверхностным интегральным уравнениям порождает систему линейных алгебраических уравнений (СЛАУ), матрица которой является плотной (dense). Она заполнена ненулевыми элементами на 100%, потому что каждая точка (заряд) на поверхности самолета непрерывно взаимодействует со всеми остальными точками посредством закона Кулона.

Для сетки всего из 100 000 элементов матрица потребует около 80 гигабайт оперативной памяти для хранения и колоссального количества процессорного времени (порядка O(N^2) операций для умножения на вектор и O(N^3) для прямого решения методом Гаусса). Это означает, что классический МГЭ упирается в «стеклянный потолок» размерности: попытка решить задачу для детализированной сетки современного подводного корабля или антенной решетки из миллионов элементов становится математически невозможной даже для самых мощных суперкомпьютеров министерства обороны.

Интеграция с Быстрым мультипольным методом (FMM)

Спасением для метода граничных элементов стала его интеграция с революционным Быстрым преобразованием мультиполей (Fast Multipole Method, FMM), разработанным Владимиром Рохлиным. Этот синтез получил название Быстрого мультипольного метода граничных элементов (Fast Multipole Boundary Element Method, FMBEM). Идея алгоритма основана на строгом математическом факте: влияние группы далеких источников (точек на поверхности) на приемник можно сгруппировать и заменить одним эквивалентным источником, используя разложение фундаментального решения (функции Грина) в ряды по сферическим гармоникам.

С вычислительной точки зрения алгоритм FMBEM полностью отказывается от сборки и хранения в памяти плотной глобальной матрицы. Алгоритм строит иерархическое дерево кубических ячеек (Octree), заключающее в себе всю поверхность модели. Если два элемента сетки находятся в соседних, близких ячейках, их взаимное влияние вычисляется точно, прямым интегрированием функций формы, и эти матричные коэффициенты образуют сильно разреженную локальную матрицу (ближнее поле). Если же элементы находятся в далеких ячейках (дальнее поле), матричные элементы не вычисляются вообще!

Мультипольные разложения и ускорение до O(N log N)

Вместо матричного умножения для дальнего поля алгоритм вычисляет мультипольные моменты ячеек нижнего уровня, сдвигает (транслирует) их центры в ячейки верхнего уровня (идя по дереву снизу вверх), затем переводит мультипольные разложения в локальные разложения (преобразование M2L), и, наконец, распределяет эти локальные поля обратно на конкретные узлы сетки приемника (идя по дереву сверху вниз). Звучит как сложнейшая математическая эквилибристика, но она выполняется компьютерами с феноменальной скоростью.

Использование FMM в качестве способа быстрого умножения плотной матрицы на вектор позволяет применять итерационные методы подпространств Крылова (например, GMRES). В результате вычислительная сложность и затраты оперативной памяти радикально падают с O(N^2) до O(N log N) или даже O(N). Это технологический прорыв колоссального масштаба: сегодня коммерческие FMBEM солверы позволяют моделировать рассеяние акустических волн на турбинах подводных лодок, используя сетки из 10-50 миллионов узлов, решая задачи, которые еще 20 лет назад считались абсолютно нерешаемыми в вычислительной акустике.

Подробнее

Разрывный метод Галеркина (DG): точные скачки в вычислительной гидродинамике

Когда непрерывность становится помехой

Классический метод конечных элементов (МКЭ) десятилетиями является непререкаемым стандартом в задачах строительной механики и теории упругости. Его успех базируется на использовании непрерывных базисных функций. Для расчета прогиба балки непрерывность перемещений между конечными элементами — это строгий физический закон. Однако при попытке применить этот же непрерывный базис к задачам газовой динамики, гиперболическим законам сохранения и расчету сверхзвуковых течений классический МКЭ потерпел катастрофическое фиаско. Причина кроется в природе самих физических явлений: сверхзвуковые потоки порождают ударные волны (скачки уплотнения), которые с математической точки зрения представляют собой строгие разрывы плотности и давления. Непрерывные полиномы МКЭ просто не могут адекватно описать разрыв функции; при попытке это сделать они генерируют гигантские нефизичные осцилляции по всей расчетной области, полностью разрушая вычислительный процесс.

Для решения этой фундаментальной проблемы математики Рид и Хилл в 1973 году (а позже Кокберн и Шу в 1980-х) разработали Разрывный метод Галеркина (Discontinuous Galerkin Method, DGM). Этот алгоритм представляет собой элегантный синтез двух миров: он берет теоретическую строгость и высокую точность полиномиальных аппроксимаций из метода конечных элементов и объединяет их с физически корректной обработкой ударных волн, заимствованной из метода конечных объемов (МКО).

Локальная база и численные потоки на границах

В методе DG расчетная область точно так же разбивается на элементы (тетраэдры или гексаэдры). Искомая функция внутри каждого элемента аппроксимируется полиномом высокой степени (как в спектральных элементах). Но главное и революционное отличие заключается в том, что мы больше не требуем непрерывности (сшивки) этих полиномов при переходе через границу от одного элемента к другому! На общей грани двух соседних кубиков функция имеет право иметь два совершенно разных значения. Вычислительные элементы становятся математически независимыми островами.

Но как эти острова обмениваются физической информацией (массой, энергией)? Здесь вступает в игру математический аппарат метода конечных объемов. При интегрировании по частям в слабой формулировке Галеркина возникают контурные интегралы по границам элементов. В эти интегралы подставляются так называемые «численные потоки» (Numerical Fluxes) — например, потоки Роу (Roe) или HLLC, которые получаются путем точного или приближенного решения локальной задачи Римана о распаде разрыва между соседними элементами. Этот поток действует как клей, который обеспечивает строгий закон сохранения массы и энергии во всей глобальной системе, при этом допуская наличие резких физических скачков прямо на границах ячеек.

Матрицы масс и метод Рунге-Кутты (RKDG)

Поскольку базисные функции жестко локализованы внутри каждого элемента и не перекрываются с соседями, глобальная матрица масс системы перестает существовать в привычном виде. Она распадается на множество крошечных блочно-диагональных матриц (размером с полиномиальный базис одного элемента). Эту маленькую матрицу можно обратить аналитически один раз до начала расчетов. В результате мы получаем чисто явную дифференциальную схему по времени, которая вообще не требует решения гигантских СЛАУ на каждом шаге!

Для интегрирования по времени используются специальные TVD (Total Variation Diminishing) методы Рунге-Кутты, которые математически гарантируют невозрастание ложных осцилляций. В сочетании с ограничителями наклона (Slope limiters), которые принудительно «срезают» возникающие локальные пики возле ударных волн, метод RKDG позволяет моделировать аэродинамику гиперзвуковых ракет, детонацию взрывчатых веществ и акустические шумы турбин с невероятной точностью (сходимость 4-го, 5-го и более высоких порядков) на совершенно неструктурированных сетках, обеспечивая идеальную масштабируемость на графических ускорителях (GPU).

Подробнее

Соц. сети