Введение

Тип параллельной обработки

Одноинструкционная, множественная обработка данных (SIMD) — это тип параллельной обработки в таксономии Флинна. SIMD может быть реализован аппаратно (как часть конструкции оборудования) и быть доступным через архитектуру набора команд (ISA), однако его не следует путать с самой ISA. SIMD описывает компьютеры с несколькими вычислительными элементами, которые одновременно выполняют одну и ту же операцию над множеством точек данных. Такие машины используют параллелизм на уровне данных, но не параллелизм задач: вычисления происходят одновременно (параллельно), но каждый элемент в любой момент времени выполняет одну и ту же инструкцию (с разными данными). SIMD особенно эффективен для типовых задач, таких как регулировка контрастности цифрового изображения или громкости цифрового аудио. Большинство современных конструкций центральных процессоров (CPU) включают SIMD-инструкции для повышения производительности при работе с мультимедиа. В таксономии Флинна 1972 года SIMD имеет три различных подкатегории, одна из которых — SIMT. SIMT не следует путать с программными или аппаратными потоками, которые представляют собой разделение времени процессора между задачами. SIMT — это истинное одновременное параллельное выполнение на аппаратном уровне. Современные графические процессоры (GPU) часто представляют собой широкие SIMD-реализации, способные выполнять операции ветвления, загрузки и сохранения данных блоками по 128 или 256 бит.

История

Первое использование SIMD-инструкций было в ILLIAC IV, который был завершен в 1966 году. SIMD был основой для векторных суперкомпьютеров начала 1970-х годов, таких как CDC Star 100 и Texas Instruments ASC, которые могли оперировать с "вектором" данных с помощью одной инструкции. Векторная обработка была особенно популяризирована Cray в 1970-х и 1980-х годах. Архитектуры векторной обработки теперь считаются отдельными от компьютеров SIMD: таксономия Дункана включает их там, где таксономия Флинна не включает, из-за того, что работы Флинна (1966, 1972) предшествовали Cray 1 (1977). Первая эра современных SIMD-компьютеров характеризовалась суперкомпьютерами с массивно-параллельной обработкой, такими как Thinking Machines CM 1 и CM 2. Эти компьютеры имели множество процессоров с ограниченной функциональностью, работающих параллельно. Например, каждый из 65 536 однобитовых процессоров в Thinking Machines CM 2 выполнял одну и ту же инструкцию одновременно, что позволяло, например, логически объединять 65 536 пар битов одновременно, используя гиперкубическую сеть или оперативную память, выделенную для процессора, для поиска операндов. Суперкомпьютерные технологии отошли от подхода SIMD, когда более мощными стали недорогие скалярные MIMD-подходы, основанные на стандартных процессорах, таких как Intel i860 XP, и интерес к SIMD ослаб. Современная эра SIMD-процессоров выросла из рынка настольных компьютеров, а не из рынка суперкомпьютеров. По мере того как настольные процессоры становились достаточно мощными для поддержки игр в реальном времени и обработки аудио/видео в 1990-х годах, рос спрос на этот конкретный тип вычислительной мощности, и производители микропроцессоров обратились к SIMD для удовлетворения этого спроса. Hewlett Packard представила инструкции MAX в настольных компьютерах PA RISC 1.1 в 1994 году для ускорения декодирования MPEG. Sun Microsystems представила SIMD-инструкции для целочисленных типов данных в своих расширениях набора инструкций "VIS" в 1995 году, в своем микропроцессоре UltraSPARC I. MIPS последовала за ними со своей аналогичной системой MDMX. Первым широко распространенным настольным SIMD стали расширения Intel MMX для архитектуры x86 в 1996 году. Это послужило толчком к внедрению гораздо более мощной системы AltiVec в системах Motorola PowerPC и IBM POWER. Intel ответила в 1999 году, представив совершенно новую систему SSE. С тех пор было разработано несколько расширений набора инструкций SIMD для обеих архитектур. Intel разрабатывает расширенные векторные расширения AVX, AVX2 и AVX 512. AMD поддерживает AVX, AVX2 и AVX 512 в своих текущих продуктах. Все эти разработки были ориентированы на поддержку графики в реальном времени и, следовательно, на обработку в двух, трех или четырех измерениях, обычно с векторными длинами от двух до шестнадцати слов, в зависимости от типа данных и архитектуры. Когда новые SIMD-архитектуры необходимо отличать от старых, новые архитектуры рассматриваются как "коротковокторные", поскольку более ранние SIMD и векторные суперкомпьютеры имели векторные длины от 64 до 64 000. Современный суперкомпьютер почти всегда представляет собой кластер MIMD-компьютеров, каждый из которых реализует (коротковокторные) SIMD-инструкции.

Преимущества

Приложение, которое может извлечь выгоду из SIMD, – это приложение, в котором одно и то же значение добавляется (или вычитается) из большого числа точек данных, что является распространенной операцией во многих мультимедийных приложениях. Примером может служить изменение яркости изображения. Каждый пиксель изображения состоит из трех значений, определяющих яркость красной (R), зеленой (G) и синей (B) составляющих цвета. Для изменения яркости значения R, G и B считываются из памяти, к ним добавляется (или из них вычитается) значение, и полученные значения записываются обратно в память. Аудио DSP также, для регулировки громкости, одновременно умножают левый и правый каналы. С SIMD-процессором этот процесс улучшается в двух аспектах. Во-первых, данные рассматриваются как блоки, и несколько значений можно загрузить сразу. Вместо последовательности инструкций, таких как "извлечь этот пиксель, теперь извлечь следующий пиксель", SIMD-процессор выполнит одну инструкцию, которая эффективно скажет "извлечь n пикселей" (где n – число, зависящее от конкретной реализации). По ряду причин это может занять значительно меньше времени, чем извлечение каждого пикселя по отдельности, как это происходит в традиционных процессорах. Другое преимущество заключается в том, что инструкция применяется ко всем загруженным данным за одну операцию. Иными словами, если SIMD-система загружает восемь точек данных одновременно, операция сложения, применяемая к данным, будет выполнена ко всем восьми значениям одновременно. Этот параллелизм отличается от параллелизма, обеспечиваемого суперскалярным процессором: восемь значений обрабатываются параллельно даже на процессоре, не являющемся суперскалярным, а суперскалярный процессор может выполнять несколько SIMD-операций параллельно.

Недостатки

Не все алгоритмы можно легко векторизовать. Например, задача с интенсивным управлением потоком, такая как разбор кода, может не получить значительной выгоды от SIMD; однако теоретически возможно векторизовать сравнения и "пакетную обработку потока" для достижения максимальной оптимальности кэша, хотя этот метод потребует больше промежуточных данных. Примечание: конвейерные системы пакетной обработки (например, графические процессоры или конвейеры программной растризации) наиболее эффективны для управления кэшем при реализации с использованием SIMD-интринсиков, но они не являются исключительными для функций SIMD. Дополнительная сложность может возникнуть из-за необходимости избегать зависимостей в последовательностях, таких как строки кода; в то время как независимость необходима для векторизации. Большие регистровые файлы увеличивают энергопотребление и требуемую площадь кристалла. В настоящее время реализация алгоритма с использованием SIMD-инструкций обычно требует ручного труда; большинство компиляторов не генерируют SIMD-инструкции из типичной программы на C, например. Автоматическая векторизация в компиляторах является активной областью исследований в информатике. (Сравните с векторной обработкой.) Программирование с конкретными наборами SIMD-инструкций может включать в себя множество задач низкого уровня. SIMD может налагать ограничения на выравнивание данных; программисты, знакомые с определенной архитектурой, могут не ожидать этого. Хуже того: выравнивание может измениться от одной ревизии или "совместимого" процессора к другой. Сбор данных в SIMD-регистры и их распределение по нужным адресам – сложная задача (иногда требующая операций перестановки) и может быть неэффективной. Некоторые наборы SIMD-инструкций не содержат специфических инструкций, таких как вращения или сложение трех операндов. Наборы инструкций зависят от архитектуры: некоторые процессоры вообще не имеют SIMD-инструкций, поэтому программистам необходимо предоставлять невекторизованные реализации (или различные векторизованные реализации) для них. Различные архитектуры предоставляют разные размеры регистров (например, 64, 128, 256 и 512 бит) и наборы инструкций, что означает, что программистам необходимо предоставлять несколько реализаций векторизованного кода для оптимальной работы на любом конкретном процессоре. Кроме того, возможный набор SIMD-инструкций расширяется с каждым новым размером регистра. К сожалению, по причинам обратной совместимости более старые версии не могут быть выведены из эксплуатации. Ранний набор инструкций MMX использовал общий регистровый файл со стеком чисел с плавающей точкой, что приводило к неэффективности при смешивании кода с плавающей точкой и MMX. Однако SSE2 исправляет эту проблему. Для решения проблем 1 и 5 векторное расширение RISC V использует альтернативный подход: вместо того, чтобы предоставлять программисту детали на уровне подрегистров, набор инструкций абстрагирует их в виде нескольких "векторных регистров", которые используют одни и те же интерфейсы на всех процессорах с этим набором инструкций. Аппаратное обеспечение обрабатывает все вопросы выравнивания и "разделения циклов". Машины с разными размерами векторов смогут выполнять один и тот же код. LLVM называет этот векторный тип "". Увеличение размера кода в десять раз и более по сравнению с эквивалентным скалярным или эквивалентным векторизованным кодом – обычное явление, а эффективность (объем выполненной работы на инструкцию) в десять раз и более может быть достигнута с помощью векторных ISA. Scalable Vector Extension от ARM использует другой подход, известный в таксономии Флинна как "ассоциативная обработка", более известный сегодня как "Predicated" (маскированный) SIMD. Этот подход не такой компактный, как векторная обработка, но все же значительно лучше, чем SIMD без маскирования. Подробные сравнительные примеры приведены на странице "Векторная обработка".

Хронология

+ Примеры SIMD-суперкомпьютеров (исключая векторные процессоры) Год Пример 1974 ILLIAC IV 1974 ICL Распределённый массивный процессор (DAP) 1976 Burroughs Scientific Processor 1981 Геометрический арифметический параллельный процессор от Martin Marietta (разработка продолжалась в Lockheed Martin, затем в Teranex и Silicon Optix) 1983 1991 Массивно-параллельный процессор (MPP) от NASA/Goddard Space Flight Center 1985 Connection Machine, модели 1 и 2 (CM 1 и CM 2), от Thinking Machines Corporation 1987 1996 MasPar MP 1 и MP 2 1991 Zephyr DC от Wavetracer 2001 Xplor от Pyxsys, Inc.

Оборудование

Маломасштабные (64 или 128 бит) SIMD стали популярными на процессорах общего назначения в начале 1990-х годов и продолжали развиваться до 1997 года и позже с появлением Motion Video Instructions (MVI) для Alpha. SIMD-инструкции, в той или иной степени, присутствуют на большинстве процессоров, включая IBM AltiVec и SPE для PowerPC, HP PA RISC Multimedia Acceleration eXtensions (MAX), Intel MMX и iwMMXt, SSE, SSE2, SSE3, SSSE3 и SSE4.x, AMD 3DNow!, подсистему ARC Video от ARC, VIS и VIS2 от SPARC, MAJC от Sun, технологию Neon от ARM, MDMX (MaDMaX) от MIPS и MIPS 3D. Набор инструкций SPU процессора Cell, разработанного совместно компаниями IBM, Sony и Toshiba, в значительной степени основан на SIMD. Philips, теперь NXP, разработала несколько SIMD-процессоров под названием Xetal. Xetal содержит 320 16-битных процессорных элементов, специально разработанных для задач компьютерного зрения. SIMD-инструкции Intel AVX 512 обрабатывают 512 бит данных за один такт.

Программное обеспечение

SIMD-инструкции широко используются для обработки 3D-графики, хотя современные графические карты со встроенной SIMD в значительной степени взяли на себя эту задачу от центрального процессора. Некоторые системы также включают функции перестановки (permute), которые переупаковывают элементы внутри векторов, что делает их особенно полезными для обработки и сжатия данных. Они также применяются в криптографии. Тенденция к вычислениям общего назначения на графических процессорах (GPGPU) может привести к более широкому использованию SIMD в будущем. Внедрение SIMD-систем в программное обеспечение для персональных компьютеров поначалу шло медленно из-за ряда проблем. Одной из них было то, что многие ранние наборы SIMD-инструкций имели тенденцию снижать общую производительность системы из-за повторного использования существующих регистров с плавающей точкой. Другие системы, такие как MMX и 3DNow!, предлагали поддержку типов данных, которые не представляли интереса для широкой аудитории, и имели дорогостоящие инструкции переключения контекста для переключения между использованием FPU и MMX-регистров. Компиляторы также часто не поддерживали SIMD, что вынуждало программистов прибегать к кодированию на языке ассемблера. SIMD на x86 стартовал медленно. Появление 3DNow! от AMD и SSE от Intel несколько запутало ситуацию, но сегодня система, похоже, стабилизировалась (после того, как AMD перешла на SSE), и новые компиляторы должны привести к увеличению количества программного обеспечения с поддержкой SIMD. Intel и AMD теперь предоставляют оптимизированные математические библиотеки, использующие SIMD-инструкции, и начали появляться альтернативы с открытым исходным кодом, такие как libSIMD, SIMDx86 и SLEEF (см. также libm). Apple добилась несколько большего успеха, хотя и вышла на рынок SIMD позже остальных. AltiVec предлагает богатую систему и может быть запрограммирован с использованием все более сложных компиляторов от Motorola, IBM и GNU, поэтому программирование на языке ассемблера редко требуется. Кроме того, многие системы, которые могли бы извлечь выгоду из SIMD, поставлялись самой Apple, например, iTunes и QuickTime. Однако в 2006 году компьютеры Apple перешли на процессоры Intel x86. API и инструменты разработки Apple (XCode) были модифицированы для поддержки SSE2 и SSE3, а также AltiVec. Apple была крупнейшим покупателем чипов PowerPC от IBM и Freescale Semiconductor. Несмотря на то, что Apple прекратила использование процессоров PowerPC в своих продуктах, дальнейшая разработка AltiVec продолжается в нескольких проектах PowerPC и Power ISA от Freescale и IBM. SIMD внутри регистра, или SWAR, – это набор методов и приемов, используемых для выполнения SIMD в регистрах общего назначения на оборудовании, которое не предоставляет прямой поддержки SIMD-инструкций. Это позволяет использовать параллелизм в определенных алгоритмах даже на оборудовании, которое не поддерживает SIMD напрямую.

Интерфейс программиста

Для разработчиков наборов инструкций SIMD обычно принято создавать собственные расширения языка C/C++ с использованием встроенных функций или специальных типов данных (с перегрузкой операторов), гарантирующих генерацию векторного кода. Intel, AltiVec и ARM NEON предоставляют расширения, широко используемые компиляторами, предназначенными для их процессоров. (Более сложные операции выполняются с помощью векторных математических библиотек.) Компилятор GNU C идет дальше, абстрагируя эти расширения в универсальный интерфейс, который можно использовать на любой платформе, предоставляя способ определения типов данных SIMD. Компилятор LLVM Clang также реализует эту функцию с аналогичным интерфейсом, определенным в промежуточном представлении (IR). Крейт Rust (и экспериментальный) использует этот интерфейс, как и Swift 2.0+. C++ имеет экспериментальный интерфейс, работающий аналогично расширению GCC. Кажется, что libcxx LLVM также его реализует. Для GCC и libstdc++ доступна оберточная библиотека, построенная на основе расширения GCC. Microsoft добавила поддержку SIMD в .NET в RyuJIT. Пакет, доступный в NuGet, реализует типы данных SIMD. Java также имеет новый предлагаемый API для инструкций SIMD, доступный в OpenJDK 17 в инкубаторном модуле. Он также имеет безопасный механизм отката к простым циклам на неподдерживаемых процессорах. Вместо предоставления типа данных SIMD, компиляторам также можно дать указание автоматически векторизовать некоторые циклы, возможно, с учетом определенных утверждений об отсутствии зависимостей данных. Это менее гибко, чем непосредственная работа с переменными SIMD, но проще в использовании. OpenMP 4.0+ имеет директиву. Этот интерфейс OpenMP заменил широкий набор нестандартных расширений, включая расширения Cilk, GCC и многие другие.

Многоверсионная система SIMD

Обычно ожидается, что потребительское программное обеспечение будет работать на широком спектре процессоров, охватывающих несколько поколений, что может ограничить возможности программиста по использованию новых SIMD-инструкций для повышения вычислительной производительности программы. Решением является включение нескольких версий одного и того же кода, использующих либо более старые, либо более новые технологии SIMD, и выбор наиболее подходящей для процессора пользователя во время выполнения (динамическая диспетчеризация). Существует два основных подхода:
Многоверсионность функций (FMV): подпрограмма в программе или библиотеке дублируется и компилируется для различных расширений набора команд, а программа определяет, какую из них использовать во время выполнения. Многоверсионность библиотек (LMV): вся библиотека программирования дублируется для различных расширений набора команд, и операционная система или программа определяет, какую из них загрузить во время выполнения. FMV, реализованный вручную на языке ассемблера, довольно часто используется в ряде библиотек, критичных к производительности, таких как glibc и libjpeg turbo. Компиляторы Intel C++, GNU Compiler Collection начиная с GCC 6 и Clang начиная с clang 7 позволяют упростить этот подход, беря на себя дублирование и выбор функций. GCC и Clang требуют явных меток в коде для "клонирования" функций, в то время как ICC делает это автоматически (с помощью опции командной строки). Язык программирования Rust также поддерживает FMV. Настройка аналогична GCC и Clang в том, что код определяет, для каких наборов инструкций следует компилировать, но клонирование выполняется вручную с помощью встраивания (inlining). Поскольку использование FMV требует изменения кода в GCC и Clang, производители чаще используют многоверсионность библиотек: это проще реализовать, так как необходимо изменить только параметры компиляции. Glibc поддерживает LMV, и эта функциональность используется в проекте Clear Linux, поддерживаемом Intel.

SIMD в сети

В 2013 году Джон МакКатчан объявил о создании высокопроизводительного интерфейса для наборов инструкций SIMD для языка программирования Dart, впервые предоставив преимущества SIMD для веб-программ. Интерфейс состоит из двух типов: Float32x4, представляющий 4 числа с одинарной точностью, и Int32x4, представляющий 4 32-битных целых числа. Экземпляры этих типов неизменяемы, а в оптимизированном коде напрямую отображаются в SIMD-регистры. Операции, выраженные на Dart, обычно компилируются в одну инструкцию без каких-либо дополнительных затрат. Это аналогично встроенным функциям (intrinsics) в C и C++. Тесты производительности для умножения матриц 4x4, преобразования 3D-вершин и визуализации множества Мандельброта показали почти 400%-ное ускорение по сравнению со скалярным кодом, написанным на Dart. Работа МакКатчана над Dart, теперь известная как SIMD.js, была принята ECMAScript, а Intel объявила на IDF 2013 о реализации спецификации МакКатчана для V8 и SpiderMonkey. Однако к 2017 году SIMD.js был исключен из очереди стандартизации ECMAScript в пользу разработки аналогичного интерфейса в WebAssembly. По состоянию на август 2020 года интерфейс WebAssembly остается незавершенным, но его переносимая 128-битная функция SIMD уже используется во многих движках. Emscripten, компилятор Mozilla C/C++ в JavaScript с расширениями, позволяет компилировать программы на C++ с использованием SIMD-интринсиков или векторного кода в стиле GCC в SIMD API JavaScript, обеспечивая сравнимое ускорение по сравнению со скалярным кодом. Он также поддерживает (и теперь предпочитает) предложение WebAssembly 128-bit SIMD.

Коммерческие применения

В целом, оказалось трудно найти устойчивые коммерческие применения для процессоров, работающих исключительно с SIMD. Одним из немногих, добившихся определенного успеха, является GAPP, разработанный Lockheed Martin и перенесенный в коммерческий сектор их дочерней компанией Teranex. Современные версии GAPP стали мощным инструментом в приложениях обработки видео в реальном времени, таких как преобразование между различными видеостандартами и частотами кадров (NTSC в/из PAL, NTSC в/из форматов HDTV и т.д.), деинтерляция, снижение шума изображения, адаптивное сжатие видео и улучшение качества изображения. Более широкое применение SIMD можно найти в видеоиграх: почти каждая современная игровая консоль, начиная с 1998 года, включает в свою архитектуру процессор SIMD. PlayStation 2 была уникальной тем, что один из ее векторных блоков мог функционировать как автономный DSP, выполняющий собственный поток инструкций, или как сопроцессор, управляемый обычными инструкциями CPU. Приложения для 3D-графики хорошо подходят для обработки SIMD, поскольку в значительной степени опираются на операции с четырехмерными векторами. Microsoft Direct3D 9.0 теперь динамически выбирает реализации своих математических операций, специфичные для конкретного процессора, включая использование SIMD-инструкций. Более поздним процессором, использующим векторную обработку, является Cell Processor, применяемый в Playstation 3 и разработанный IBM в сотрудничестве с Toshiba и Sony. Он использует множество SIMD-процессоров (архитектура NUMA, каждый с независимой локальной памятью и управляемый универсальным CPU) и предназначен для работы с огромными объемами данных, необходимыми для приложений 3D- и видеообработки. Он отличается от традиционных ISA тем, что SIMD реализован в нем изначально, без отдельных скалярных регистров. Ziilabs разработала SIMD-процессор для использования в мобильных устройствах, таких как медиаплееры и мобильные телефоны. Более масштабные коммерческие SIMD-процессоры доступны от ClearSpeed Technology, Ltd. и Stream Processors, Inc. ClearSpeed CSX600 (2004) имеет 96 ядер, каждое из которых оснащено двумя блоками вычислений с плавающей точкой двойной точности, а CSX700 (2008) – 192 ядра. Stream Processors возглавляет архитектор компьютеров Билл Далли. Их процессор Storm 1 (2007) содержит 80 SIMD-ядер, управляемых CPU MIPS.