stringtranslate.com

Векторный процессор

В вычислениях векторный процессор или процессор массива — это центральный процессор (ЦП), который реализует набор команд , где его инструкции предназначены для эффективной и результативной работы с большими одномерными массивами данных, называемыми векторами . В этом отличие от скалярных процессоров , инструкции которых работают только с отдельными элементами данных, и в отличие от некоторых из тех же самых скалярных процессоров, имеющих дополнительные одну инструкцию, несколько данных (SIMD) или арифметические единицы SWAR . Векторные процессоры могут значительно повысить производительность при выполнении определенных рабочих нагрузок, особенно при численном моделировании и подобных задачах. Методы векторной обработки также используются в оборудовании игровых консолей и графических ускорителях .

Векторные машины появились в начале 1970-х годов и доминировали в разработке суперкомпьютеров с 1970-х по 1990-е годы, особенно в различных платформах Cray . Быстрое падение соотношения цены и производительности традиционных микропроцессоров привело к упадку векторных суперкомпьютеров в 1990-е годы.

История

Ранние исследования и разработки

Разработка векторной обработки началась в начале 1960-х годов в компании Westinghouse Electric Corporation в рамках их проекта «Соломон» . Целью Соломона было резко повысить математическую производительность за счет использования большого количества простых сопроцессоров под управлением одного главного центрального процессора (ЦП). ЦП подавал одну общую команду всем арифметико-логическим устройствам (АЛУ), по одной на цикл, но с разными точками данных для работы каждого из них. Это позволило машине Соломона применить единый алгоритм к большому набору данных , подаваемому в виде массива.

В 1962 году Westinghouse отменила проект, но его возобновил Университет Иллинойса в Урбане-Шампейне под названием ILLIAC IV . Их версия конструкции первоначально предусматривала машину с производительностью 1 GFLOPS и 256 ALU, но, когда она была наконец выпущена в 1972 году, она имела только 64 ALU и могла достигать производительности только от 100 до 150 MFLOPS. Тем не менее, он показал, что базовая концепция была правильной, и при использовании в приложениях с интенсивным использованием данных, таких как вычислительная гидродинамика , ILLIAC оказался самой быстрой машиной в мире. Подход ILLIAC, заключающийся в использовании отдельных ALU для каждого элемента данных, не является общим для более поздних разработок и часто относится к отдельной категории — массово-параллельные вычисления. Примерно в это же время Флинн отнес этот тип обработки к ранней форме одиночной инструкции и нескольких потоков (SIMT).

Компьютер для работы с функциями

Компьютер для работы с функциями был представлен и разработан Карцевым в 1967 году. [1]

Суперкомпьютеры

Первыми векторными суперкомпьютерами являются Control Data Corporation STAR-100 и Advanced Scientific Computer (ASC) компании Texas Instruments , которые были представлены в 1974 и 1972 годах соответственно.

Базовое ASC (т. е. «одноконвейерное») ALU использовало конвейерную архитектуру, которая поддерживала как скалярные, так и векторные вычисления, при этом пиковая производительность достигала примерно 20 MFLOPS, что легко достигалось при обработке длинных векторов. Расширенные конфигурации ALU поддерживают «два канала» или «четыре канала» с соответствующим увеличением производительности в 2 или 4 раза. Пропускной способности памяти было достаточно для поддержки этих расширенных режимов.

В остальном STAR-100 был медленнее, чем собственные суперкомпьютеры CDC, такие как CDC 7600 , но при выполнении задач, связанных с данными, они могли справляться с ними, будучи намного меньшими и менее дорогими. Однако машине также потребовалось немало времени на декодирование векторных инструкций и подготовку к запуску процесса, поэтому ей требовались очень специфические наборы данных для работы, прежде чем она действительно что-либо ускорила.

Векторный метод был впервые полностью использован в 1976 году знаменитым Cray-1 . Вместо того, чтобы оставлять данные в памяти, как в STAR-100 и ASC, конструкция Cray имела восемь векторных регистров , каждый из которых содержал шестьдесят четыре 64-битных слова. Векторные инструкции применялись между регистрами, что намного быстрее, чем обращение к основной памяти. В то время как STAR-100 применял одну операцию к длинному вектору в памяти, а затем переходил к следующей операции, конструкция Cray загружала меньшую часть вектора в регистры, а затем применяла к этим данным как можно больше операций. , тем самым избегая многих гораздо более медленных операций доступа к памяти.

В конструкции Крэя для реализации векторных инструкций использовался конвейерный параллелизм , а не несколько ALU. Кроме того, в конструкции были совершенно отдельные конвейеры для разных инструкций, например, сложение/вычитание было реализовано на другом аппаратном обеспечении, чем умножение. Это позволило передать пакет векторных инструкций в каждый из субблоков ALU — метод, который они назвали векторной цепочкой . Cray-1 обычно имел производительность около 80 MFLOPS, но при подключении до трех цепей он мог достигать максимальной производительности 240 MFLOPS и в среднем около 150 — намного быстрее, чем любая машина того времени.

Процессорный модуль Cray J90 с четырьмя скалярными/векторными процессорами

Последовали и другие примеры. Корпорация Control Data попыталась снова выйти на рынок high-end со своей машиной ETA-10 , но она продавалась плохо, и они восприняли это как возможность полностью покинуть область суперкомпьютеров. В начале и середине 1980-х годов японские компании ( Fujitsu , Hitachi и Nippon Electric Corporation (NEC) представили векторные машины на основе регистров, аналогичные Cray-1, обычно немного быстрее и намного меньше. Системы с плавающей запятой (FPS) на базе Орегона . построили дополнительные массивы процессоров для миникомпьютеров , а затем построили свои собственные минисуперкомпьютеры .

На протяжении всего этого времени компания Cray продолжала оставаться лидером по производительности, постоянно побеждая конкурентов с помощью серии машин, результатом которой стали Cray-2 , Cray X-MP и Cray Y-MP . С тех пор рынок суперкомпьютеров в большей степени сосредоточился на массовой параллельной обработке, а не на более совершенных реализациях векторных процессоров. Однако, осознавая преимущества векторной обработки, IBM разработала виртуальную векторную архитектуру для использования в суперкомпьютерах, объединяющих несколько скалярных процессоров в качестве векторного процессора.

Хотя векторные суперкомпьютеры, подобные Cray-1, в наши дни менее популярны, NEC продолжает производить компьютеры этого типа и по сей день, выпустив серию компьютеров SX . Совсем недавно в SX-Aurora TSUBASA процессор и 24 или 48 гигабайт памяти размещались на модуле HBM 2 внутри карты, которая физически напоминает графический сопроцессор, но вместо того, чтобы служить сопроцессором, она является основным компьютером с ПК-совместимый компьютер, к которому он подключен, выполняет вспомогательные функции.

графический процессор

Современные графические процессоры ( GPU ) включают в себя массив шейдерных конвейеров , которые могут управляться вычислительными ядрами и могут считаться векторными процессорами (с использованием аналогичной стратегии для сокрытия задержек памяти). Как показано в статье Флинна 1972 года, ключевым отличительным фактором графических процессоров на базе SIMT является то, что они имеют один декодер-транслятор команд, но ядра, получающие и выполняющие одну и ту же инструкцию, в остальном достаточно нормальны: свои собственные ALU, свои собственные файлы регистров, свои собственные блоки загрузки/сохранения и собственные независимые кэши данных L1. Таким образом, хотя все ядра одновременно выполняют одну и ту же инструкцию синхронно друг с другом, они делают это с совершенно разными данными из совершенно разных ячеек памяти. Это значительно сложнее и сложнее, чем «Packed SIMD» , который строго ограничен выполнением только параллельных конвейерных арифметических операций. Хотя точные внутренние детали современных коммерческих графических процессоров являются частной тайной, команде MIAOW [2] удалось собрать воедино неофициальную информацию, достаточную для реализации подмножества архитектуры AMDGPU. [3]

Недавнее развитие

Некоторые современные архитектуры ЦП разрабатываются как векторные процессоры. Векторное расширение RISC -V следует тем же принципам, что и ранние векторные процессоры, и реализуется в коммерческих продуктах, таких как Andes Technology AX45MPV. [4] Также разрабатываются несколько архитектур векторных процессоров с открытым исходным кодом , включая ForwardCom и Libre-SOC .

Сравнение с современной архитектурой

По состоянию на 2016 год большинство обычных процессоров реализуют архитектуры с SIMD-инструкциями фиксированной длины. На первый взгляд их можно рассматривать как форму векторной обработки, поскольку они работают с несколькими наборами данных (векторизованных, явной длины) и заимствуют функции векторных процессоров. Однако по определению добавление SIMD само по себе не может квалифицировать процессор как настоящий векторный процессор , поскольку SIMD имеет фиксированную длину , а векторы имеют переменную длину . Разница проиллюстрирована ниже на примерах, показывающих и сравнивающих три категории: Pure SIMD, Predicated SIMD и Pure Vector Processing. [ нужна цитата ]

Другие конструкции ЦП включают в себя несколько инструкций для векторной обработки нескольких (векторизованных) наборов данных, обычно известных как MIMD (множественные инструкции, множественные данные) и реализованных с помощью VLIW (очень длинное командное слово) и EPIC (явное параллельное вычисление инструкций). Векторный процессор Fujitsu FR-V VLIW сочетает в себе обе технологии.

Разница между SIMD и векторными процессорами

Наборы команд SIMD лишены важных функций по сравнению с наборами векторных инструкций. Наиболее важным из них является то, что векторные процессоры по определению и конструкции всегда имели переменную длину с момента их создания.

В то время как чистый (фиксированной ширины, без предикации) SIMD часто ошибочно называют «векторным» (поскольку SIMD обрабатывает данные, которые оказываются векторами), посредством тщательного анализа и сравнения исторических и современных ISA можно заметить, что фактические векторные ISA имеют следующие функции, которых нет ни в одной SIMD ISA :

Предикатный SIMD (часть таксономии Флинна ), который представляет собой комплексные маски предикатов на уровне отдельных элементов для каждой векторной инструкции, которые теперь доступны в ARM SVE2. [8] А AVX-512 почти можно назвать векторным процессором. [ как? ] Предикативный SIMD использует SIMD ALU фиксированной ширины, но позволяет локально управляемую (предикативную) активацию модулей для обеспечения появления векторов переменной длины. Приведенные ниже примеры помогают объяснить эти категориальные различия.

SIMD, поскольку он использует пакетную обработку фиксированной ширины, по своей конструкции не может справиться с итерациями и сокращениями. Это дополнительно иллюстрируется примерами ниже.

Кроме того, векторные процессоры могут быть более ресурсоэффективными за счет использования более медленного оборудования и экономии энергии, но при этом обеспечивать пропускную способность и меньшую задержку, чем SIMD, за счет векторной цепочки . [9] [10]

Рассмотрим как SIMD-процессор, так и векторный процессор, работающий с четырьмя 64-битными элементами и выполняющий последовательности ЗАГРУЗКА, СЛОЖЕНИЕ, УМНОЖЕНИЕ и СОХРАНЕНИЕ. Если ширина SIMD равна 4, то процессор SIMD должен полностью ЗАГРУЗИТЬ четыре элемента, прежде чем он сможет перейти к ADD, должен завершить все ADD, прежде чем он сможет перейти к MULTIPLY, и аналогичным образом должен завершить все MULTIPLY, прежде чем он сможет запустите МАГАЗИНЫ. Это по определению и замыслу. [11]

Необходимость одновременного выполнения 4-х 64-битных операций ЗАГРУЗКИ и 64-битных операций СОХРАНЕНИЯ является очень дорогостоящей с точки зрения аппаратного обеспечения (256-битные пути данных к памяти). Также имеется 4 64-битных ALU, особенно MULTIPLY. Чтобы избежать таких высоких затрат, SIMD-процессор должен иметь 64-битную загрузку 1 ширины, 64-битное хранилище STORE 1 ширины и только 64-битные ALU шириной 2 ширины. Как показано на диаграмме, которая предполагает модель выполнения с несколькими задачами , последствия заключаются в том, что выполнение операций теперь занимает больше времени. Если многовыпуск невозможен, то операции занимают еще больше времени, поскольку LD может не быть выпущен (запущен) одновременно с первыми ADD и так далее. Если есть только 4-битные 64-битные SIMD ALU, время завершения еще хуже: только когда все четыре LOAD завершены, могут начаться операции SIMD, и только когда все операции ALU завершены, могут начаться STORE.

Векторный процессор, напротив, даже если он однозадачный и не использует SIMD ALU, имеет только 1-битную 64-битную ЗАГРУЗКУ, 1-битную 64-битную ЗАПИСЬ (и, как в Cray -1 , способность запустить MULTIPLY одновременно с ADD), может выполнить четыре операции быстрее, чем процессор SIMD с LOAD 1, STORE 1 и SIMD 2. Более эффективное использование ресурсов благодаря объединению векторов в цепочку является ключевым преимуществом и отличием от SIMD. SIMD по замыслу и определению не может выполнять цепочку, за исключением всей группы результатов. [12]

Описание

В общих чертах, процессоры могут манипулировать одним или двумя фрагментами данных одновременно. Например, у большинства процессоров есть инструкция, которая по сути говорит: «Добавьте A к B и поместите результат в C». Данные для A, B и C могут быть — по крайней мере теоретически — закодированы непосредственно в инструкции. Однако в эффективной реализации все редко бывает так просто. Данные редко отправляются в необработанном виде, а вместо этого «указываются» путем передачи адреса в ячейку памяти, в которой хранятся данные. Декодирование этого адреса и получение данных из памяти занимает некоторое время, в течение которого процессор традиционно простаивает, ожидая появления запрошенных данных. По мере увеличения скорости процессора эта задержка памяти исторически стала серьезным препятствием для производительности; см. Стена памяти .

Чтобы сократить время, затрачиваемое на эти шаги, большинство современных процессоров используют метод, известный как конвейерная обработка инструкций , при котором инструкции по очереди проходят через несколько подблоков. Первый подблок считывает адрес и декодирует его, следующий «выбирает» значения по этим адресам, а следующий выполняет сами математические вычисления. При конвейерной обработке «хитрость» заключается в том, чтобы начать декодирование следующей инструкции еще до того, как первая покинет ЦП, подобно сборочной линии , поэтому декодер адреса используется постоянно. Для выполнения любой конкретной инструкции требуется одинаковое количество времени, время, известное как задержка , но ЦП может обрабатывать весь пакет операций перекрывающимся образом гораздо быстрее и эффективнее, чем если бы он делал это по одной.

Векторные процессоры развивают эту концепцию на шаг дальше. Вместо конвейерной передачи только инструкций они также конвейеризируют сами данные. Процессору подаются инструкции, в которых говорится не просто сложить А с Б, но и сложить все числа «отсюда сюда» ко всем числам «оттуда туда». Вместо того, чтобы постоянно декодировать инструкции и затем извлекать данные, необходимые для их выполнения, процессор считывает одну инструкцию из памяти, и в определении самой инструкции просто подразумевается, что инструкция снова будет работать с другим элементом данных. по адресу, который на один шаг больше предыдущего. Это позволяет существенно сэкономить время декодирования.

Чтобы проиллюстрировать, какую разницу это может иметь, рассмотрим простую задачу сложения двух групп по 10 чисел. На обычном языке программирования можно было бы написать «цикл», который поочередно собирал каждую из пар чисел, а затем складывал их. Для процессора это будет выглядеть примерно так:

; Гипотетическая RISC-машина ; предположим, что a, b и c — это ячейки памяти в соответствующих регистрах ; добавить 10 чисел в a к 10 числам в b, сохранить результаты в c move $10 , count ; count := 10 цикл : нагрузка r1 , нагрузка r2 , b добавить r3 , r1 , r2 ; r3 := r1 + r2 сохраняем r3 , c добавляем a , a , $4 ; двигаться дальше, добавить b , b , $4, добавить c , c , $4 , десятичный счет ; уменьшить счетчик jnez , цикл ; вернуться назад, если счетчик еще не равен 0, ret                                       

Но для векторного процессора эта задача выглядит совершенно иначе:

; предположим, что у нас есть векторные регистры v1-v3 ; при размере, равном или больше 10, переместите $10 , count ; count = 10 vload v1 , a , count vload v2 , b , count vadd v3 , v1 , v2 vstore v3 , c , count ret                     

Обратите внимание на полное отсутствие циклов в инструкциях, поскольку именно аппаратное обеспечение выполнило 10 последовательных операций: фактически счетчик циклов явно рассчитывается для каждой инструкции .

Векторные ISA в стиле Cray идут еще дальше и предоставляют глобальный регистр «счета», называемый длиной вектора (VL):

; снова предположим, что у нас есть векторные регистры v1-v3 ; с размером больше или равным 10 setvli $10 # Установить длину вектора VL=10 vload v1 , a # 10 загружается из vload v2 , b # 10 загружается из b vadd v3 , v1 , v2 # 10 добавляет vstore v3 , c # 10 магазины в складе                     

Этот подход дает несколько преимуществ экономии. [13]

  1. необходимы только три трансляции адресов. В зависимости от архитектуры это само по себе может привести к значительной экономии.
  2. Еще одна экономия — выборка и декодирование самой инструкции, которую нужно сделать только один раз вместо десяти.
  3. Сам код также стал меньше, что может привести к более эффективному использованию памяти, уменьшению размера кэша инструкций L1, снижению энергопотребления.
  4. При уменьшении размера программы прогнозирование ветвей становится проще.
  5. Поскольку длина (эквивалентная ширине SIMD) не жестко запрограммирована в инструкции, кодирование не только становится более компактным, но и «ориентированным на будущее» и позволяет даже конструкциям встроенных процессоров рассматривать возможность использования векторов исключительно для получения всех других преимуществ. , а не стремиться к высокой производительности.

Кроме того, в более современных векторных процессорах ISA появилась функция «Fail on First» или «Fault First» (см. ниже), что дает еще больше преимуществ.

Более того, высокопроизводительный векторный процессор может иметь несколько функциональных блоков , параллельно добавляющих эти числа. Проверка зависимостей между этими числами не требуется, поскольку векторная инструкция определяет несколько независимых операций. Это упрощает необходимую логику управления и может еще больше повысить производительность за счет предотвращения зависаний. Таким образом, математические операции в целом выполнялись гораздо быстрее, причем ограничивающим фактором было время, необходимое для извлечения данных из памяти.

Не все проблемы можно решить с помощью такого решения. Включение этих типов инструкций обязательно усложняет работу ядра ЦП. Эта сложность обычно приводит к тому, что другие инструкции выполняются медленнее, т. е. всякий раз, когда не складывается много чисел подряд. Более сложные инструкции также усложняют декодеры, что может замедлить декодирование более распространенных инструкций, таких как обычное сложение. ( Это можно несколько смягчить, если полностью сохранить принципы ISA для RISC : RVV добавляет только около 190 векторных инструкций даже с расширенными функциями. [14] ).

Векторные процессоры традиционно разрабатывались для наилучшей работы только при обработке больших объемов данных. По этой причине процессоры такого типа встречались в основном в суперкомпьютерах , так как сами суперкомпьютеры, как правило, находились в таких местах, как центры прогнозирования погоды и физические лаборатории, где «обрабатываются» огромные объемы данных. Однако, как показано выше и продемонстрировано RISC-V RVV, эффективность векторных ISA дает и другие преимущества, которые привлекательны даже для встраиваемых систем.

Векторные инструкции

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

Самоповторяющиеся инструкции встречаются в ранних векторных компьютерах, таких как STAR-100, где вышеуказанное действие описывалось одной командой (что-то вроде vadd c, a, b, $10). Они также встречаются в архитектуре x86 в качестве REPпрефикса. Однако таким образом можно эффективно выполнять аппаратные средства только очень простых вычислений без значительного увеличения затрат. Поскольку в архитектуре STAR-100 все операнды должны находиться в памяти, задержка, вызванная доступом, также стала огромной.

Интересно, однако, что Broadcom включил пространство во все векторные операции Videocore IV ISA для REPполя, но в отличие от STAR-100, который использует память для своих повторов, повторы Videocore IV присутствуют во всех операциях, включая арифметические векторные операции. Длина повтора может быть небольшим диапазоном, равным двум , или может быть получена из одного из скалярных регистров. [15]

Cray -1 представил идею использования регистров процессора для пакетного хранения векторных данных. Длины пакетов (длина вектора, VL) могут быть установлены динамически с помощью специальной инструкции, при этом значение по сравнению с Videocore IV (и, что особенно важно, как будет показано ниже, также с SIMD) заключается в том, что длина повтора не обязательно должна быть частью кодировка инструкции. Таким образом, в каждой партии можно выполнить значительно больше работы; кодирование инструкций также намного более элегантно и компактно. Единственным недостатком является то, что для того, чтобы в полной мере воспользоваться преимуществами дополнительной мощности пакетной обработки, необходимо также увеличить нагрузку на память и скорость хранения. Иногда это утверждается [ кем? ] является недостатком векторных процессоров в стиле Cray: на самом деле это часть достижения высокой производительности, как это видно на графических процессорах , которые сталкиваются с точно такой же проблемой.

Современные SIMD-компьютеры утверждают, что они улучшили раннюю версию Cray за счет прямого использования нескольких ALU для более высокой степени параллелизма по сравнению с использованием только обычного скалярного конвейера. Современные векторные процессоры (такие как SX-Aurora TSUBASA ) сочетают в себе оба способа, выдавая несколько данных на несколько внутренних конвейерных SIMD ALU, причем количество выдаваемых данных динамически выбирается векторной программой во время выполнения. Маски можно использовать для выборочной загрузки и хранения данных в ячейках памяти, а также использовать те же маски для выборочного отключения обрабатывающего элемента SIMD ALU. Некоторые процессоры с SIMD ( AVX-512 , ARM SVE2 ) способны выполнять такого рода выборочную, поэлементную ( «предикатную» ) обработку, и именно они в некоторой степени заслуживают номенклатуры «векторный процессор» или, по крайней мере, заслуживают требования возможность «векторной обработки». SIMD-процессоры без поэлементного предикации ( MMX , SSE , AltiVec ) категорически этого не делают.

Современные графические процессоры, которые имеют множество небольших вычислительных блоков, каждый из которых имеет свои собственные независимые SIMD ALU, используют одноинструкционную многопоточность (SIMT). Модули SIMT запускаются из общего модуля команд с синхронизацией широковещательной передачи. «Векторные регистры» очень широки, а конвейеры имеют тенденцию быть длинными. «Поточная» часть SIMT включает в себя способ обработки данных независимо на каждом из вычислительных блоков.

Кроме того, графические процессоры, такие как Broadcom Videocore IV, и другие внешние векторные процессоры, такие как NEC SX-Aurora TSUBASA, могут использовать меньше векторных единиц, чем предполагает ширина: вместо 64 единиц для регистра шириной 64 числа аппаратное обеспечение может вместо этого использовать выполните конвейерный цикл из 16 единиц для гибридного подхода. Broadcom Videocore IV также способен использовать этот гибридный подход: номинально заявляя, что его SIMD QPU Engine поддерживает в своих инструкциях операции с массивом FP ​​длиной 16, на самом деле он выполняет их по 4 за раз, как (еще одна) форма «потоков». [16]

Пример векторной инструкции

Этот пример начинается с алгоритма («IAXPY»), сначала покажите его в виде скалярных инструкций, затем SIMD, затем предикативных SIMD и, наконец, векторных инструкций. Это постепенно помогает проиллюстрировать разницу между традиционным векторным процессором и современным SIMD. Пример начинается с 32-битного целочисленного варианта функции «DAXPY» на языке C :

void iaxpy ( size_t n , int a , const int x [], int y []) { for ( size_t i = 0 ; i < n ; i ++ ) y [ i ] = a * x [ i ] + y [ я ]; }                          

На каждой итерации к каждому элементу y добавляется элемент x, умноженный на a. Программа представлена ​​в скалярно-линейной форме для удобства чтения.

Скалярный ассемблер

Скалярная версия этого алгоритма будет загружать по одному из x и y, обрабатывать одно вычисление, сохранять один результат и выполнять цикл:

цикл: load32 r1 , x ; загрузить одни 32-битные данные load32 r2 , y mul32 r1 , a , r1 ; r1 := r1 * a add32 r3 , r1 , r2 ; r3 := r1 + r2 store32 r3 , y addl x , x , $4 ; x := x + 4 addl y , y , $4 subl n , n , $1 ; n := n - 1 jgz n , петля ; вернуться в цикл, если n > 0, выход: ret                                       

Код, подобный STAR, остается кратким, но поскольку векторизация STAR-100 изначально была основана на доступе к памяти, для обработки информации теперь требуется дополнительный слот памяти. Также требуется двукратное увеличение задержки из-за дополнительных требований к доступу к памяти.

 ; Предположим, что tmp предварительно выделен vmul tmp , a , x , n ; tmp[i] = a * x[i] vadd y , y , tmp , n ; y[i] = y[i] + tmp[i] ret             

Чистый (непредсказанный, упакованный) SIMD

Современная упакованная архитектура SIMD, известная под многими именами (перечисленными в таксономии Флинна ), может выполнять большую часть операций в пакетном режиме. Код во многом похож на скалярную версию. Предполагается, что x и y здесь правильно выровнены (только начинаются с числа, кратного 16) и что n кратно 4, поскольку в противном случае для расчета маски или запуска скалярной версии потребуется некоторый код настройки. Для простоты также можно предположить, что инструкции SIMD имеют возможность автоматически повторять скалярные операнды, как это может делать ARM NEON. [17] Если это не так, необходимо использовать «splat» (широковещательную рассылку) для копирования скалярного аргумента в регистр SIMD:

 splatx4 v4 , а ; v4 = а,а,а,а   

Затраченное время будет в основном таким же, как и при векторной реализации, y = mx + cописанной выше.

vloop: load32x4 v1 , x load32x4 v2 , y mul32x4 v1 , a , v1 ; v1 := v1 * a add32x4 v3 , v1 , v2 ; v3 := v1 + v2 store32x4 v3 , y addl x , x , $16 ; x := x + 16 addl y , y , $16 subl n , n , $4 ; п := п - 4 jgz n , vloop ; вернуться назад, если n > 0, выход: ret                                      

Обратите внимание, что оба указателя x и y увеличиваются на 16, потому что именно столько (в байтах) имеют четыре 32-битных целых числа. Было принято решение, что алгоритм будет работать только с 4-х SIMD, поэтому константа жестко запрограммирована в программе.

К несчастью для SIMD, подсказка заключалась в приведенном выше предположении, что «n кратно 4», а также в «выровненном доступе», который, очевидно, является ограниченным вариантом использования для специалистов.

Реально, для циклов общего назначения, таких как в переносимых библиотеках, где n не может быть ограничено таким образом, накладные расходы на настройку и очистку SIMD для обработки не кратных ширине SIMD могут значительно превысить количество команд внутри. сама петля. Если предположить, что в худшем случае аппаратное обеспечение не может выполнить несогласованный доступ к памяти SIMD, реальный алгоритм будет:

SIMD восьми ширины требует повторения алгоритма внутреннего цикла сначала с элементами SIMD четырех ширины, затем SIMD двух ширины, затем одного (скалярного), с тестом и ветвью между каждым из них, чтобы охватить первый и последний оставшийся SIMD. элементы (0 <= n <= 7).

Это более чем в три раза увеличивает размер кода, а в крайних случаях это приводит к увеличению количества инструкций на порядок ! Это можно легко продемонстрировать , скомпилировав пример iaxpy для AVX-512 , используя параметры "-O3 -march=knl"gcc .

Со временем, по мере того, как ISA развивается и продолжает повышать производительность, это приводит к тому, что ISA Architects добавляют SIMD с 2-мя панелями, затем с 4-мя SIMD, затем с 8-ми и выше. Таким образом, можно понять, почему AVX-512 существует в x86.

Без предсказывания, чем шире ширина SIMD, тем хуже становятся проблемы, что приводит к массовому увеличению количества кодов операций, снижению производительности, дополнительному энергопотреблению и ненужной сложности программного обеспечения. [18]

С другой стороны, векторные процессоры предназначены для выполнения вычислений переменной длины для произвольного числа n и, следовательно, требуют очень малой настройки и никакой очистки. Даже по сравнению с теми SIMD ISA, которые имеют маски (но не имеют setvlинструкций), векторные процессоры создают гораздо более компактный код, поскольку им не нужно выполнять явный расчет маски для покрытия нескольких последних элементов (показано ниже).

Предикатный SIMD

Предполагая гипотетический предикатный (с поддержкой маски) SIMD ISA и снова предполагая, что инструкции SIMD могут обрабатывать невыровненные данные, цикл инструкций будет выглядеть следующим образом:

vloop: # готовим маску. немногие ISA имеют min to min t0 , n , $4 ; t0 = min(n, 4) сдвиг m , $1 , t0 ; m = 1<<t0 sub m , m , $1 ; m = (1<<t0)-1 # теперь выполняем операцию, замаскированную m битами load32x4 v1 , x , m load32x4 v2 , y , m mul32x4 v1 , a , v1 , m ; v1 := v1 * a add32x4 v3 , v1 , v2 , m ; v3 := v1 + v2 store32x4 v3 , y , m # обновляем x, y и n для следующего цикла addl x , t0 * 4 ; x := x + t0*4 addl y , t0 * 4 subl n , n , t0 ; n := n - t0 # цикл? jgz n , влуп ; вернуться назад, если n > 0, выход: ret                                                            

Здесь видно, что код намного чище, но немного сложнее: по крайней мере, здесь нет настройки или очистки: на последней итерации цикла маска предиката будет установлена ​​​​в 0b0000, 0b0001, 0b0011, 0b0111 или 0b1111, что приводит к выполнению от 0 до 4 операций с элементом SIMD соответственно. Еще одно потенциальное осложнение: некоторые RISC ISA не имеют инструкции «min», вместо этого необходимо использовать ветвление или скалярное предикатное сравнение.

Понятно, что предикатный SIMD, по крайней мере, заслуживает термина «совместимый с векторами», поскольку он может работать с векторами переменной длины за счет использования масок предикатов. Однако последним шагом на пути к «истинной» векторной ISA является полное отсутствие в ISA каких-либо свидетельств ширины SIMD, оставляя это полностью на усмотрение аппаратного обеспечения.

Чистый (истинный) вектор ISA

Для векторных ISA в стиле Cray, таких как RVV, используется команда setvl (установка длины вектора). Аппаратное обеспечение сначала определяет, сколько значений данных оно может обработать в одном «векторе»: это могут быть либо реальные регистры, либо внутренний цикл (гибридный подход, упомянутый выше). Это максимальное количество (количество аппаратных «полос») называется «MVL» (максимальная длина вектора). Обратите внимание, что, как видно из SX-Aurora и Videocore IV, MVL может быть реальным количеством аппаратных линий или виртуальным . (Примечание. Как упоминалось в руководстве по ARM SVE2, программисты не должны совершать ошибку, предполагая фиксированную ширину вектора: следовательно, MVL не является величиной, которую необходимо знать программисту. Это может немного сбивать с толку после многих лет мышления SIMD). [ тон ]

При вызове setvl с указанием количества элементов данных, подлежащих обработке, «setvl» разрешено (по существу требуется) ограничить это значение максимальной длиной вектора (MVL) и, таким образом, возвращает фактическое число , которое может быть обработано оборудованием в последующем векторе. инструкции и устанавливает во внутреннем специальном регистре «VL» ту же самую сумму. В своих руководствах по SVE2 ARM называет этот метод программированием без учета длины вектора. [19]

Ниже представлен векторный ассемблер в стиле Cray для того же цикла в стиле SIMD, что и выше. Обратите внимание, что t0 (который, содержащий удобную копию VL, может варьироваться) используется вместо жестко запрограммированных констант:

vloop: setvl t0 , n # VL=t0=min(MVL, n) vld32 v0 , x # вектор загрузки x vld32 v1 , y # вектор загрузки y vmadd32 v1 , v0 , a # v1 += v0 * a vst32 v1 , y # сохранить Y add y , t0 * 4 # продвинуть y на VL*4 add x , t0 * 4 # продвинуть x на VL*4 sub n , t0 # n -= VL (t0) bnez n , vloop # повторить if n ! = 0                                     

По сути, это не сильно отличается от версии SIMD (обрабатывает 4 элемента данных за цикл) или от исходной версии Scalar (обрабатывает только один). n по-прежнему содержит количество элементов данных, которые осталось обработать, но t0 содержит копию VL — число, которое будет обрабатываться на каждой итерации. t0 вычитается из n после каждой итерации, и если n равно нулю, то все элементы обработаны.

При сравнении с вариантом сборки Predicated SIMD следует отметить ряд моментов:

  1. В инструкцию setvlвстроена инструкцияmin
  2. Там, где вариант SIMD жестко запрограммировал как ширину (4) при создании маски, так и ширину SIMD (load32x4 и т. д.), векторные эквиваленты ISA не имеют такого ограничения. Это делает векторные программы портативными, независимыми от поставщиков и перспективными.
  3. Установка VL эффективно создает скрытую маску предиката , которая автоматически применяется к векторам.
  4. Если при использовании предикатного SIMD длина маски ограничена той, которая может храниться в скалярном (или специальной маске) ​​регистре, то векторные регистры маски ISA не имеют такого ограничения. Векторы Cray-I могли содержать чуть более 1000 элементов (в 1977 году).

Таким образом, очень ясно видно, как векторные ISA уменьшают количество инструкций.

Также обратите внимание, что, как и в варианте SIMD с предикатом, указатели на x и y увеличиваются на t0 раз в четыре, поскольку они оба указывают на 32-битные данные, но n уменьшается на прямой t0. По сравнению с ассемблером SIMD фиксированного размера очевидная разница очень незначительна: x и y увеличиваются на жестко запрограммированную константу 16, n уменьшается на жестко запрограммированную 4, поэтому изначально трудно оценить значение. Разница заключается в том, что векторное оборудование может выполнять 4 одновременных операции, или 64, или 10 000, это будет один и тот же векторный ассемблер для всех них, и при этом не будет кода очистки SIMD . Даже по сравнению с SIMD с поддержкой предикатов, он все еще более компактен, понятен, элегантен и использует меньше ресурсов.

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

Кроме того, количество элементов, входящих в функцию, может начинаться с нуля. Это устанавливает длину вектора равной нулю, что фактически отключает все векторные инструкции, превращая их в пустые во время выполнения. Таким образом, в отличие от непредикатного SIMD, даже когда нет элементов для обработки, ненужного кода очистки все равно нет.

Пример векторного сокращения

Этот пример начинается с алгоритма, который включает сокращение. Как и в предыдущем примере, сначала это будет показано в скалярных инструкциях, затем в SIMD и, наконец, в векторных инструкциях, начиная с c :

void ( size_t n , int a , const int x []) { int y = 0 ; for ( size_t i = 0 ; я < n ; я ++ ) y += x [ i ]; вернуть y ; }                          

Здесь аккумулятор (y) используется для суммирования всех значений в массиве x.

Скалярный ассемблер

Скалярная версия этого алгоритма будет загружать каждый из x, добавлять его к y и выполнять цикл:

 установить y , 0 ; y инициализируется нулевым циклом: load32 r1 , x ; загрузить одни 32-битные данные add32 y , y , r1 ; y := y + r1 addl x , x , $4 ; x := x + 4 subl n , n , $1 ; n := n - 1 jgz n , петля ; вернуться в цикл, если n > 0 out: ret y ; возвращает результат, y                             

Это очень просто. «y» начинается с нуля, 32-битные целые числа по одному загружаются в r1, добавляются к y, а адрес массива «x» перемещается к следующему элементу массива.

Снижение SIMD

Здесь начинаются проблемы. SIMD по своей конструкции не способен выполнять арифметические операции «межэлементно». Элемент 0 одного регистра SIMD может быть добавлен к элементу 0 другого регистра, но элемент 0 не может быть добавлен ни к чему другому , кроме другого элемента 0. Это накладывает некоторые серьезные ограничения на потенциальные реализации. Для простоты можно предположить, что n равно ровно 8:

 аддл r3 , x , $16 ; для 2-х 4 из x load32x4 v1 , x ; первые 4 из x load32x4 v2 , r3 ; 2-е 4 из x add32x4 v1 , v2 , v1 ; добавить 2 группы                 

На данный момент было выполнено четыре добавления:

но, например, из-за того, что 4-х SIMD по своей конструкции не может добавляться x[0]+x[1], дела идут быстро, как и в общем случае использования SIMD для циклов IAXPY общего назначения. Чтобы суммировать четыре частичных результата, можно использовать SIMD двухширинного размера с последующим одиночным скалярным сложением, чтобы окончательно получить ответ, но часто данные должны быть переданы из выделенных регистров SIMD, прежде чем можно будет выполнить последнее скалярное вычисление. .

Даже при общем цикле (n не фиксировано) единственный способ использовать SIMD шириной 4 — это предположить четыре отдельных «потока», каждый из которых смещен на четыре элемента. Наконец, необходимо суммировать четыре частичных результата. Другие методы включают перетасовку: в Интернете можно найти примеры для AVX-512 , как выполнить «Горизонтальную сумму» [20] [21]

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

Векторное сокращение ISA

Наборы векторных команд имеют встроенные в ISA операции арифметического сокращения. Если предполагается, что n меньше или равно максимальной длине вектора, требуются всего три инструкции:

 setvl t0 , n # VL=t0=min(MVL, n) vld32 v0 , x # вектор загрузки x vredadd32 y , v0 # уменьшение-добавление в y           

Код, когда n больше максимальной длины вектора, не намного сложнее и аналогичен первому примеру («IAXPY»).

 set y , 0 vloop: setvl t0 , n # VL=t0=min(MVL, n) vld32 v0 , x # вектор загрузки x vredadd32 y , y , v0 # добавить все x в y add x , t0 * 4 # заранее x by VL*4 sub n , t0 # n -= VL (t0) bnez n , vloop # повтор, если n != 0 ret y                             

Простота алгоритма поразительна по сравнению с SIMD. Опять же, как и в примере с IAXPY, алгоритм не зависит от длины (даже во встраиваемых реализациях, где максимальная длина вектора может быть только одна).

Аппаратные реализации могут, если они уверены, что будет получен правильный ответ, выполнять сокращение параллельно. Некоторые векторные ISA предлагают режим параллельного сокращения в качестве явной опции, когда программист знает, что любые потенциальные ошибки округления не имеют значения, и низкая задержка имеет решающее значение. [22]

Этот пример еще раз подчеркивает ключевое фундаментальное различие между настоящими векторными процессорами и процессорами SIMD, включая большинство коммерческих графических процессоров, которые созданы на основе функций векторных процессоров.

Выводы из примеров

По сравнению с любым SIMD-процессором, претендующим на роль векторного процессора, сокращение размера программы на порядок просто шокирует. Однако этот уровень элегантности на уровне ISA имеет довольно высокую цену на аппаратном уровне:

  1. На примере IAXPY видно, что в отличие от процессоров SIMD, которые могут упростить свое внутреннее оборудование, избегая проблем с несогласованным доступом к памяти, векторному процессору такое упрощение не сходит с рук: пишутся алгоритмы, которые по своей сути полагаются на векторную загрузку и сохранение. успешно, независимо от выравнивания начала вектора.
  2. Хотя из примера сокращения видно, что, помимо инструкций перестановки , SIMD по определению полностью избегает межполосных операций (элемент 0 может быть добавлен только к другому элементу 0), векторные процессоры решают эту проблему напрямую. То, что программисты вынуждены делать в программном обеспечении (используя перетасовку и другие трюки, чтобы переместить данные в правильную «дорожку»), векторные процессоры должны делать аппаратно, автоматически.

В целом, тогда есть выбор: либо иметь

  1. сложное программное обеспечение и упрощенное оборудование (SIMD)
  2. упрощенное программное обеспечение и сложное аппаратное обеспечение (векторные процессоры)

Именно эти резкие различия отличают векторный процессор от процессора с SIMD.

Возможности векторного процессора

Хотя многие SIMD ISA заимствованы или вдохновлены приведенным ниже списком, типичными функциями векторного процессора являются: [23] [24] [25]

Функции векторной обработки графического процессора

Поскольку многим приложениям 3D- шейдеров требуются тригонометрические операции, а также короткие векторы для общих операций (RGB, ARGB, XYZ, XYZW), в современных графических процессорах обычно присутствует поддержка следующих функций в дополнение к тем, которые имеются в векторных процессорах:

Ошибка (или сбой) в первую очередь

Представленная в ARM SVE2 и RISC-V RVV концепция спекулятивных последовательных векторных нагрузок. ARM SVE2 имеет специальный регистр под названием «Регистр первого отказа» [34] , где RVV изменяет (усекает) длину вектора (VL). [35]

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

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

Это начинает намекать на причину, по которой ffirst является настолько инновационным, и лучше всего иллюстрируется memcpy или strcpy при реализации со стандартным 128-битным непредикативным SIMD без ffirst. Для IBM POWER9 количество оптимизированных вручную инструкций для реализации strncpy превышает 240. [36] Напротив, та же самая процедура strncpy в оптимизированном вручную ассемблере RVV состоит всего из 22 инструкций. [37]

Приведенный выше пример SIMD потенциально может привести к сбою и сбою в конце памяти из-за попыток прочитать слишком много значений: он также может вызвать значительное количество страниц или ошибок несовпадения из-за аналогичного пересечения границ. Напротив, предоставляя векторной архитектуре свободу решать, сколько элементов загружать, первая часть strncpy, если она изначально начинается на неоптимальной границе памяти, может возвращать ровно столько загрузок, чтобы на последующих итерациях цикла пакеты векторизованного чтения памяти оптимально согласованы с базовыми кэшами и структурами виртуальной памяти. Кроме того, аппаратное обеспечение может использовать возможность завершить чтение памяти любой данной итерации цикла точно на границе страницы (избегая дорогостоящего второго поиска TLB), при этом спекулятивное выполнение подготавливает следующую страницу виртуальной памяти, пока данные все еще обрабатываются в текущей. петля. Все это определяется железом, а не самой программой. [38]

Производительность и ускорение

Пусть r будет коэффициентом скорости вектора, а f будет коэффициентом векторизации. Если время, затраченное векторным модулем на добавление массива из 64 чисел, в 10 раз быстрее, чем у его эквивалентного скалярного аналога, r = 10. Кроме того, если общее количество операций в программе равно 100, из которых только 10 являются скалярными. (после векторизации), то f = 0,9, т. е. 90% работы выполняется векторным блоком. Отсюда следует достижимое ускорение:

Таким образом, даже если производительность векторного блока очень высока ( ), ускорение будет меньше, чем , что предполагает, что отношение f имеет решающее значение для производительности. Это соотношение зависит от эффективности компиляции, например от смежности элементов в памяти.

Смотрите также

Рекомендации

  1. ^ Б. Н. Малиновский (1995). История компьютерных технологий в их лицах . НАБОР. ISBN 5770761318.
  2. ^ Группа вертикальных исследований MIAOW
  3. ^ ГПУ МИАОВ
  4. ^ «Andes анонсирует многоядерный 1024-битный векторный процессор RISC-V: AX45MPV» (пресс-релиз). GlobeNewswire. 7 декабря 2022 г. Проверено 23 декабря 2022 г.
  5. ^ Мияока, Ю.; Чой, Дж.; Тогава, Н.; Янагисава, М.; Оцуки, Т. (2002). Алгоритм формирования аппаратного блока для синтеза процессорного ядра с упакованными инструкциями типа SIMD . Азиатско-Тихоокеанская конференция по схемам и системам. Том. 1. С. 171–176. дои : 10.1109/APCCAS.2002.1114930. hdl : 2065/10689 .
  6. ^ "Riscv-v-spec/V-spec.adoc в мастере · riscv/Riscv-v-spec" . Гитхаб . 16 июня 2023 г.
  7. ^ «Справочное руководство по языку ассемблера Vector Engine» (PDF) . 16 июня 2023 г.
  8. ^ «Документация - Разработчик Arm» .
  9. ^ «Векторная архитектура». 27 апреля 2020 г.
  10. ^ Векторные и SIMD процессоры, слайды 12-13.
  11. ^ Массив и векторная обработка, слайды 5-7
  12. ^ SIMD против Vector GPU, слайды 22-24
  13. ^ Паттерсон, Дэвид А .; Хеннесси, Джон Л. (1998). Организация и проектирование компьютера: аппаратно-программный интерфейс, стр. 751-2 (2-е изд.). Морган Кауфманн. п. 751-2. ISBN 155860491X.
  14. ^ "Riscv-v-spec/V-spec.adoc в мастере · riscv/Riscv-v-spec" . Гитхаб . 19 ноября 2022 г.
  15. ^ Руководство программиста Videocore IV
  16. ^ Анализ Videocore IV QPU Джеффа Буша
  17. ^ «Кодирование для неона. Часть 3. Умножение матриц». 11 сентября 2013 г.
  18. ^ SIMD считается вредным
  19. ^ Учебное пособие по ARM SVE2
  20. ^ "Sse - трансляция 1-к-4 и уменьшение 4-к 1 в AVX-512" .
  21. ^ «Сборка — самый быстрый способ выполнить горизонтальную векторную сумму SSE (или другое сокращение)» .
  22. ^ "Riscv-v-spec/V-spec.adoc в мастере · riscv/Riscv-v-spec" . Гитхаб . 19 ноября 2022 г.
  23. ^ Обзор Крея
  24. ^ RISC-V РВВ ISA
  25. ^ Обзор SX-Арора
  26. ^ Инструкции по сбору и разбросу регистров RVV
  27. ^ «Процессор POWER10 IBM - Уильям Старк и Брайан В. Томпто, IBM» . YouTube . Архивировано из оригинала 11 декабря 2021 г.
  28. ^ Морейра, Хосе Э.; Бартон, Кит; Баттл, Стивен; Бергнер, Питер; Бертран, Рамон; Бхат, Пунит; Кальдейра, Педро; Эдельсон, Дэвид; Фоссум, Гордон; Фрей, Брэд; Иванович, Неманья; Кершнер, Чип; Лим, Винсент; Капур, Шакти; Тулио Мачадо Фильо; Сильвия Мелитта Мюллер; Олссон, Бретт; Садашивам, Сатиш; Салейл, Батист; Шмидт, Билл; Шринивасарагаван, Раджалакшми; Шриватсан, Шричаран; Томпто, Брайан; Вагнер, Андреас; Ву, Нельсон (2021). «Матричное математическое средство для процессоров Power ISA (TM)». arXiv : 2104.03142 [cs.AR].
  29. ^ Крикелис, Анаргирос (1996). «Модульный массово-параллельный процессор для обработки объемной визуализации». Высокопроизводительные вычисления для компьютерной графики и визуализации . стр. 101–124. дои : 10.1007/978-1-4471-1011-8_8. ISBN 978-3-540-76016-0.
  30. ^ «Руководство по программированию CUDA C++» .
  31. ^ LMUL > 1 в RVV
  32. ^ Заброшенный патент США US20110227920-0096.
  33. ^ Видеокор IV QPU
  34. ^ Введение в ARM SVE2
  35. ^ Загрузка при первой ошибке RVV
  36. ^ ИСПРАВЛЕНИЕ к libc6 для добавления оптимизированной strncpy POWER9.
  37. ^ Пример RVV strncpy
  38. ^ Статья ARM SVE2 Н. Стивенса