2016-01-29 3 views
6

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

Что делает компьютер при циклизации, которого он не делает при использовании векторизации (я говорю о фактических вычислениях, которые выполняет компьютер, а не о том, что пишет программист) или что он делает по-другому?

Я не смог убедить себя, почему разница должна быть такой значительной. Вероятно, я мог бы убедить, что векторизованный код в какой-то момент сбрасывает некоторые из них, но компьютер все равно должен выполнять такое же количество операций, не так ли? Например, если мы умножим вектор размера N на скаляр, мы будем иметь N умножений для выполнения в любом случае, не так ли?

+1

Оборудование может быть параллельным. Вы можете xor два 32-битных числа в 1 цикл. Вы можете использовать два 1048576 битовых номера в течение 1 цикла. Просто сожгите еще несколько проводов на чипе. – usr

+0

С помощью современных коротко-векторных SIMD вы используете векторы внутри цикла для обработки целого массива. Старые векторные машины Cray могут настраиваться для большой операции, а затем одна команда будет загружать/управлять/хранить, но это не так, как работают x86 SSE/ARM NEON/PowerPC AltiVec. –

ответ

11

Векторизация (как правило, используется термин) относится к операции SIMD (одна инструкция, несколько данных).

Это означает, что одна команда выполняет одну и ту же операцию над несколькими параллельными операндами. Например, для множественного вектора размера N скаляром назовем M числом операндов, размер которых он может работать одновременно. Если это так, то количество команд, которые ему нужно выполнить, составляет приблизительно N/M, где (с чисто скалярными операциями) он должен будет выполнять N операций.

Например, текущий набор инструкций Intel для AVX 2 использует 256-битные регистры. Они могут использоваться для хранения (и управления) набора из 4 операндов по 64 бита или 8 операндов по 32 бит за штуку.

Итак, если вы имеете дело с 32-битными действительными числами с одной точностью, это означает, что одна команда может выполнять 8 операций (умножений в вашем случае) сразу, поэтому (по крайней мере теоретически) вы можете завершите N умножений, используя только команды умножения N/8. По крайней мере теоретически это должно позволить операции завершить примерно в 8 раз быстрее, чем позволяет выполнение одной команды за раз.

Конечно, точная выгода зависит от того, сколько операндов вы поддерживаете в каждой инструкции. Первые попытки Intel поддерживали только 64-разрядные регистры, поэтому для работы с 8 элементами одновременно эти элементы могут составлять всего 8 бит. В настоящее время они поддерживают 256-битные регистры, и они объявили о поддержке 512-битных (и они, возможно, даже отправили это в несколько высокопроизводительных процессоров, но не в обычные потребительские процессоры, по крайней мере пока). Положительное использование этой возможности также может быть нетривиальным, мягко говоря. Инструкции по расписанию, так что у вас на самом деле есть N операндов, доступных и в нужном месте в нужное время, не обязательно простая задача (вообще).

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

Имейте в виду, что векторизация не - единственный способ, которым центральный процессор может выполнять операции параллельно. Также существует возможность параллелизма уровня инструкций, который позволяет одному процессору (или одному ядру процессора) выполнять одновременно несколько команд. Большинство современных процессоров включают аппаратное обеспечение (теоретически) для выполнения до 4 инструкций за такт, если инструкции представляют собой сочетание нагрузок, хранилищ и ALU. Они могут довольно регулярно выполнять около двух инструкций за такт в среднем или более в хорошо настроенных циклах, когда память не является узким местом.

Тогда, конечно, есть многопоточность - работает несколько потоков инструкций (по крайней мере логически) отдельных процессоров/ядер.

Таким образом, современный процессор может иметь, скажем, 4 ядра, каждый из которых может выполнять 2 векторных умножения за такт, и каждая из этих инструкций может работать на 8 операндах. Таким образом, по крайней мере теоретически, он может выполнять 4 * 2 * 8 = 64 операции за такт.

Некоторые инструкции имеют лучшую или худшую пропускную способность. Например, пропускная способность FP ниже, чем FMA, или умножается на Intel до Skylake (1 вектор за такт вместо 2). Но логическая логика типа AND или XOR имеет 3 вектора на пропускную способность каждого такта; для построения блока выполнения AND/XOR/OR не требуется много транзисторов, поэтому процессоры реплицируют их. Узкие места на общей ширине трубопровода (фронт-сервер, который декодирует и выходит в нестандартную часть ядра) являются общими при использовании высокопроизводительных инструкций, а не узких мест на конкретном исполнительном устройстве.

+0

В моем вступительном курсе компьютерных систем (и в нашем параллельном курсе программирования) мы рассматривали процессор (или одно ядро ​​многоядерного процессора) как систему с черным ящиком, которая может ТОЛЬКО делать вещи последовательно; вычисления не могли быть вычислены одновременно. Это неправильно? Или у ядра есть свои собственные подпроцессоры, которые могут выполнять простые вычисления? –

+2

Да, в отношении современного (разумно высокого класса) процессора это неверно. Главные настольные/серверные процессоры поддерживали различные типы параллелизма на протяжении десятилетий. Чисто последовательным будет (например) 486, но больше не относится к оригинальному Pentium. На мэйнфреймах те же самые вещи случались еще дольше (например, у CDC 6500 была архитектура, похожая на Pentium, а 6600 похожа на Pentium Pro). Они были выпущены около 1964 года или около того. –

+0

Большинство современных процессоров имеют ширину конвейера 4 uops (Intel с Core2, AMD с Bulldozer). Это дает вам 4 инструкции за такт, если у вас есть соединение нагрузок, хранилищ и однократных инструкций ALU. (пары сравнения + пары ветвлений могут сливаться в 1 мкп, поэтому истинный максимальный IPC Хасуэлла составляет 6 инструкций за такт, но гораздо более реалистично, чтобы просто сказать 4.) Трубопровод Райцена имеет ширину 6, но инструкции с одним-юопом могут работать только 5 Часы. (Векторы AVX/AVX2 256b декодируются до 2 мкп и могут хорошо заполнять трубу.) Core2 вряд ли выполнит 4 IPC, за исключением специально созданных циклов, но это реалистично для SKL. –

1

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

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

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

+0

Итак, векторный код имеет радикально различную реализацию? Он фактически просто распределяет операции между другими ядрами? Если да, означает ли это, что одноядерный процессор не будет иметь преимуществ от векторизации или есть ли «субблочные» аппаратные «единицы» (из-за отсутствия лучшего слова) внутри каждого ядра, которые все равно помогут ускорить работу? –

0

Векторизация имеет два основных преимущества.

  1. Основное преимущество состоит в том, что аппаратные средства предназначены для поддержки векторных инструкций в общем случае имеет аппаратные средства, которые способны выполнять несколько операций АЛУ в общем случае, когда используются векторные инструкции. Например, если вы попросите его выполнить 16 дополнений с 16-элементной векторной инструкцией, у него может быть 16 параллельных сумматоров, которые могут выполнять все добавления одновременно. Только путь доступа ко всем тем суммам - через векторизация. С помощью скалярных инструкций вы получите только один одиночный сумматор.

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

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


Или, по крайней мере, 15 из 16, возможно, один используется также делать скалярные операции.

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

Смежные вопросы