Оптимизация для pentium процессора список инструкций с плавающей точкой

Содержание

Оптимизация для pentium процессора список инструкций с плавающей точкой

ОПТИМИЗАЦИЯ
6.1. Приемы оптимизации для процессоров Intel Pentium

Все, что здесь написано, является выборкой наиболее важных на мой взгляд фактов из документации от Agner Fog. Если вы серьезно интересуетесь оптимизацией для Intel Pentium (plain, MMX, PPro, P2), найдите и прочтите эту документацию (я нашел на www.agner.org/assem .

6.1.1. Спаривание целочисленных команд

По-моему, основной прием ускорения. Дело в том, что у процессоров Pentium есть два конвейера обработки команд, U-pipe и V-pipe. В результате некоторые пары команд могут исполняться одновременно, а это практически удваивает скорость.

Эти команды могут быть исполнены и в U-pipe, и в V-pipe, и при этом могут быть спарены (с какой-либо другой командой):

mov reg/mem,reg/mem/imm
push reg/imm
pop reg
lea, nop, inc, dec, add, sub, cmp, and, or, xor
некоторые формы test

Эти команды могут быть исполнены только в U-pipe, но при этом все-таки могут быть спарены:

adc, sbb
shr, sar, shl, sal на заданное число
ror, rol, rcr, rcl на единичку

Эти команды могут быть исполнены в любом конвейере, но могут быть спарены только в V-pipe:

near call (близкий вызов)
short/near jump (короткий/близкий переход)
short/near conditional jump (короткий/близкий переход по условию)

Все остальные целочисленные команды могут быть исполнены только в U-pipe и не могут быть спарены вообще.

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

    Первая команда может быть исполнена и спарена в U-pipe, вторая, соответственно, в V-pipe.

Если первая команда записывает что-то в регистр, то вторая команда не может производить чтение/запись из регистра. Причем, в этом условии части регистров считаются за весь регистр (то есть, запись в al/ah расценивается как запись в eax, а запись в cf — как запись в flags).

  • Две команды, записывающие что-то в регистр флагов, могут быть спарены, несмотря на условие 2:
  • Команда, записывающая что-то в регистр флагов, может быть спарена с условным переходом, несмотря на условие 2:
  • Следующие пары команд могут спариться несмотря на то, что обе команды изменяют esp:
  • Существуют ограничения на исполнение команд с префиксом. Префиксы возникают в таких случаях:
    • команда, адресующаяся не к сегменту по умолчанию, имеет префикс сегмента (примеры: mov eax,es:[ebx]; mov eax,ds:[ebp])
    • команда, работающая с 16-битными операндами в 32-битном режиме или с 32-битными операндами в 16-битном режиме, имеет префикс разрядности операнда (примеры: mov ax,1234 в защищенном режиме; mov ax,word ptr [variable] в защищенном режиме; xor eax,eax в реальном режиме)
    • команды, использующая 32-битную адресацию в 16-битном режиме, имеет префикс разрядности адреса (пример: mov ax,[ebx] в реальном режиме)
    • rep, lock — префиксы (пример: rep stosd)
    • многие команды, которых не было на 8086, имеют двухбайтовый код команды, где первый байт равен 0Fh. На процессоре Pentium без MMX этот байт считается префиксом. Наиболее часто встречающиеся команды с префиксом 0Fh: movzx, movsx, push/pop fs/gs, lfs/lgs/lss, setXX, bt/btc/btr/bts/bsf/bsr/shld/shrd, imul с двумя операндами и без операнда-числа (immediate).

    На процессоре Pentium без MMX команда с префиксом может исполняться только в U-pipe, исключение — близкие переходы по условию (conditional near jumps). На процессоре Pentium с MMX команды с префиксами 0Fh и размера операнда или адреса может исполняться в любом конвейере; но команды с префиксами сегмента, rep или lock (повторения или блокировки шины) могут исполняться только в U-pipe.

    Команда, в которой одновременно участвует смещение (displacement) и заданное число (immediate) не может быть спарена на процессоре Pentium без MMX и может быть выполнена и спарена только в U-pipe на процессоре Pentium с MMX. Вот примеры:

    Спаривающаяся команда, которая читает из памяти, считает и записывает результат в регистр или в регистр флагов занимает 2 такта. Спаривающаяся команда, которая читает из памяти, считает и записывает результат обратно в память занимает 3 такта. Примеры таких команд:

    Существует также так называемое неполное спаривание (imperfect pairing), когда обе команды выполняются в разных конвейерах, но НЕ одновременно (возможно, частично перекрываясь по времени исполнения), а следующие за ними команды не могут начать исполнение, пока обе команды не закончатся. Такое случается в следующих случаях:

    1. Вторая команда вызывает AGI (address generation interlock, блокировка генерирования адреса). Это происходит, если адрес, используемый во второй команде зависит от регистров, измененных в первой команде. Примеры:
    2. Две команды одновременно обращаются к одному и тому же двойному слову памяти. Примеры (подразумевается, что esi делится на 4):
    3. Две команды одновременно обращаются к адресам, в которых одинковы биты 2-4 (это вызывает конфликт кэш-банков). Для dword-адресов это значит, что разница между двумя адресами делится на 32. Пример:
    4. Первая команда производит чтение, подсчет и запись одновременно; вторая — чтение и изменение; в этом случае число тактов, требующееся для выполнения пары команд, можно рассчитать по следующей таблице:
    первая команда
    вторая команда mov или
    регистровая
    чтение/
    подсчет
    чтение/подсчет/
    запись
    mov или регистровая 1 2 3
    чтение/подсчет 2 2 4
    чтение/подсчет/запись 3 3 5

    У процессора Pentium непосредственно на кристалле есть 8k кэш-памяти (это т.н. кэш-память первого уровня, L1 cache) для кода и 8k — для данных. Данные из L1 cache считываются/записываются за один такт; кэш-промах же может стоить довольно много тактов. Таким образом, для наиболее эффективного использования кэша необходимо знать, как он работает.

    Итак, L1 cache состоит из 256 кэш-линий (cachelines), по 32 байта в каждой. При чтении данных, которых нет в кэше, процессор считывает из памяти целую кэш-линию. Кэш-линии всегда выравнены на физический адрес, делящийся на 32; так что если прочитать байт по адресу, делящемуся на 32, то можно читать и писать в следующий за ним 31 байт без всяких задержек. Свои данные имеет смысл располагать с учетом этого факта — например, выравнивать массивы из структур длиной 32 байта на 32; перед записью в видеопамять читать оттуда один байт (один раз на 32 записываемых байта); используемые вместе данные располагать вместе; и так далее.

    Но кэш-линия не может быть связана с любым физическим адресом. У каждой кэш-линии есть некое 7-битное «заданное значение» (set-value), которое должно совпадать с битами адреса 5-11. Для каждого из 128 возможных значений set-value есть две кэш-линии. Отсюда следует то, что в кэше не может одновременно содержаться более двух блоков данных с одинаковыми битами адреса 5-11. Чем это чревато, покажем на примере.

    У используемых трех адресов будет одинаковое значение в битах 5-11. Поэтому к моменту самого первого чтения в ecx в кэше точно не окажется свободной кэш-линии, процессор выберет для нее наименее использованную (least recently used) линию, ту самую, которая была использована при чтении eax. При чтении ebx, соответственно, будет заново перекрыта линия, использованная при чтении ecx. В результате цикл будет состоять из сплошных кэш-промахов и съест порядка 60 тактов. Если же поменять 28 на 32, изменив, таким образом, на единичку биты 5-11 для адреса [esi+20*4096+28], то для чтения в eax и ebx будут как раз использованы две имеющихся линии, для чтения в ecx — третья, не совпадающая ни с одной из этих двух. В результате — скорость порядка трех тактов на один проход и ускорение примерно в 20 (. ) раз.

    Еще одна интересная вещь, которую стоит учесть — Pentium НЕ загружает кэш-линию при промахе записи; только при промахе чтения. При промахе записи данные пойдут в L2 cache или память (в зависимости от настроек L2 cache). А это довольно медленно. Поэтому, если мы последовательно пишем в один и тот же 32-байтовый блок, но не читаем оттуда, то имеет смысл сначала сделать холостое чтение из этого блока, чтобы загрузить его в L1 cache; тогда все последовательные операции записи будут есть только по одному такту.

    6.1.3. Разные трюки

    Трюков есть много, перечислим здесь только наиболее часто используемые:

    работа с fixed point вместо floating point иногда (если код не слишком сильно насыщен математикой) быстрее; практически всегда быстрее для клонов;

    все данные желательно выравнивать по адресам, кратным размеру данных (то есть, переменные-байты можно не выравнивать, слова — выравнивать на 2, двойные слова — на 4); обращение к невыравненной переменной влечет за собой задержку минимум на три такта;

    деление на заранее известное число можно заменить умножением на обратное ему число;

    деление на степень двойки для целых чисел заменяется на сдвиг влево; деление чисел с плавающей точкой (fdiv) на Intel Pentium (на клонах, к несчастью, это не так) может исполняться параллельно с целочисленными командами.

    Проектирование процессора с плавающей точкой (стр. 1 из 4)

    Пояснительная записка к курсовому проекту по дисциплине

    «Организация ЭВМ и систем»

    «Проектирование процессора с плавающей точкой»

    Выполнил студент гр.343

    1. Описание команд

    1.1. FMul ST, ST(i) — умножение

    1.2. FSt m32real — сохранение

    2. Форматы данных

    2.1. Внутренний формат

    2.2. Внешний формат

    2.3. Пример формата m80real

    2.4. Пример формата m32real

    3. Программная модель процессора

    4. Блок – схема процессора

    5. Алгоритмы операций

    5.1. Алгоритм операции FMulSt,St(i)

    5.2. Алгоритм операции FSt m32real

    6. Структурные схемы блоков процессора

    6.2. Блок преобразования форматов

    6.3. Блок регистров

    6.4. Блок обработки данных (блок умножения)

    6.5. Блок микропрограммного управления

    7. Моделирование операции FMul St,St(i)

    Список использованных источников

    FMul ST, ST(i) — умножение.

    Команда умножения умножает операнды источника и получателя и возвращает произведение в получатель.

    Оба операнда находятся в регистровом стеке в формате 80real.

    Умножение с анализом младшего бита множителя со сдвигом множимого.

    Особые случаи: P, U, O, D, I.

    Особые случаи: P, U, O, D, I.

    Емкость ОП 4 Кбайт.

    Длина слова памяти 128 бит.

    С появлением процессора i486 и его сопроцессора FPU – сопроцессора с плавающей точкой, работа с вещественными числами стала аппаратной, а не программной задачей. Производительность ЭВМ увеличилась. Возможности использования ЭВМ в бухгалтерии и многих других областях деятельности человека дали толчок массовому внедрению их в повседневную жизнь. Были переписаны многие программы, компиляторы. Освоение архитектуры, принципов работы сопроцессора FPU стало для программистов едва ли не основной задачей.

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

    1.1. FMulST, ST(i) — умножение.

    Команда умножения умножает операнды источника и получателя и возвращает произведение в получатель.

    Оба операнда находятся в регистровом стеке в формате 80real.

    Умножение с анализом младшего бита множителя со сдвигом множимого.

    P — неточный результат;

    D — денормализованный операнд;

    I — недействительная операция.

    Формат команды представлен на рисунке 1.1

    Адрес второго операнда определяется полем ST(i), которое принимает значения от 000 до 111, где 000 – вершина стека, 111 – восьмой элемент регистрового стека.

    Бит R показывает, возвращается ли результат в вершину стека. В данном случае R = 0.

    Бит P указывает, что после операции производится извлечение из стека. P = 0, так как извлечения нет.

    Команда FSt m32real передает значение из регистра ST в ОП. Содержимое ST остается неизменным.

    P — неточный результат;

    D — денормализованный операнд;

    I — недействительная операция.

    Формат команды представлен на рисунке 1.2

    Адрес операнда m32real определяется полями mod, r/m, SIB, Disp. Адрес вычисляется целочисленным процессором. К началу операции он уже сформирован. Бит [0] первого байта команды определяет тип операции.

    В данном случае Бит [0] = 1 – передача данного из стека в память.

    Поле MF определяет тип операнда. При m32realMF = 00.

    2.1. Внутренний формат.

    Во внутренних операциях процессор с плавающей точкой (ППТ) использует представление вещественных чисел в формате с расширенной точностью (РТ, m80real) (рис.2.1). Длина формата 80 бит.

    Значащие цифры числа находятся в поле мантиссы (М). Длина мантиссы 64 бита. Поле порядка (E) показывает фактическое положение двоичной точки в разрядах мантиссы. Длина порядка 15 бит. Бит знака (S) определяет знак числа. Мантисса представлена в прямом коде. Порядок задается в смещенной форме; он равен истинному порядку (П), увеличенному на значение смещения – смещ РТ = 16383:

    Истинный порядок изменяется от –16382 до 16383. Порядки 000…0b и 111…1b зарезервированы для специальных значений. Числа в формате РТ имеют явный бит F0.

    Значение числа в формате РТ равно

    В данном курсовом проекте рассматривается один внешний формат m32real – формат обычной точности (ОТ) (рис.2.2). Длина формата 32 бита.

    Значащие цифры числа находятся в поле мантиссы (М). Длина мантиссы 23 бита. Поле порядка (E) показывает фактическое положение двоичной точки в разрядах мантиссы. Длина порядка 8 бит. Бит знака (S) определяет знак числа. Мантисса представлена в прямом коде. Порядок задается в смещенной форме; он равен истинному порядку (П), увеличенному на значение смещения – смещ ОТ = 127:

    Истинный порядок изменяется от –126 до 127. Порядки 000…0b и 111…1b зарезервированы для специальных значений. Явный бит F0 в формате ОТ отсутствует и мантисса оказывается правильной дробью.

    Значение числа в формате ОТ равно

    Покажем представление десятичного числа 24789.8125 в формате РТ. Двоичный код числа равен 110000011010101.1101b, истинный порядок равен 14. Смещенный порядок E=14+16383=16397=100000000001101b. Число в формате РТ приведено на рис. 2.3.

    Покажем представление десятичного числа -85.125 в формате ОТ. Двоичный код числа равен -1010101.001b, истинный порядок равен 6. Смещенный порядок E=6+127=133=10000101b. Число в формате ОТ приведено на рис. 2.4.

    Программная модель (рис. 3.1) включает в себя кольцевой стек из восьми регистров R0-R7, слово тэгов TW, слово состояния SW и слово управления CW. В стеке хранятся числа в формате РТ. В полях S, Е и М регистров записаны соответственно знак, порядок и мантисса. Вершина стека определяется полем TOP слова состояния SW и обозначается ST(0), или просто ST. На рисунке вершиной стека является физический регистр R3. ST(0) содержит последнее включенное в стек значение, регистр ST(1) предпоследнее и т.д. Включение в стек осуществляет декремент TOP и загрузку в новую вершину стека. При извлечении из стека данное читается из ST(0), а затем производится инкремент TOP.

    С каждым регистром стека ассоциируется двухбитный тэг, характеризующий хранимое число:

    00 — нормализованное число;

    01 — истинный нуль;

    10 — денормализованное число, бесконечность или неопределенность;

    11 — пустой регистр.

    В слове состояния SW поле TOP содержит адрес текущей вершины стека. Биты кода условия C0-C3 фиксируют результаты команд сравнения, проверки и анализа. Восемь бит отведены для регистрации особых случаев (ошибок) (рис.3.2).

    При выполнении команд с ПТ возможны следующие особые случаи:

    ·P – неточный результат (точность);

    ·D – денормализованный операнд;

    ·I – недействительная операция;

    ·Z – деление на нуль.

    Особым случаям соответствуют флажки в слове состояния SW (рис.3.2): IE, ZE, DE, OE, UE, PE. При любом особом случае устанавливается бит суммарной ошибки ES, а также вырабатывается активный сигнал ошибки FERR.

    В слове управления CW поле RCзадает режим округления, когда формат получателя не позволяет точно представить результат. Пусть B – точный результат, A и C – ближайшие к нему представимые в заданном формате числа: A

    Особенности архитектуры процессоров Pentium III и Pentium IV

    Разработка процессоров Pentium III и Pentium IV определяла не только создание процессоров с новым уровнем производительности, но имела своей основной целью обеспечить эффективную поддержку мультимедийных и 3D технологий.

    Архитектурные особенности процессоров Pentium III:

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

    2. Технология обработки мультимедиа-данных Intel MMX™. Технология Intel MMX предусматривает поддержку набора из 57 целочисленных команд и четырех типов данных общего назначения, легко применимых для оптимизации широкого круга мультимедийных и коммуникационных приложений. В рамках этой технологии используется расширение «Одна инструкция над множественными данными» (Single Instruction, Multiple Data, SIMD); в процессор введены восемь 64-разрядных регистров технологии MMX.

    3. Технология динамического исполнения:

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

    · Анализ потока данных: переупорядочивает очередь выполнения команд, анализируя зависимости их операндов.

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

    4. Самотестирование и мониторинг производительности:

    · Функция самотестирования (Built In Self Test, BIST) обеспечивает обнаружение одиночных неисправностей — типа остановки микрокоманды и ошибки в логических матрицах, а также тестирует кэш-память, буферы TLB и целостность микрокода.

    · Порт тестового доступа и архитектура сканирования окружения, соответствующие стандарту IEEE 1149.1, позволяют проверять процессоры Pentium III с помощью стандартного интерфейса.

    · Встроенный датчик производительности обеспечивает возможность мониторинга быстродействия и подсчета событий.

    · Встроенный в матрицу термодиод, измеряющий ее температуру. Системные платы позволяют использовать его для мониторинга температуры процессора.

    5. Внедрена высокопроизводительная архитектура двойной независимой шины (Dual independent Bus, DIB), разделяющая системную шину и шину кэш-памяти, повышающая скорость обмена данными, производительность и масштабируемость по мере развития новых технологий.

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

    7. Неблокируемая объединенная кэш-память второго уровня (L2) объемом 512 Кб повышает производительность, сокращая среднее время доступа к памяти путем хранения часто используемых команд и данных. Пропускная способность кэш-памяти увеличена благодаря использованию отдельной 64-разрядной шины. Скорость работы кэш-памяти второго уровня растет с увеличением частоты процессора. Кроме того, в процессор встроена раздельная кэш-память первого уровня для команд и данных, объемом по 16 Кб. Процессоры поддерживают кэширование до 4 Гб памяти.

    8. Процессоры поддерживают функцию распознавания и коррекции ошибок (Error Correction Code, ECC) на шине кэш-памяти второго уровня для приложений с повышенными требованиями к целостности данных.

    9. Конвейеризованное устройство операций с плавающей точкой (Floating-Point Unit, FPU) поддерживает как 32-разрядный и 64-разрядный форматы IEEE 754, так и 80-разрядное представление чисел.

    10. Технология запроса адреса памяти и ответа системной шины с проверкой четности и возможностью повтора повышает надежность обмена данными.

    Pentium IV радикально отличается от своих предшественников. Архитектуре этих процессоров дано имя NetBurst. Рассмотрим важнейшие особенности процессора:

    1. Гиперконвейерная архитектура: Pentium IV отличается от предшественников конвейером, длина которого составляет не менее 20 стадий (конвейер Pentium III насчитывает 10 стадий). Именно поэтому новый процессор способен работать на сверхвысоких частотах. В самом деле: если последовательность исполнения команды разбита на более мелкие этапы, то каждый из них процессор сможет выполнять быстрее, следовательно, тактовую частоту ЦП можно повысить. К сожалению, длинный конвейер не лишен недостатков. Основной его враг — инструкции условных переходов. Процессор, выполняя такую команду, в зависимости от определенного условия должен либо совершить переход на новый адрес, либо продолжить обработку следующей инструкции. Все современные процессоры стараются предсказать результат каждого ветвления до того, как условие перехода будет вычислено. Если прогноз окажется верным, ЦП будет работать без простоев. Если предсказание ошибочно, процессору приходится очищать весь конвейер и запускать его заново. Pentium IV ошибается в предсказании ветвлений на треть реже, чем Pentium III.

    2. Кэш трассировки исполнения (Execution trace cache): Pentium IV отличается от х86-совместимых процессоров уникальной организацией кэш-памяти. Pentium III и Athlon используют одну половину кэш первого уровня (L1) для хранения инструкций, а другую – для данных. Все современные ЦП исполняют громоздкие инструкции х86, предварительно разбив их на простые и удобные для обработки микрооперации. Декодеры Pentium III и Athlon считывают команды из кэш-памяти первого уровня и делят их на микрокоманды, которые передаются исполнительному устройству. Такая схема имеет два серьезных недостатка:

    · Во-первых, если декодеру попадается сложная инструкция, то исполнительному устройству приходится простаивать до тех пор, пока она не будет преобразована в микрооперации;

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

    Pentium IV не хранит инструкции в кэш первого уровня. Вместо этого процессор помещает уже декодированный код в так называемом кэш трассировки исполнения (Execution Trace Cache).

    Иными словами, в новом кэш хранятся не классические инструкции х86, а готовые к исполнению микрооперации. Такой подход позволяет избежать описанных выше проблем. Во-первых, исполнительные устройства Pentium IV не ждут декодера, а считывают микрокоманды непосредственно из кэш трассировки исполнения. Во-вторых, если цикл полностью помещается в новый кэш, процессору не приходится декодировать его многократно. В Execution Trace Cache можно хранить до 12000 микрокоманд.

    Объем кэш первого уровня Pentium IV (данных) составляет всего восемь килобайт. Для сравнения: L1-кэш Pentium III и Athlon могут хранить до 16 и 64 килобайт данных соответственно; объем принесен в жертву скорости — на ожидание данных из кэш первого уровня Pentium IV тратит всего два такта, а его конкуренты — минимум три.

    Кэш второго уровня соединен с ядром широкой 256-битной шиной данных (Intel называет эту конфигурацию Advanced Transfer Cache).

    3. Механизм ускоренного выполнения (rapid execution engine): Все современные процессоры оснащены не одним, а несколькими АЛУ (арифметико-логическими устройствами, то есть блоками, выполняющими арифметические и логические операции над целочисленными данными). Инструкции х86 плохо поддаются распараллеливанию; очень часто процессор не может обработать команду до тех пор, пока не вычислит результат предшествующей ей инструкции. Такие пары команд называются зависимыми. Поскольку обрабатывать их параллельно нельзя, процессору приходится вычислять их по очереди.

    Чтобы максимально сократить время исполнения зависимых инструкций, Pentium IV оснащен двумя АЛУ, работающими на удвоенной частоте процессора. Каждое из них может исполнить за такт две простых операции (сложение, вычитание и логические). На удвоенной частоте обрабатываются не все арифметические команды, а лишь простейшие из них. Сложные операции (например, умножение) Pentium IV выполняет на своей номинальной частоте.

    4. SSE2: Набор SIMD-инструкций SSE, появившийся в процессорах Pentium III, не только включен в Pentium IV, но и существенно расширен. К имевшимся 70 командам добавлено еще 144. SIMD-инструкции (Single Instruction Multiple Data — одна инструкция над многими данными) производят арифметические операции над несколькими (более чем двумя) операндами. Прежние команды SSE позволяли обработать одновременно четыре пары вещественных чисел одинарной точности (восемь 32-битных чисел с плавающей запятой). Другие типы данных SSE не обрабатывает. Команды, появившиеся в SSE2, могут работать с двумя парами вещественных чисел двойной точности (четырьмя 64-битными числами с плавающей запятой) и целочисленными операндами длиной от одного до 16 байт. Добавлены также новые команды, управляющие кэшированием данных.

    Самым важным нововведением в SSE2 следует признать поддержку SIMD-операций над вещественными числами двойной точности. Напомним, что SSE и 3Dnow! работают лишь с операндами одинарной точности, недостаточной для многих инженерных приложений. AMD едва ли сможет добавить в свой набор команд операции над вещественными числами двойной точности. Дело в том, что инструкции 3DNow! хранят операнды в 80-разрядных регистрах математического сопроцессора, и втиснуть в такой регистр два 64-битных числа в принципе невозможно.

    5. Системная шина: Вместе с оригинальным ядром Pentium IV получил обновленную системную шину (FSB). От FSB процессоров Pentium III она отличается возможностью передавать данные четыре раза за такт (Intel называет этот режим «Quad Pumped»). Таким образом, даже работая на скромной частоте 100 мегагерц, эта 64-разрядная шина может передавать информацию со скоростью до 3.2 Гбайт/с. Впрочем, даже самая быстрая шина будет простаивать, если память не сможет поставлять данные с адекватной скоростью.

    Pentium IV подобный дисбаланс не грозит. Материнские платы для этого процессора оснащаются двухканальным контроллером памяти. Пропускная способность каждого канала может достигать 1.6 Гбайт/с; таким образом, суммарная полоса пропускания RAM достигает внушительной цифры 3.2 Гбайт/с.

    Не нашли то, что искали? Воспользуйтесь поиском:

    Оптимизация для pentium процессора список инструкций с плавающей точкой

    1. Введение в архитектуру INTEL

    1.1. Краткая история архитектуры INTEL

    Развитие архитектуры Intel (IA) может быть прослежено от микропроцессоров 8085 и 8080 до микропроцессора 4004 (первого микропроцессора, созданного Intel в 1969). Однако, первым настоящим процессором в семействе IA является 8086, и выпущенный вслед за ним более дешевый процессор 8088. Объектный код программ созданных для этих процессоров может быть запущен и на более поздних версиях процессора семейства IA.

    Процессор 8086 имеет 16-разрядные регистры и 16-разрядную внешнюю шину данных, с 20-разрядной адресацией которая позволяет адресовать 1-Mbyte адресного пространства. Процессор 8088 такой же за исключением меньшей внешней шины данных — 8 бит. В эти процессоры вводится сегментация, но только в “Реальном Режиме”; 16-разрядные регистры могут действовать как указатели на адрес в сегментах размером до 64 KBytes. Четыре сегментных регистра содержат 20-разрядный базовый адрес текущего активного сегмента; значит без переключения между сегментами можно адресовать до 256 KBytes.

    В процессоре Intel 80286 вводится Защищенный Режим. Этот новый режим использует содержимое сегментных регистров как селектор или указатель в таблице дескриптора. Дескриптор хранит 24-битный базовый адрес, позволяющий адресовать до 16 Mbyte физической памяти, поддерживает виртуальное управление памятью и различные механизмы защиты. Это включает проверку границы сегмента, опции сегментов только для чтения и только для запуска, и четыре уровня привилегей для защиты кода операционной системы (в некоторых подразделах, если требуется) от приложений или программ пользователя. Более того, переключение задач и локальная таблица дескриптора позволяет операционной системе защитить приложения или программы пользователя друг от друга.

    В процессоре Intel386 вводятся в архитектуру 32-разрядные регистры, для использования в вычислениях и адресации памяти. Нижняя половина каждого 32-разрядного регистра имеет значение одного 16-разрядного регистра предыдущих двух поколений, для обеспечения полной обратной совместимости. Был введен новый Виртуальный Режим 8086 для повышения быстродействия на новой 32-разрядной машине программ созданных для процессоров 8086 и 8088. 32-разрядная адресация поддерживается внешней 32-битной шиной адреса, что позволяет адресовать 4-GByte адресного пространства, и также позволяет чтоб размер каждого сегмента был до 4-GByte. Первоночальные инструкции были расширены новыми инструкциями с 32-разрядными операндами и формой адресации. В процессоре Intel386 также вводится страничная организация памяти, с фиксированным размером страницы 4-Kbyte, она предусматривает метод для управления виртуальной памятью который значительно лучше использования сегментов (это было намного эффективнее для операционных систем, и полностью прозрачно для приложений без значительной потери в скорости). Кроме того, возможность определения сегментов размером в 4-GBytes физического адресного пространства, вместе с страничной организацией памяти, позволяет создавать защищенную “плоскую модель” адресной системы, включая полную поддержку широко используемых на mainframe операционной системы UNIX.

    В архитектуре процессоров Intel поддерживается обратная совместимость с объектным кодом для сбережения инвестиций в программное обеспечение, но в тоже время, в каждом новом поколении используются все более эффективные микропроцессорные архитектуры и технологии конструирования. Intel работала по внедрению и соединению сложной техники архитектуры mainframe в микропроцессорную архитектуру. Многие модели паралельной обработки намного усиливали производительность техники, и процессор Intel386 был первым процессором IA в который включили шесть паралельных стадий. Это Интерфейсный Блок Шины (доступ к памяти и устройству ввода/вывода других блоков), Блок Предварительного Кода (получает объектный код из Блока Шины и помещает его в 16-байтную очередь), Блок Декодирования Инструкции (декодирует объектный код из Предварительного блока в микрокод), Блок Выполнения (выполняет инструкции микрокода), Сегментный Блок (переводит логические адреса в линейные адреса и выполняет проверку защиты), и Страничный Блок (переводит линейные адреса в физические, выполняет проверку страничной защиты, и содержит кэш с информацией о 32 наиболее часто используемых страницах).

    В процессор Intel486 добавлена возможность параллельного выполнения, с помощью расширения Блока Декодирования Инструкции и Блока Выполнения процессора Intel386 в пять конвейерных стадий, где каждая стадия (если нужно) работает параллельно с другими и одновременно может выполняться до пяти инструкций в разных стадиях. Каждая стадия может выполнить свою работу над одной инструкцией за один такт, то есть процессор Intel486 может выполнить работу над одной инструкцией за один такт CPU. Также к процессору Intel486 был добавлен 8-Kbyte чип кэша L1 для увеличения процента инструкций которые могут быть выполнены за один такт: инструкции доступа в память (если операнд находился в кэше L1). В процессоре Intel486 впервые на чип с CPU был интегрирован Блок арифметического устройства с плавающей запятой (FPU) и добавлены новые контакты, биты, и инструкции для поддержки более сложных и мощных систем (поддержку L2 кэша и мультипроцессорности).

    Позже в поколение процессоров Intel486, Intel добавила в процессор Intel486 SL Enhanced (расширенный) функции поддержки энергосбережения и другие возможности системного управления. Эти функции были развиты в процессорах Intel386 SL и Intel486 SL, которые были специализированы для быстро растущего рынка ноутбуков PC работающих от батарей. Эти функции включали новый Режим Управления Системой, запускаемый собственным выделенным контактом прерывания, который позволяет управлять системой (такой как управление энергосбережением) и добавляется к системе прозрачно для других операционных систем и всех приложений. Функции Стоп Таймер и Автоматическая Остановка позволяют CPU работать на пониженной частоте (для сохранения энергии), или остановиться (с сохранением текущего состояния).

    В процессор Intel Pentium для достижения суперскалярной производительности была доблавлена вторая линия конвейерной обработки (две линии конвейера, известных как u и v, вместе могут выполнять две инструкции за один такт). Также был удвоен кэш L1, 8-Kbyte для кода, и другие 8-Kbyte для данных. Кэш данных для обеспечения более эффективного режима обратной записи использует протокол MESI. Для увеличения производительности в конструкциях циклов было добавлено прогнозирование ветвлений с чипом таблицы переходов. Основные регистры остались 32 битные, но добавилась внутренняя шина данных 128 и 256 бит, для увеличения скорости внутренней передачи данных, и внешняя шина данных была увеличена до 64 бит. Был добавлен Дополнительный Программируемый Контролер Прерываний (Advanced Programmable Interrupt Controller) для поддержки систем с несколькими процессорами Pentium, и для поддержки двух процессорных систем были разработаны новые контакты и специальный режим (dual processing) .

    В процессор Intel Pentium Pro добавлено “Динамическое Выполнение”. Он имеет трехходовую суперскалярную архитектуру, это значит что процессор может выполнять три инструкции за каждый такт CPU. Это осуществляется внедрением большего параллелизма чем в процессоре Pentium. В суперскалярной реализации процессора Pentium Pro предусматривается Динамическое Выполнение (анализ потоков микро-данных, нестандартное выполнение, улучшенное прогнозирование ветвлений, и прогностическое выполнение). Три устройства декодирования инструкций работают параллельно декодируя объектный код в более малые операции называемые “микрокодом” (“micro-ops”). Они попадают в накопитель инструкций, и (когда нет взаимосвязи) могут быть выполнены пятью параллельными блоками выполнения (два целых, два FPU и один блок для работы с памятью). Блок Сброса изъемает выполненый микрокод в порядке настоящего расположения в программе, учитывая все ветвления. Мощность процессора Pentium Pro дополнительно расширена его кэшом: он имеет такие же два 8-KByte чипа кэша L1 как и у процессора Pentium, и к тому же у него есть 256-KByte кэш L2 который находится в том же корпусе что и CPU, использует выделенную 64-разрядную шину. Кэш L1 — двухпортовый, кэш L2 поддерживает до 4 паралельных обращений, и 64-разрядная внешняя шина данных ориентированна по направлению входных данных, это значит что каждое обращение описывается отдельным запросом и ответом, с многочисленными запросами пока ожидается ответ. Эти функции паралелизма для доступа к данным работают с возможностью параллельного выполнения для обеспечения “non-blocking” архитектуры в которой процессор намного полнее используется. Также в процессоре Pentium Pro шина адреса увеличена до 36-бит, что позволяет адресовать до 64 Gbytes физического адресного пространства.

    В процессор Pentium II к архитектуре процессора Pentium Pro добавлены команды MMX. Для процессора Pentium II вводится новая спецификация установки в материнскую плату слот 1 и слот 2. В этой новой спецификации кэш L2 выносится из кристала. Для слот 1 и слот 2 используются ножевое соединение вместо сокет. В процессоре Pentium II увеличен кэш данных L1 и кэш инструкций L1 до 16 KByte каждый. В процессоре Pentium II размер кэша L2 может быть 256 KBytes, 512 KBytes и 1 MByte или 2 MByte (только для слот 2). Процессоры слота 1 используют “половинную тактовую частоту” шины, а процессоры слота 2 используют “полную тактовую частоту ” шины.

    Процессор Pentium III базируется на архитектуре процессоров Pentium Pro и Pentium II. В процессоре Pentium III введены 70 новых инструкций. Эти инструкции исполняются на существующих функциональных блоках архитектуры.

    1.2. Увеличение производительности архитектуры INTEL и закон Мура

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

    Увеличиваем производительность процессора

    Частота и производительность процессора может быть выше, чем указано в стандартных характеристиках. Также со временем использования системы производительность всех главных комплектующих ПК (оперативной памяти, ЦП и т.д.) может постепенно падать. Чтобы этого избежать, нужно регулярно “оптимизировать” свой компьютер.

    Необходимо понимать, что все манипуляции с центральным процессором (особенно разгон) нужно проводить только если убеждены в том, что он сможет их “пережить”. Для этого может потребоваться выполнить тестирование системы.

    Способы оптимизации и ускорения работы процессора

    Все манипуляции по улучшению качества работы ЦП можно поделить на две группы:

    • Оптимизация. Основной акцент делается на грамотное распределение уже доступных ресурсов ядер и системы, дабы добиться максимальной производительности. В ходе оптимизации трудно нанести серьёзный вред ЦП, но и прирост производительности, как правило, не очень высокий.
    • Разгон. Манипуляции непосредственно с самим процессором через специальное ПО или BIOS для повышения его тактовой частоты. Прирост производительности в этом случае получается весьма ощутимым, но и возрастает риск повредить процессор и другие компоненты компьютера в ходе неудачного разгона.

    Узнаём, пригоден ли процессор для разгона

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

    1. Чтобы узнать температуру ядер процессора (это один из главных факторов при разгоне), в левой части выберите пункт “Компьютер”, затем перейдите в пункт “Датчики” из главного окна или меню пунктов.
    2. Здесь вы сможете просмотреть температуру каждого ядра процессора и общую температуру. На ноутбуке, при работе без особых нагрузок она не должна превышать 60 градусов, если она равна или даже немного превышает этот показатель, то от разгона лучше отказаться. На стационарных ПК оптимальная температура может колебаться в районе 65-70 градусов.

    Если всё нормально, то перейдите в пункт “Разгон”. В поле “Частота ЦП” будет указано оптимальное число МГц при разгоне, а также процент, на который рекомендуется увеличить мощность (обычно колеблется в районе 15-25%).

    Способ 1: оптимизация при помощи CPU Control

    Чтобы безопасно оптимизировать работу процессора, потребуется скачать CPU Control. Данная программа имеет простой интерфейс для обычных пользователей ПК, поддерживает русский язык и распространяется бесплатно. Суть данного способа заключается в равномерном распределении нагрузки на ядра процессора, т.к. на современных многоядерных процессорах, некоторые ядра могут не участвовать в работе, что влечёт потерю производительности.

    Инструкция по использованию данной программы:

      После установки откроется главная страница. Изначально всё может быть на английском. Чтобы это исправить, перейдите в настройки (кнопка “Options” в правой нижней части окошка) и там в разделе “Language” отметьте русский язык.

    На главной странице программы, в правой части, выберите режим “Ручной”.

  • Если вы не хотите назначать процессы вручную, то можно оставить режим “Авто”, который стоит по умолчанию.
  • После закрытия программа автоматически сохранит настройки, которые будут применятся при каждом запуске ОС.
  • Способ 2: разгон при помощи ClockGen

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

    1. В главном окне перейдите во вкладку «PLL Control», где при помощи ползунков можно изменить частоту процессора и работы оперативной памяти. Не рекомендуется за раз слишком сильно передвигать ползунки, лучше небольшими шагами, т.к. слишком резкие изменения могут сильно нарушить работу ЦП и ОЗУ.
    2. Когда получите необходимый результат, нажмите на «Apply Selection».
  • Чтобы при перезапуске системы настройки не сбивались, в главном окне программы перейдите в пункт «Options». Там, в разделе «Profiles Management», поставьте флажок напротив «Apply current settings at startup».
  • Способ 3: разгон процессора в BIOS

    Довольно сложный и “опасный” способ, особенно для неопытных пользователей ПК. Перед разгоном процессора рекомендуется изучить его характеристики, в первую очередь, температуру при работе в штатном режиме (без серьёзных нагрузок). Для этого воспользуйтесь специальными утилитами или программами (описанная выше AIDA64 вполне подойдет для этих целей).

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

    1. Произведите вход в BIOS при помощи клавиши Del или клавиш от F2 до F12 (зависит от версии БИОСа, материнской платы).
    2. В меню BIOS найдите раздел с одним из таких наименований (зависит от вашей версии БИОСа и модели материнской платы) – “MB Intelligent Tweaker”, “M.I.B, Quantum BIOS”, “Ai Tweaker”.

    Теперь вы можете видеть данные о процессоре и вносить некоторые изменения. Перемещаться по меню можно при помощи клавиш со стрелочками. Переместитесь до пункта “CPU Host Clock Control”, нажмите Enter и поменяйте значение с “Auto” на “Manual”, чтобы можно было самостоятельно изменять настройки частоты.

    Спуститесь на пункт ниже к “CPU Frequency”. Чтобы внести изменения, нажмите Enter. Далее в поле “Key in a DEC number” введите значение в диапазоне от того, что написано в поле “Min” до “Max”. Не рекомендуется применять сразу максимальное значение. Лучше наращивать мощности постепенно, дабы не нарушить работу процессора и всей системы. Для применения изменений нажмите Enter.

  • Чтобы сохранить все изменения в БИОСе и выйти, найдите пункт в меню “Save & Exit” или несколько раз нажмите на Esc. В последнем случае система сама спросит, требуется ли сохранять изменения.
  • Способ 4: оптимизация работы ОС

    Это самый безопасный метод увеличения производительности ЦП путём очистки автозагрузки от ненужных приложений и дефрагментации дисков. Автозагрузка – это автоматическое включение той или иной программы/процесса при загрузке операционной системы. Когда в этом разделе скапливается слишком много процессов и программ, то при включении ОС и дальнейшей работе в ней, на центральный процессор может быть оказана слишком высокая нагрузка, что нарушит производительность.

    В автозагрузку приложения можно добавлять как самостоятельно, так и приложения/процессы могут добавляться сами. Чтобы второго случая не было, рекомендуется внимательно читать все пункты, которые отмечены галочкой во время установки того или иного софта. Как убрать уже имеющиеся элементы из Автозагрузки:

    1. Для начала перейдите в “Диспетчер задач”. Чтобы перейти туда, используйте комбинацию клавиш Ctrl+SHIFT+ESC или в поиске по системе вбейте “Диспетчер задач” (последнее актуально для пользователей на Windows 10).
    2. Перейдите в окно “Автозагрузка”. Там будут представлены все приложения/процессы, которые запускаются вместе с системой, их состояние (включено/отключено) и общее влияние на производительность (Нет, низкое, среднее, высокое). Что примечательно – здесь вы можете отключить все процессы, при этом не нарушите работу ОС. Однако, отключив некоторые приложения, вы можете сделать работу с компьютером немного неудобной для себя.

    В первую очередь, рекомендуется отключать все пункты, где в колонке “Степень влияния на производительность” стоят отметки “Высокое”. Чтобы отключить процесс, кликните по нему и в правой нижней части окна выберите “Отключить”.

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

    1. Нажмите правой кнопкой мыши по системному диску (вероятнее всего, это (C:)) и перейдите в пункт “Свойства”.
    2. В верхней части окна найдите и перейдите во вкладку “Сервис”. В разделе “Оптимизация и дефрагментация диска” нажмите “Оптимизировать”.
  • В открывшемся окне можно выбрать сразу несколько дисков. Перед дефрагментацией рекомендуется провести анализ дисков, нажав на соответствующую кнопку. Анализ может идти до нескольких часов, в это время не рекомендуется запускать программы, которые могут вносить какие-либо изменения на диске.
  • После анализа система напишет, требуется ли дефрагментация. Если да, то выделите нужный диск (диски) и нажмите на кнопку “Оптимизировать”.

    Рекомендуется также назначить автоматическую дефрагментацию дисков. Для этого перейдите по кнопке “Изменить параметры”, далее отметьте галочкой “Выполнять по расписанию” и задайте нужное расписание в поле “Частота”.

    Оптимизировать работу ЦП не так сложно, как кажется на первый взгляд. Однако, если оптимизация не дала сколь-нибудь заметных результатов, то в этом случае центральный процессор потребуется разогнать самостоятельно. В некоторых случаях разгон не обязательно производить через БИОС. Иногда производитель процессора может предоставить специальную программу для увеличения частоты той или иной модели.

    Отблагодарите автора, поделитесь статьей в социальных сетях.

    PARALLEL.RU — Информационно-аналитический центр по параллельным вычислениям

    Быстрое ознакомление с оптимизацией компиляторов Intel 10.0

    Пошаговый подход к оптимизации приложения с использованием компиляторов Intel.

    До того, как вы начнете настраивать программу на эффективную работу, вы можете проверить ее на корректность, компилируя ее без оптимизации, используя ключи /Od (-O0).

    1. Основные опции для настройки. В большинстве случаев следует начинать с опций /O2 (-O2) (установка по умолчанию). Следующим шагом следует попробовать /O3 (-O3) для приложений с большим количеством циклов, особенно на архитектурах IA-64.
    2. Специфичные настройки для процессоров. Для полного списка рекомендуемых опций смотрите соответствующую таблицу. Для двухъядерных процессоров Intel Itanium 2 9000 используйте опцию /G2-p9000 (-mtune=itanium2-p9000).
    3. Используйте анализатор производительности Intel Vtune для помощи в обнаружении ключевых мест в коде, чтобы знать, какие именно части вашего приложения могут быть улучшены дальнейшими настройками. Отчеты по оптимизации компиляторов Intel также помогают в обнаружении мест, где компилятор может нуждаться в дополнительной информации от пользователя.
    4. Добавление межпроцедурной оптимизации (IPO) /Qipo (-ipo) и/или управляемой профилем оптимизации (PGO) /Qprof-gen (-prof-gen и -prof-use), затем измерить производительность еще раз и определить, есть ли выигрыш от применения какой-то из этих оптимизаций, или от обоих сразу.
    5. Оптимизация приложения для гипертрединговых, многоядерных или многопроцессорных систем путем использования опций /Qparallel (-parallel), /Qopenmp (-openmp) или использования библиотек Intel Performance Libraries или элементов Intel Threading Building Blocks.
    6. Использование профилировщика Intel Thread Profile для помощи в понимании структуры программ и максимизации их производительности. Использование Intel Thread Checker для сокращения времени на доработку параллельных приложений путем обнаружения специфичных ошибок и увеличения скорости разработки приложения в целом. Оба инструмента работают с бинарным инструментарием. Использование компилятора Intel с кодом программы, оснащенным таким инструментарием, даст более полную информацию об исходном коде.

    Более подробная информация может быть получена из документации компилятора и документа «Optimizing Applications with the Intel C++ & Fortran Compilers» (PDF, 1.14MB, eng.).

    Основные опции

    Начинайте настройку эффективности с использования ключей /O1, /O2 или /O3 (-O1, -O2 или -O3 ). Это основные опции для оптимизации, которые должны быть использованы, прежде всего, при настройке приложения для всех процессоров. Произведите замеры производительности до того, как приступите к использованию расширенных опций оптимизации.

    Windows Linux,
    Mac OS
    Комментарии
    /Od -O0 Без оптимизации. Используется на ранних стадиях разработки и отладки приложения для проверки корректности работы программы.
    /O1 -O1 Оптимизация по размеру. Не использует методов оптимизации, которые могут увеличить размер кода. Создает в большинстве случаев самый маленький размер кода.
    /O2 -O2 Максимизация скорости. Установка по умолчанию. Как правило, создает более быстрый код, чем /O1 (-O1).
    /O3 -O3 Задействует методы оптимизации из /O2 (-O2) и, дополнительно, более агрессивные методы оптимизации циклов и доступа к памяти, такие как подстановка скаляров, раскрутка циклов, подстановка кода для избежания ветвлений, блокирование циклов для обеспечения более эффективного использования кэш-памяти и, только на системах архитектуры IA-64, дополнительная подготовка данных. Данная опция особенно рекомендуется для приложений, где есть циклы, которые активно используют вычисления с плавающей точкой или обрабатывают большие порции данных. Эти агрессивные методы оптимизации могут в ряде случаев и замедлить работу приложений других типов по сравнению с использованием /O2 (-O2).
    /zi -g Генерирует отладочную информацию для использования с любым обычным отладчиком. Эта опция отключает /O2 (-O2) и делает /Od (-O0) по умолчанию до тех пор, пока тип оптимизации не будет указан явно.
    /debug:full -debug full Облегчает отладку оптимизированного кода добавлением символьной информации, включая информацию о локальной таблице символов, независимо от используемого уровня оптимизации. Это может привести к минимальным снижениям производительности. Если эта опция указывается для приложения, которое делает вызовы к подпрограммам библиотек языка С, которые надо отладить, опция /dbglibs также должна быть указана для подключения соответствующих отладочных библиотек С.

    Производительность параллельных программ

    Компиляторы Intel поддерживают разработку многопроцессных приложений для гипертрединговых, многоядерных и/или многопроцессорных систем посредством двух опций: /Qparallel (-parallel) или /Qopenmp (-openmp). Если вы используете Intel Thread Profiler или Intel Thread Checker для настройки ваших приложений, используйте /Qtcheck (-tcheck) в случае Intel Thread Checker и /Qtprofile (-tprofile) в случае Intel Thread Profiler.

    Windows Linux,
    Mac OS
    Комментарии
    /Qopenmp -openmp Задействует создание кода на базе директив OpenMP.
    /Qopenmp-report -openmp-report Задает уровень диагностики OpenMP. Установка по умолчанию /Qopenmp-report1.
    /Qparallel -parallel Обнаруживает циклы с простой структурой, которые могут быть безопасно выполнены в параллельном режиме и автоматически создает параллельный код для таких циклов.
    /Qpar-report -par-report Управляет уровнями диагностики автоматического распараллеливания:
    0 — Не выдает диагностической информации.
    1 — Помечает успешно распараллеленный циклы (установка по умолчанию).
    2 — добавляет информацию о циклах, которые не удалось преобразовать.
    3 — Добавляет информацию о всех найденных или подозреваемых зависимостях, не позволяющих распараллеливание.
    /Qpar-threshold[n] -par-threshold[n] Устанавливает порог для автоматического распараллеливания циклов, базирующийся на вероятности выгодности выполнения цикла в параллельном режиме, параметр n — в диапазоне от 0 до 100 (по умолчанию n=100).
    0 — Распараллеливать циклы вне зависиомти от вычислительной сложности.
    100 — Распараллеливать циклы только в случае почти однозначной выгодности выполнения циклов в параллельном режиме.
    Опция должна использоваться совместно с /Qparallel (-parallel)
    /Qtprofile -tprofile Позволяет получить информацию о структуре параллельного приложения для использования в целях их настройки для достижения максимальной производительности. Опция создает бинарный файл, который сгенерирует данные о приложении, которые могут быть просмотрены с помощью Intel Thread Profiler.
    /Qtcheck -tcheck Позволяет получить информацию для диагностики ошибок в параллельной части параллельного приложения. Эта опция создает бинарный файл, который сгенерирует данные о приложении, которые могут быть просмотрены с помощью Intel Thread Checker.
    /Qopt-mem-bandwith
    (только для IA-64)
    -opt-mem-bandwith
    (только для IA-64)
    Запрещает использовать методы оптимизации, которые могут увеличить требования к объему используемой памяти.
    /Qopt-mem-bandwidth0 (-opt-mem-bandwidth0) — нет запрета (установка по умолчанию)
    /Qopt-mem-bandwidth1 (-opt-mem-bandwidth1) — запрещает оптимизацию циклов в секциях OpenMP (используется по умолчанию с /Qparallel (-parallel) или /Qopenmp (-openmp)).
    /Qopt-mem-bandwidth2 (-opt-mem-bandwidth2) — запрещает оптимизацию для всех циклов. Может использоваться для MPI или других параллельных приложений.
    Для Mac OS опция не поддерживается.

    Cпецифичные для процессоров архитектур IA-32 и Intel 64

    Используйте /QxT (-xT в случае Linux и Mac OS) для лучших результатов на процессорах семейства Intel Core2 и /QxP (-xP в Linux) на более старых системах на базе Intel, поддерживающих инструкции SSE3. Рекомендуется использовать /QaxT /QxW (-axT -xW в Linux) для лучших результатов на семействе Intel Core2 и хорошей производительности на других системах, поддерживающих SSE2, включая процессоры от AMD. Для лучшей производительности на не Intel процессорах, поддерживающих инструкции SSE3, рекомендуется использовать /QxO (-xO) вместо /QxW (-xW). Рекомендуемые опции для более старых процессоров смотрите ниже. Как и на предыдущих шагах, производите замер влияния на производительность каждой из опций, чтобы принять лучшие решения. Используйте отчеты оптимизаторов компилятора Intel для того чтобы понять, можно ли помочь компилятору разрешить какие-либо сложности, например, возможные зависимости или альясы.

    Windows Linux,
    Mac OS
    Комментарии
    /Qx -x Для создания приложения, исполняемого на конкретном типе процессора. Генерирует специальный код для такого процессора и задействует векторизацию. Исполняемый файл должен запускаться только на совместимых процессорах.

    S — Может генерировать инструкции SSE4, SSSE3, SSE3, SSE2 и SSE для процессоров Intel. Оптимизирует и для будущих процессоров Intel, поддерживающих векторизацию компилятора SSE4 и медиа-акселераторы.

    T — может генерировать инструкции SSSE3, SSE3, SSE2 и SSE для процессоров Intel. Оптимизирует для процессоров семейства Intel Core2 Duo, четырехъядерных процессоров Intel Xeon и двухъядерных процессоров Intel Xeon серий 5300, 5100 и 3000.

    P — Может генерировать инструкции SSE3, SSE2 и SSE для процессоров Intel. Оптимизирует для микроархитектуры процессоров Intel Core, процессоров Intel Pentium 4 с SSE3, процессоров Intel Xeon с SSE3, двухъядерных процессоров Intel Pentium T2060, процессоров Intel Pentium Extreme Edition и процессоров Intel Pentium D. Осуществляет оптимизации, не задействованные с /QxO (-xO).

    O — Может генерировать инструкции SSE3, SSE2 и SSE. Оптимизирует для микроархитектур процессоров Intel Core, процессоров Intel Pentium 4 с SSE3, процессоров Intel Xeon с SSE3, двухъядерных процессоров Intel Pentium T2060, процессоров Intel Pentium Extreme Edition и процессоров Intel Pentium D. Код может быть выполнен и не на процессорах Intel, поддерживающих SSE3*.

    N — Может генерировать инструкции SSE2 и SSE для процессоров Intel. Оптимизирует для процессоров Intel Pentium 4, процессоров Intel Xeon с SSE2 и процессоров Intel Pentium M. Осуществляет оптимизации, не задействованные с /QxW (-xW).

    W — может генерировать инструкции SSE2 и SSE. Оптимизирует для процессоров Intel Pentium 4 и процессоров Intel Xeon с SSE2. Код может быть выполнен и не на процессорах Intel, поддерживающих SSE2 и SSE*.

    K — Может генерировать инструкции SSE. Оптимизирует для процессоров Intel Pentium III и процессоров Intel Pentium III Xeon. Код может быть выполнен и не на процессорах Intel, поддерживающих SSE*.

    Примечание: на Mac OS значения опций O, N, W и K не поддерживаются. Для систем с Mac OS архитектуры IA-32 -xP является установкой по умолчанию. Для систем Mac OS архитектуры Intel 64 установкой по умолчанию является -xT.

    /Qax

    -ax Автоматический выбор процессора. Генерирует специальный код и задействует векторизацию, создавая код, не привязанный к конкретному процессору. Можно использовать более одного значения для получения одного исполняемого файла под разные процессоры. Например, для наилучшей производительности на процессорах семейства Intel Core2 Duo, четырехъядерных процессорах Intel Xeon, двухъядерных процессорах Intel Xeon серий 5300, 5100 и 3000 при возможности хорошей работы и на процессорах AMD, поддерживающих только SSE2, используйте /QaxT /QxW (-axT -xW в Linux) для генерации бинарного файла, использующего SSSE3 и настроенного и для не-SSSE3 x86-64 процессоров.

    В данном примере комбинация /QaxT /QxW (-axT -xW в Linux) даст бинарный файл с двумя видами кода. Один код даст возможность использовать полное преимущество процессоров семейства Intel Core2 Duo, четырехъядерных процессоров Intel Xeon processors и двухъядерных процессоров Intel Xeon серий 5300, 5100 и 3000. Другой код также даст возможность использовать возможности процессоров Intel и будет работать и на процессорах, не поддерживающих SSE3.

    Во время работы приложение автоматически определяет тип используемого процессора и выбирает соответствующий вариант кода. Примечания: Значение опции O не поддерживается для /Qax (-ax). Значения P, N, W и K не поддерживаются в Mac OS.

    /Qvec-report[n] -vec-report[n] Разметка возможности векторизации циклов:
    n = 0: без информации
    n = 1: размечает векторизуемые циклы (настройка по умолчанию)
    n = 2: размечает и векторизуемые, и не векторизуемые циклы
    n = 3: размечает векторизуемые циклы и объяснения, почему не векторизуемые не могут векторизоваться

    *Значения опций O, W и K создают бинарные файлы, которые должны запускаться не на процессорах Intel, таких как AMD, имеющих такие же возможности, как и соответствующие процессоры Intel. Значения опции P и N добавляют дополнительные оптимизации, которые не задействуются опциями O и W.

    Cпецифичные для процессоров архитектур IA-64

    В основном, использование /O3 (-O3), IPO и/или PGO, в сочетании с отчетами оптимизации (описанными в разделе тонкой настройки), помогающими разрешить возможные проблемы с альясами и улучшить использование памяти, обеспечивает наилучшую производительность на системах на базе IA-64.

    Windows Linux,
    Mac OS
    Комментарии
    /G2 -mtune=itanium2 Оптимизирует приложение для процессоров Intel Itanium 2.
    Сгенерированный код также совместим с более старыми процессорами IA-64.
    (установка по умолчанию)
    /G2-p9000 -mtune=itanium2-p9000 Оптимизирует для двухъядерных процессоров Intel Itanium 2 9000.
    Сгенерированный код также совместим со всеми процессорами IA-64, пока в программе нет вызовов функций, специфичных для процессоров Intel Itanium 2 9000.
    /QIPF-fma[-] -IPF-fma[-] Активирует [деактивирует] комбинирование операций умножения с плавающей точкой и операций сложения/вычитания.
    (включено по умолчанию)
    /Qivdep-parallel -ivdep-parallel Задает отсутствие зависимостей по памяти в циклах, где указана директива IVDEP. Обычно используется в сочетании с /Qparallel (-parallel).
    /Qprefetch[-] -prefetch[-] Включает или выключает предварительные подстановки.

    Межпроцедурная (IPO) и профильно-зависимая оптимизация (PGO)

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

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

    Однако IPO может увеличивать размер кода. Следует обратить внимание на оценки как производительности, так и времени компиляции и изменение размера кода с этими опциями. IPO лучше всего использовать в сочетании с PGO для определения тех функций, тело которых имеет смысл подставлять вместо вызова.

    Windows Linux,
    Mac OS
    Комментарии
    /Qip -ip Оптимизация отдельного файла.
    Межпроцедурные оптимизации, включая выборочные подстановки внутри этого файла.

    Внимание: Для больших файлов эта опция может существенно увеличить время компиляции и размер кода.

    /Qipo[value] -ipo[value] Разрешает подстановки и другие межпроцедурные оптимизации с несколькими исходными файлами. Значение в опции управляет максимальным числом выполненных компиляций (или числом объектных файлов). Значение по умолчанию — 0 (выбирает компилятор).

    Внимание: Эта опция может существенно увеличить время компиляции и размер кода.

    /Qipo-jobs[n] -ipo-jobs[n] Определяет количество команд (заданий) для одновременного выполнения на фазе линкования IPO. Значение по умолчанию — 1.
    /Ob2 -finline-functions-finline-level=2 Эта опция разрешает подстановку функций внутри текущего исходного файла на усмотрение компилятора. Опция задействована по умолчанию при /O2 и /O3 (-O2 и -O3).

    Внимание: Эта опция может существенно увеличить время компиляции и размер кода. Она может быть отключена с помощью /Ob0 (-fno-inline-functions в Linux и Mac OS).

    /Qinline-factor=n -finline-factor=n Эта опция масштабирует общий и максимальный размеры функций, которые могут подставляться. Значение по умолчанию — 100, т.е. 100% или единичный масштаб.
    /Qprof-gen -prof-gen Обеспечивает инструментами для профилирования.
    /Qprof-use -prof-use Включает использование профильной информации в ходе оптимизации.
    /Qprof-dir dir -prof-dir dir Определяет директорию для выходных файлов профилирования *.dyn и *.dpi.

    Арифметика с плавающей точкой

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

    Windows Linux,
    Mac OS
    Комментарии
    /fp:name -fp-model name Этот метод управления последовательностью результатов выполнения операций с плавающей точкой путем запрещения оптимизаций рекомендуется с опциями /Op (-mp) и /Qprec (-mp1). Возможные значения:

    precise — разрешает оптимизацию кода с операциями с плавающей точкой только для безопасных, с точки зрения сохранения значений, оптимизаций.

    double/extended/source — неявно выражает точность, вычисляя промежуточные значения с точностью double, extended или исходной. Значения double и extended недоступны для компилятора Intel Fortran.

    fast=[1|2] — позволяет использовать более агрессивные методы оптимизации ценой незначительного падения точности или последовательности вычислений. (fast=1 по умолчанию)

    except — разрешает семантику floating point exception.

    strict — режим строгого выполнения, включает как опции precise, так и except и отключает сжатие fma.

    Рекомендация: /fp:source (-fp-model source) рекомендуется для большинства ситуаций с процессорами IA-64, на процессорах, поддерживающих Intel 64, и на IA-32 в случае использования SSE с помощью /QxW (-xW) или выше, когда требуется дополнительная связанность и повторимость операций с плавающей точкой.

    /Qfp-speculation mode -fp-speculation mode Управляет анализом операций с плавающей точкой в следующих режимах:

    fast — анализировать операции с плавающей точкой. (по умолчанию)

    off — отключает анализ операций с плавающей точкой.

    safe — Не анализировать, если это может вызвать несоответствие.

    strict — то же, что и off.

    /Qftz[-] -ftz[-] Когда основная программа или dll компилируется с этой опцией, не инициализированные значения обнуляются для всей программы (dll). Установка этой опции не гарантирует, что все не инициализированные значения будут обнулены. Обнуляются лишь те значения, которые были сгенерированы во время запуска.
    В системах на базе IA-64 опция по умолчанию выключена, кроме /O3 (-O3).
    В системах на базе IA-32 и Intel 64 опция по умолчанию включена, кроме /Od (-O0), но обнуляются только замеченные не инициализированные значения в результате выполнения инструкций SSE.

    Тонкая настройка (все процессоры)

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

    Полная документация по компиляторам Intel С++ и Fortran содержит детальное описание прагм, директив и интринзиков, которые могут быть использованы для раскрутки циклов, векторизации и других методов для тонкой настройки внутри кода вашего приложения.

    Windows Linux,
    Mac OS
    Комментарии
    /Qunroll[n] -unroll[n] Устанавливает максимально число раскруток циклов.

    /Qunroll0 (-unroll0) отключает раскрутку.

    /Qunroll (-unroll) позволяет выбирать число раскруток компилятору (значение по умолчанию).

    /Qrestrict[-] -[no]restrict Включает [выключает] устранение неоднозначности с указателями с помощью запрещающих ключевых слов.
    /Oa -fno-alias Указывает отсутствие алиасов в программе.
    /Ow -fno-fnalias Указывает отсутствие алиасов в теле функций.
    /Qalias-args[-] -alias-args[-] Подразумевает, что аргументы функций могут иметь алиасы [не могут].
    /Qopt-class-analysis[-] -[no-]opt-class-analysis Эта опция использует информацию об иерархии классов С++ для анализа и разрешения виртуальных вызовов функций во время компиляции. Если приложение на С+++ содержит нестандартные конструкции, это может привести к разным результатам. По умолчанию, опция выключена, но включена при использовании /Qipo (-ipo), делая доступным улучшенную оптимизацию для С++.

    Примечание: Поддерживается только для С++.

    -fexceptions Опция включает создание таблицы обработки несоответствий. В приложениях, написанных на нескольких языках, опция не дает подпрограммам Fortran конфликтовать с обработкой несоответствий в подпрограммах С++. Используется по умолчанию для С++.
    -fno-exceptions Опция отключает создание таблицы обработки несоответствий, делая код меньше. Когда опция используется, при любой обработке несоответствий С++ во время вызова подпрограмм Fortran будет получена ошибка.
    /Qopt-report -opt-report Генерирует отчет об оптимизации в stderr.
    /Qopt-report-levellevel -opt-report-levellevel Устанавливает подробность сообщений на выходе. Возможные значения: min (по умолчанию), med и max.
    /Qopt-report-phasename -opt-report-phasename Создание отчетов. По умолчанию не создаются. Опция может использоваться несколько раз для получения отчетов на разных фазах хода компиляции. Возможные значения аргумента:

    all — все возможные отчеты для данной фазы

    ipo — отчеты IPO

    ipo_inl — только отчеты IPO по подстановке функций

    hlo — отчеты HLO

    hpo — отчеты HPO

    ecg — отчеты Code Generator (только Windows и Linux на IA-64)

    ecg_swp — только отчеты по пайплайнингу от Code Generator (только Windows и Linux на IA-64)

    Оптимизация для PENTIUM процессора

    ОПТИМИЗАЦИЯ ДЛЯ PENTIUM ПРОЦЕССОРА
    **********************************
    Права на распространение Ангера Фога, (c) 1996
    Перевод Дмитрия Померанцева, (c) 1997 FTS Labs.

    0. примечание переводчика
    1. введение
    2. литература
    3. отладка и проверка
    4. модель памяти
    5. выравнивание
    6. кеш
    7. блокировка генерации адреса (AGI)
    8. спаривание инструкций
    9. исполнение кода в цикле
    10. неполное спаривание
    11. замена сложных инструкций на более простые
    12. переходы и ветви
    13. префиксы
    14. уменьшение длины кода
    15. планирование операций с плавающей точкой
    16. оптимизация цикла
    17. обзор специальных инструкций

    18. целые числа вместо чисел с плавающей точкой
    19. числа с плавающей точкой вместо целых чисел
    20. список целочисленных инструкций
    21. список инструкций с плавающей точкой
    22. скоростные испытания
    23. соображения о других микропроцессорах

    0. ПРИМЕЧАНИЕ ПЕРЕВОДЧИКА
    =========================
    Прежде всего я хочу сказать, что я не являюсь профессиональным переводчиком
    и ранее не занимался переводами технической документации. Возможно, где то
    в тексте будут встречаться литературные огрехи, но в любом случае —
    документация на английском языке из любопытной вещи превратилась во вполне
    понятное руководство, пригодное к повседневной работе.

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

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

    Prescott New Instructions (SSE3): обзор новых SIMD расширений с точки зрения разработки и оптимизации программного обеспечения

    С выпуском нового 90-нм процессора Pentium 4 под кодовым названием Prescott, анонсированного Intel 2 февраля 2004 года архитектура Intel NetBurst приобрела ряд нововведений и дополнений, позволяющих по праву назвать процессор Prescott новым поколением процессоров семейства IA-32. Ключевыми моментами улучшенной архитектуры NetBurst, согласно Intel, являются следующие:

    • Поддержка технологии Hyper-Threading (которая, судя по всему, не претерпела каких-либо изменений);
    • Углубленный конвейер, позволяющий достичь еще более высоких частот;
    • Высокая частота системной шины (800 MHz, появившаяся еще со времен последних моделей Northwood);
    • Увеличенный вдвое объем первого и второго уровней кэша, а также большее количество буферов сохранения (store) и объединения записи (write-combining);
    • Поддержка новых SIMD расширений под кодовым названием Prescott New Instructions (официально — SSE3).

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

    • Prescott New Instructions (SSE3): Extended Features, бит 0;
    • Debug Trace Store Qualification: Extended Features, бит 4;
    • Улучшенная технология Intel SpeedStep (использующая MSR процессора): Extended Features, бит 7;
    • Поддержка инструкций MONITOR/MWAIT: Extended Features, бит 3.

    Ключевым элементом новой, улучшенной архитектуры Prescott является, конечно же, поддержка ряда новых инструкций, получивших кодовое название Prescott New Instructions (PNI) и, далее, официальное — SSE3. Это набор из 13 новых инструкций, призванных улучшить производительность процессора в ряде операций потоковой обработки данных. Дополнения коснулись набора команд SSE (Streaming SIMD Extensions), работающих с четырехкомпонентными векторами с одинарной точностью, SSE2 (Streaming SIMD Extensions 2), работающих с двумерными векторами чисел двойной точности, а также x87 FPU. Новая технология является полностью совместимой с существующим программным обеспечением (ПО), разработанным под архитектуру IA-32. В связи с этим гарантируется, что имеющееся ПО будет работать корректно без необходимости какой-либо модификации и на новых процессорах, поддерживающих расширения SSE3. Более того, использование расширений SSE3 не требует какой-либо дополнительной поддержки со стороны операционной системы, связанной с сохранением и восстановлением состояния процессора при переключении контекста, за исключением той, которая является необходимой (и уже имеется) для поддержки потоковых расширений SSE/SSE2. Краткий экскурс в SSE3

    Приступим к рассмотрению этого нового набора из 13 инструкций. Его можно разбить на следующие подгруппы:

    1. Преобразование чисел с плавающей точкой (x87) в целые числа

    В эту подгруппу входит одна-единственная инструкция из всего набора Prescott New Instructions (SSE3), которая работает на уровне x87 FPU.

    FISTTP (сохранение целочисленного значения с освобождением элемента стека x87-FP с округлением в сторону нуля). Ее поведение аналогично поведению стандартной IA-32 инструкции FISTP, но важным отличием является использование округления в сторону нуля (известного как truncate или chop) вне зависимости от того, какой способ округления выбран в данный момент в контрольном слове FPU.

    2. Дублирование данных

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

    MOVSLDUP — загрузка 128-битного значения из исходного операнда (памяти или XMM-регистра) в операнд назначения с дублированием первого и третьего 32-битных элементов:

    Операнд A (128 бит, 4 элемента): a3 | a2 | a1 | a0
    Операнд B (128 бит, 4 элемента): b3 | b2 | b1 | b0

    MOVSLDUP A, B
    Результат (операнд A): b2 | b2 | b0 | b0

    MOVSHDUP — загрузка 128-битного значения из исходного операнда в операнд назначения с дублированием второго и четвертого 32-битных элементов:

    Операнд A (128 бит, 4 элемента): a3 | a2 | a1 | a0
    Операнд B (128 бит, 4 элемента): b3 | b2 | b1 | b0

    MOVSHDUP A, B
    Результат (операнд A): b3 | b3 | b1 | b1

    MOVDDUP — загрузка 64-битного значения из памяти или исходного регистра (биты [63-0]) с дублированием в обоих нижней и верхней частях регистра назначения:

    Операнд A (128 бит, 2 элемента): a1 | a0
    Операнд B (64 бита, 1 элемент): b0

    MOVDDUP A, B
    Результат (операнд A): b0 | b0

    3. Загрузка невыровненных переменных

    Данную подгруппу представляет инструкция LDDQU. Это операция особой загрузки невыровненного 128-битного значения из памяти, исключающая возможность «разрыва» (пересечения границы) строки кэша. В случае, если адрес загружаемого элемента выровнен по 16-байтной границе, LDDQU осуществляет обычную загрузку запрашиваемого 16-байтного значения (т.е., по сути, ведет себя аналогично инструкциям MOVAPS/MOVAPD/MOVDQA из стандартного набора SSE/SSE2). В противном случае LDDQU загружает целых 32 байта, начиная с выровненного адреса (ниже запрашиваемого) с последующим извлечением требуемых 16 байт. Использование этой инструкции позволяет достичь значительного увеличения производительности при загрузке невыровненных 128-битных значений из памяти, по сравнению со стандартными инструкциями MOVUPS/MOVUPD/MOVDQU SIMD-расширений SSE/SSE2.

    4. Одновременное сложение/вычитание

    В эту подгруппу входят две новые инструкции, первая из которых работает с четырехкомпонентными векторами чисел одинарной точности (SSE), вторая — с двухкомпонентными векторами чисел двойной точности (SSE2).

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

    Операнд A (128 бит, 4 элемента): a3 | a2 | a1 | a0
    Операнд B (128 бит, 4 элемента): b3 | b2 | b1 | b0

    ADDSUBPS A, B
    Результат (операнд A): a3+b3 | a2-b2 | a1+b1 | a0-b0

    ADDSUBPD — ведет себя аналогично, но работает с числами двойной точности (двухэлементными операндами SSE2):

    Операнд A (128 бит, 2 элемента): a1 | a0
    Операнд B (128 бит, 2 элемента): b1 | b0

    ADDSUBPD A, B
    Результат (операнд A): a1+b1 | a0-b0

    5. Горизонтальное сложение/вычитание

    Пятая подгруппа представлена четырьмя командами, осуществляющими принципиально новые операции для SIMD расширений семейства SSE/SSE2. Первые две из них работают с четырехкомпонентными векторами с одинарной точностью, остальные — с двухкомпонентными векторами с двойной точностью.

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

    Операнд A (128 бит, 4 элемента): a3 | a2 | a1 | a0
    Операнд B (128 бит, 4 элемента): b3 | b2 | b1 | b0

    HADDPS A, B
    Результат (операнд A): b2+b3 | b0+b1 | a2+a3 | a0+a1

    HSUBPS — осуществляет горизонтальное вычитание элементов с одинарной точностью. Ее поведение аналогично HADDPS, единственным отличием является использование операции вычитания вместо сложения:

    Операнд A (128 бит, 4 элемента): a3 | a2 | a1 | a0
    Операнд B (128 бит, 4 элемента): b3 | b2 | b1 | b0

    HSUBPS A, B
    Результат (операнд A): b2-b3 | b0-b1 | a2-a3 | a0-a1

    HADDPD — осуществляет горизонтальное сложение элементов с двойной точностью. Первым (нижним) результирующим элементом является сумма нижней и верхней частей первого (исходного) операнда, вторым (верхним) — сумма нижней и верхней половин второго операнда (операнда назначения):

    Операнд A (128 бит, 2 элемента): a1 | a0
    Операнд B (128 бит, 2 элемента): b1 | b0

    HADDPD A, B
    Результат (операнд A): b0+b1 | a0+a1

    HSUBPD — осуществляет горизонтальное вычитание элементов с двойной точностью. Эта инструкция аналогична HADDPS, но использует операцию вычитания вместо сложения:

    Операнд A (128 бит, 2 элемента): a1 | a0
    Операнд B (128 бит, 2 элемента): b1 | b0

    HSUBPD A, B
    Результат (операнд A): b0-b1 | a0-a1

    6. Синхронизация потоков

    В последнюю подгруппу можно включить две инструкции, нацеленные на использование в системном программировании с целью предоставления возможности более эффективной синхронизации потоков, в частности, при использовании технологии Hyper-Threading. Ожидается, что эти инструкции будут использоваться при разработке операционных систем и драйверов устройств с целью улучшения производительности процессора и снижения энергопотребления последнего, когда он находится в режиме «пустого» ожидания (по всей видимости, наряду с введенной в расширения SSE2 инструкцией PAUSE).

    MONITOR — устанавливает диапазон адресов памяти (обычно используется одна строка кэша), по которому будет осуществляться отслеживание записей по стандартному протоколу write-back.

    MWAIT — вводит логический процессор в оптимизированный режим (режим низкого энергопотребления) при ожидании записей по протоколу write-back по пространству адресов, заданных инструкцией MONITOR. С архитектурной точки зрения ее поведение идентично NOP. Выход из оптимизированного состояния осуществляется в случае записи по установленному пространству адресов, а также при срабатывании любого прерывания или исключения. Использование SSE3 в разработке и оптимизации ПО

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

    1. Расчетные задачи, использующие x87 FPU

    В задачах такого типа (каковыми является подавляющее большинство профессионального расчетного ПО) может оказаться весьма полезной инструкция быстрого преобразования вещественных чисел в целые (FISTTP), единственная из всего набора SSE3, работающая на уровне x87 FPU (все остальные, как нетрудно видеть, задействуют исполнительные блоки SIMD — они работают с типами данных, присущими SSE или SSE2).

    Известно, что правильным с точки зрения стандарта C/C++/Fortran способом преобразования переменных типа float (чисел с плавающей точкой) в переменные типа int (целые числа) в операциях вида:

    является округление в сторону нуля (truncate). В то же время, выбранным по умолчанию способом округления x87 FPU является округление в сторону ближайшего точного числа (round-to-nearest). Необходимость существования операции округления, вообще говоря, связана вовсе не с преобразованием вещественных чисел в целые, а с конечным способом представления бесконечного множества чисел с плавающей точкой (32 бита для чисел одинарной точности, 64 бита для чисел двойной точности, 80 бит для переменных с расширенной точностью, а также для внутреннего представления данных в x87 FPU). При этом наиболее точное конечное представление чисел с плавающей точкой достигается именно при таком способе округления.

    В связи с этим, приведенный выше C-код в процессорах IA-32 нынешнего поколения будет преобразован любым компилятором, соблюдающим требования стандарта ANSI C, в ассемблерный код примерно следующего вида:

    Код 1.1

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

    Первый — это сохранить значение контрольного слова FPU, загрузить новое значение контрольного слова FPU с нужным способом округления, после чего совершить сразу целый ряд преобразований, и, наконец, восстановить исходное состояние FPU. Именно такой способ рекомендуется в ряде документации по оптимизации кода для процессоров x86 (в частности, для AMD Athlon). Трудность такого подхода заключается в том, что, во-первых, необходима реорганизация кода, позволяющая сгруппировать, по возможности, все преобразования значений float в int. Во-вторых, саму процедуру преобразования придется писать в виде ассемблерной вставки.

    Второй подход — это использовать доступные SIMD-расширения, вроде SSE или 3DNow! В первом случае для этой цели подходят команды CVTSS2SI и CVTPS2PI (последняя позволяет осуществлять два преобразования одновременно, но использует MMX-регистр, что, в свою очередь, приводит к необходимости переключения режимов FPU/MMX, которое является относительно «бесплатным» далеко не для всех процессоров). Во втором случае преобразование пары вещественных значений в целочисленные можно осуществлять с помощью команды PF2ID. Здесь вновь присутствуют трудности, присущие, кстати, набору 3DNow! в целом — использование MMX-регистров, и, как следствие, необходимость переключения режимов работы процессора (либо очистки, либо сохранения/восстановления содержимого FPU-стека и MMX-регистров). В качестве наиболее простой процедуры преобразования можно придумать следующую, оформленную в виде ассемблерной вставки:

    Код 1.2

    Подобный код вовсе не обязательно писать вручную, его вполне умеют генерировать компиляторы, понимающие SSE (при включении соответствующего ключа оптимизации, например, -QxK для Intel C++ Compiler 7.0). Таким образом, второй подход при наличии должной поддержки со стороны процессора, по идее, должен давать существенный выигрыш в производительности при преобразовании указанных типов данных. Более того, использование команд SSE, в отличие от MMX/3DNow!, не требует дополнительных затрат, связанных с переключением режима работы процессора.

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

    Код 1.3

    К сожалению, по непонятным пока что причинам такой код не генерируется автоматически компилятором, понимающим SSE3 (каковым является Intel C++ Compiler 8.0 при использовании ключа оптимизации -QxP). Вместо этого создается аналог рассмотренного выше SSE-кода, использующего команду CVTTSS2SI. Тем не менее, время исполнения SSE3-кода должно быть вполне сопоставимым, если даже не меньшим, чем вышеупомянутого SSE-кода. Самое время проверить это утверждение на практике.

    Тип кода Время исполнения, тактов *
    1.1. Преобразование с помощью FPU 26.0
    1.2. Преобразование с помощью SSE 3.80
    1.3. Преобразование с помощью FPU/SSE3 2.50

    * Здесь и далее замеры проводились на Pentium 4 Prescott 2.8A ГГц

    Мы видим, что время исполнения первого примера (код 1.1) оказывается непозволительно большим для одной-единственной операции преобразования данных (26 тактов процессора), что позволяет говорить о серьезном недостатке стандартного набора команд x87 FPU архитектуры IA-32. Введение в последнюю расширений SSE значительно спасает положение — аналогичный SSE-код (1.2) отнимает всего 3.8 тактов процессора, что почти в 7 раз быстрее по сравнению с традиционным подходом. Тем не менее, новые расширения SSE3 оказываются еще более эффективными по отношению к этой задаче, и как нельзя лучше подходят для преобразования вещественных чисел в целые. Действительно, выполнение соответствующего кода (1.3) занимает всего 2.5 такта процессора, что более чем на порядок быстрее, чем традиционное решение, реализуемое в IA-32 x87 FPU.

    Резюмируя, можно сказать, что использование новой инструкции FISTTP позволяет достичь значительного сокращения объема кода, необходимого для преобразования вещественных чисел в целые и, что еще более важно, времени исполнения последнего. В связи с этим оно является более чем оправданным. Остается только надеяться, что Intel позаботиться ввести ее автоматическое использование в последующие версии Intel C++ Compiler.

    2. Вычисления с комплексными числами

    Комплексная арифметика довольно часто встречается во всевозможных спектральных задачах, в частности — задачах обработки аудиоданных. К ним относятся дискретное/быстрое преобразование Фурье (DFT/FFT), частотная фильтрация и т.п. Среди новых расширений SSE3 можно выделить пять инструкций, позволяющих ускорить вычисления с комплексными числами. Сюда относятся инструкции одновременного сложения-вычитания ADDSUBPS и ADDSUBPD и инструкции дублирования данных MOVSLDUP, MOVSHDUP и MOVDDUP (исходный операнд которых может представлять собой адрес памяти). Первые позволяют исключить излишние операции смены знака у части элементов данных (обычно осуществляемые с помощью XORPS/XORPD), вторые — лишние операции распаковки данных, загружаемых из памяти (UNPCKLPS/UNPCKLPD, SHUFPS/SHUFPD).

    Рассмотренные ниже примеры кода показывают, как можно реализовать умножение комплексных чисел, используя только SSE2 (код 2.1), или SSE2 и новые расширения SSE3 (код 2.2). mem_X представляет собой превый комплексный операнд, mem_Y — второй; результат умножения сохраняется в mem_Z. В регистре XMM7 хранится константа, используемая для смены знака одного из элемента данных.

    Код 2.1. Комплексное умножение с помощью SSE2

    struct __declspec(align(16)) DCOMPLEX < double Re; double Im; >; DCOMPLEX mem_X, mem_Y, mem_Z; __asm

    Код 2.2. Комплексное умножение с помощью SSE2/SSE3

    struct __declspec(align(16)) DCOMPLEX < double Re; double Im; >; DCOMPLEX mem_X, mem_Y, mem_Z; __asm

    Сопоставим производительность первого примера, использующего только SSE2, со вторым, который использует в том числе и новые расширения SSE3.

    Тип кода Время исполнения, тактов
    2.1. Комплексное умножение, SSE2 10.5
    2.2. Комплексное умножение, SSE2/SSE3 5.6

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

    3. Кодирование видео

    Наиболее затратной с точки зрения процессорного времени операцией в задачах кодирования видеоданных обычно является Motion Estimation (ME), в которой блоки текущего кадра сравниваются с блоками предыдущего кадра с целью нахождения наилучшего соответствия (критерием последнего обычно является сумма абсолютных разностей). Особенность алгоритма ME заключается в том, что адреса блоков текущего кадра является выровненными, в то время как блоки предыдущего кадра обычно не являются выровненными по 16-байтной границе. В существующей архитектуре IA-32 операции невыровненной загрузки SSE/SSE2 имеют два серьезных недостатка:

    • Отсутствие аппаратной поддержки;
    • Возможность «разрыва» (пересечения границы) строки кэша.

    Так, в микроархитектуре NetBurst нет микрооперации, соответствующей загрузке невыровненного 128-битного значения (командами MOVUPS, MOVUPD или MOVDQU), в связи с чем последние эмулируются двумя 64-битными операциями загрузки с последующим объединением данных. Помимо эмуляции, могут возникать и дополнительные затраты в том случае, если загрузка сопровождается пересечением 64-байтной границы строки кэша процессора.

    Введенная в набор SSE3 инструкция специализированной загрузки невыровненных 128-битных значений LDDQU призвана решить эту проблему. В то же время, поскольку эта команда загружает большее количество данных (32 байта, начиная с выровненного адреса), имеется ряд ограничений на ее использование. В частности, ее не рекомендуется использовать для некэшируемых (Uncached, UC) регионов, или регионов с объединением записи (Write-combining, USWC), а также в ситуациях, когда может ожидаться «загрузка после сохранения» (Store-to-load forwarding, STLF). В остальных случаях, каковыми является большинство, можно ожидать до 30% улучшения производительности кода, использующего операции невыровненной загрузки (учитывая, что пересечение границы строки кэша при загрузке невыровненных значений может проявляться в 25% случаев). Приведем фрагменты такого кода из алгоритма ME, использующие только SSE2 (код 3.1) и SSE2/SSE3 (код 3.2).

    Код 3.1. Motion Estimation без SSE3

    Попробуем оценить реальный выигрыш в производительности, который можно достичь при замене стандартной операции невыровненной загрузки MOVDQU на инструкцию специализированной загрузки невыровненных данных LDDQU. В нашем примере, для сведения влияния подсистемы памяти практически к нулю мы использовали блоки данных current_block и previous_block размером всего 64 байта, т.е. помещающиеся в одну строку кэша. При этом current_block располагался по адресу, выровненному по 16-байтной границе, а previous_block со смещением от этой границы на 4 байта вправо. Таким образом, ровно одна из четырех операций загрузки данных из previous_block приводила к пересечению границы строки кэша.

    Тип кода Время исполнения, тактов
    3.1. Motion Estimation, SSE2 7.0
    3.2. Motion Estimation, SSE2/SSE3 5.0

    Замена MOVDQU на LDDQU, по результатам тестирования, уменьшает время исполнения такого кода на два такта процессора. Выигрыш в скорости при использовании этой SSE3-инструкции в нашем простейшем случае составляет 40%, в связи с чем ее применение в тех случаях, когда данные не могут быть выровнены по 16-байтной границе, является вполне оправданным. При этом, правда, следует иметь в виду упомянутые выше ограничения на ее использование.

    4. Векторные операции

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

    Какие векторные операции чаще всего можно встретить в реальных 3D-приложениях? Прежде всего, это операции с трех- или четырехмерными векторами, вроде их сложения, вычитания и скалярного умножения (умножения вектора на число). Не менее важными являются операции скалярного произведения двух векторов, вычисления длины вектора и процедура нормирования вектора (деления каждого элемента вектора на длину вектора). С точки зрения разработки и оптимизации ПО, для осуществления большинства подобных операций как нельзя лучше подходят SIMD расширения SSE, введенные в архитектуру IA-32 с выходом первых процессоров Intel Pentium III. Операндами инструкций набора SSE являются 128-битные регистры XMM (или 128-битное значение в памяти, которое, как правило, должно быть выровнено по 16-байтной границе), содержимое которых можно рассматривать как четырехмерные вектора, построенные из чисел с одинарной точностью:

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

    Из этого примера видно, что для осуществления собственно операции сложения необходима всего одна инструкция ADDPS (при условии, что как исходные вектора, так и результат сложения хранятся в XMM-регистрах, т.е. операции загрузки-выгрузки данных не требуются). Для осуществления подобной операции с помощью FPU потребовалось бы гораздо большее количество операций:

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

    VECTOR4F A, B; float dot = A.x * B.x + A.y * B.y + A.z * B.z; float norm = sqrtf(A.x * A.x + A.y * A.y + A.z * A.z);

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

    Код 4.1. Скалярное произведение двух векторов, SSE

    В рассмотренном примере вычисление скалярного произведения осуществляется при помощи одной операции умножения (MULPS), двух операций перемещения (MOVHLPS), одной операции распаковки (UNPCKLPS) и двух операций однокомпонентного (скалярного) сложения (ADDSS). Кроме того, что немаловажно, задействуется один дополнительный XMM-регистр.

    Выходов из ситуации, в смысле, путей дальнейшей оптимизации кода, как всегда, можно придумать несколько. Первый из них — использовать для вычисления скалярных произведений не SSE, а FPU. Но это связано с дополнительными трудностями переноса данных из регистров SSE в стек FPU и обратно в том случае, если большая часть кода использует именно расширения SSE. В связи с этим мы не будем рассматривать его в нашем сравнительном тестировании производительности.

    Второй способ — использовать однокомпонентные (скалярные) инструкции SSE. Получается что-то вроде аналога FPU-кода, но более удобного, поскольку мы используем все те же XMM-регистры:

    Код 4.2. Скалярное произведение двух векторов, SSE scalar

    Именно такой способ, по всей видимости, предпочитают оптимизирующие компиляторы вроде Intel C++ Compiler 7.0 (при задании соответствующего ключа оптимизации -QxK). В связи с этим мы включили его в наше сравнение, результаты которого представлены ниже.

    Есть еще и третий способ, довольно фантастический. Он заключается в одновременном вычислении сразу четырех скалярных произведений восьми трехмерных векторов, но зато использует расширения SSE в полной мере. Для полноты картины приведем и его, но при этом отметим, что вряд ли кто-то действительно захочет возиться с подобной ручной оптимизацией.

    Код 4.3. Четыре скалярных произведения, SSE

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

    Рассмотрим, наконец, что же позволяют нам сделать в плане оптимизации вычислений скалярных произведений грядущие расширения SSE3. А позволяют они многое. Для этого достаточно взглянуть на следующий код, относящийся к вычислению одного скалярного произведения.

    Код 4.4. Скалярное произведение двух векторов, SSE/SSE3

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

    Код 4.5. Два скалярных произведения, SSE/SSE3

    И все равно, складывается ощущение некоторой незавершенности оптимизации. Два скалярных произведения в результате вычисления как бы дублируются. Действительно, а почему бы не попытаться использовать SSE3 на всю мощь и попробовать посчитать сразу четыре скалярных произведения? Взгляните на следующий код — это достигается уже далеко не такой ценой, как при вычислении этих самых четырех скалярных произведений исключительно с помощью SSE-инструкций (код 4.3):

    Код 4.6. Четыре скалярных произведения, SSE/SSE3

    Заметьте, что в этом коде нет ни одной лишней операции (излишнего перемещения данных) и не используется ни один вспомогательный регистр (для временного хранения данных). Более того, данный код одинаково хорошо подходит для вычисления четырех скалярных произведений как трехмерных, так и четырехмерных векторов, в то время как код 4.3 специально «подогнан» и годится лишь для операций с трехмерными векторами.

    Как всегда, самое время проверить все вышесказанное на практике. Для этого попробуем оценить, во сколько тактов процессора уложится вычисление одного скалярного произведения с использованием только SSE-команд (код 4.1, 4.2) и SSE вместе с SSE3 (код 4.4), а также сравним эффективность вычисления четырех скалярных произведений с помощью SSE-кода (код 4.3) и кода, в полной мере использующего новые процессорные расширения (код 4.6).

    Тип кода Время исполнения, тактов
    4.1. Одно скалярное произведение, SSE 8.60
    4.2. Одно скалярное произведение, SSE scalar 8.75
    4.4. Одно скалярное произведение, SSE/SSE3 9.00
    4.3. Четыре скалярных произведения, SSE 33.67
    4.6. Четыре скалярных произведения, SSE/SSE3 18.33

    Что же мы видим? Одно скалярное произведение, использующее расширения SSE/SSE3 далеко не на полную мощность, не то что не выигрывает, но даже несколько проигрывает при использовании новой инструкции HADDPS из набора SSE3. И это несмотря на то, что мы сократили объем кода и устранили необходимость использования дополнительных XMM-регистров. Тем не менее, поскольку увеличение времени исполнения такого кода (4.4) является сравнительно малым, использование SSE3 в этом случае (вычисление одного скалярного произведения трехкомпонентных векторов) можно считать оправданным, хотя бы по причине того, что в распоряжении компилятора, ну или непосредственно разработчика, остается большее количество доступных XMM-регистров.

    Но давайте теперь посмотрим, что же получается в случае одновременного вычисления сразу четырех скалярных произведений? В этом случае выигрыш в скорости при использовании SSE3 оказывается весьма и весьма значительным, SSE3-код опережает свой SSE-аналог почти на 84%. Что еще раз доказывает, что использование сразу всех четырех элементов XMM-регистра является оптимальным режимом работы SIMD расширений Intel, и SSE3 здесь не является исключением. В этой связи ручная оптимизация под SSE3 может оказаться намного более эффективной, нежели поручение этой же работы оптимизирующему компилятору.

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

    Тип задачи Выигрыш в скорости, раз, по сравнению с традиционным FPU/SIMD-кодом
    Преобразование данных (float to int) 10.4
    Комплексное умножение 1.88
    Загрузка невыровненных значений 1.40
    Одно скалярное произведение векторов 0.96
    Четыре скалярных произведения векторов 1.84

    Сравнение с конкурентными решениями

    С выпуском процессоров архитектуры AMD64, AMD наконец-то ввела полный набор SIMD-расширений в свои процессоры семейства K8 (Opteron, Athlon 64, Athlon 64 FX). SIMD-расширения AMD64 включают в себя как традиционно присущие процессорам AMD наборы 3DNow! (начиная с K6-2) и Extended 3DNow! (начиная с Athlon), так и расширения Intel SSE/SSE2. Тем не менее, с точки зрения оптимизации ПО такое решение не многим лучше реализованного в обычных Pentium 4 (только SSE/SSE2). А связано это с тем, что подавляющее большинство компиляторов по-прежнему не умеет автоматически генерировать код, использующий расширения 3DNow!/Extended 3DNow! Единственным известным нам примером компилятора, умеющего генерировать 3DNow! код, является VectorC , который, однако, до сих пор находится в стадии бета-тестирования и все еще не имеет полноценной поддержки C++ кода.

    Большим минусом SIMD-расширений архитектуры AMD64 является отсутствие принципиально новых и весьма полезных инструкций, наподобие тех, что Intel ввела в свои новые процессоры Prescott. Возьмем, к примеру, операции горизонтального сложения/вычитания векторов. Давно известно, что процессоры AMD, фактически, умеют делать такие вычисления еще со времен K6-2 (инструкция PFACC). Горизонтальное вычитание, правда, появилось несколько позже — с момента введения новых расширений Extended 3DNow! в первых процессорах Athlon (инструкция PFNACC). Но 3DNow!, как известно, имеет ряд недостатков. О некоторых из них мы уже говорили выше — это необходимость использования MMX-регистров, что исключает возможность одновременного использования 3DNow! и FPU-кода, с одной стороны, и уменьшает количество свободных регистров при совместном использовании 3DNow! и MMX-кода, с другой. Вторым недостатком является низкая разрядность MMX-регистров (64 бита), так что в них влезает всего два значения с плавающей точкой одинарной точности. Т.е. для эффективных вычислений с трех- и четырехмерными векторами необходимо использовать по два регистра на каждый. В связи с этим, для AMD было бы весьма разумным расширить функциональность этих инструкций так, чтобы они умели работать с XMM-регистрами, наподобие того, как была расширена функциональность инструкций MMX с введением расширений SSE2 в процессоры семейства Pentium 4. И даже опередить тем самым Intel, поскольку получилось бы полное подобие расширений SSE3. Действительно, давайте посмотрим, для примера, как можно уже сейчас эмулировать инструкцию HADDPS XMM0, XMM1 с помощью SIMD-расширений AMD64 (будем считать, что в XMM0 уже загружен вектор A, а в XMM1 — вектор B): __asm < // Входные данные: // XMM0: A.w | A.z | A.y | A.x // XMM1: B.w | B.z | B.y | B.x movhlps xmm2, xmm0 // ? | ? | A.w | A.z movhlps xmm3, xmm1 // ? | ? | B.w | B.z movdq2q mm0, xmm0 // A.y | A.x movdq2q mm1, xmm2 // A.w | A.z movdq2q mm2, xmm1 // B.y | B.x movdq2q mm3, xmm3 // B.w | B.z pfacc mm0, mm1 // A.w+A.z | A.y+A.x pfacc mm2, mm3 // B.w+B.z | B.y+B.x movq2dq xmm0, mm0 // ? | ? | A.w+A.z | A.y+A.x movq2dq xmm2, mm2 // ? | ? | B.w+B.z | B.y+B.x movlhps xmm0, xmm2 // A.w+A.z | A.y+A.x | B.w+B.z | B.y+B.x // Выходные данные: // XMM0: A.w+A.z | A.y+A.x | B.w+B.z | B.y+B.x >

    Нетрудно видеть, что в этом коде реальных вычислительных операций всего две — это те самые инструкции PFACC. Все остальные операции (целых 9 штук), по сути, являются лишними — они связаны с необходимостью перемещения данных из XMM- в MMX-регистры и обратно и, как следствие, требуют наличия дополнительных свободных регистров. Заключая, можно сказать, что предпосылки к введению новых расширений в процессоры архитектуры AMD64 явно имеются, и причем уже довольно давно. Теперь остается лишь дождаться, что AMD не будет сильно отставать в этом плане от Intel (а ведь могла бы и опередить!) и все же введет их в последующие модели своих 64-разрядных процессоров.

    «Оптимизация для PENTIUM процессора» — читать интересную книгу автора

    ОПТИМИЗАЦИЯ ДЛЯ PENTIUM ПРОЦЕССОРА
    **********************************
    Права на распространение Ангера Фога, (c) 1996
    Перевод Дмитрия Померанцева, (c) 1997 FTS Labs.

    0. примечание переводчика
    1. введение
    2. литература
    3. отладка и проверка
    4. модель памяти
    5. выравнивание
    6. кеш
    7. блокировка генерации адреса (AGI)
    8. спаривание инструкций
    9. исполнение кода в цикле
    10. неполное спаривание
    11. замена сложных инструкций на более простые
    12. переходы и ветви
    13. префиксы
    14. уменьшение длины кода
    15. планирование операций с плавающей точкой
    16. оптимизация цикла
    17. обзор специальных инструкций

    18. целые числа вместо чисел с плавающей точкой
    19. числа с плавающей точкой вместо целых чисел
    20. список целочисленных инструкций
    21. список инструкций с плавающей точкой
    22. скоростные испытания
    23. соображения о других микропроцессорах

    0. ПРИМЕЧАНИЕ ПЕРЕВОДЧИКА
    =========================
    Прежде всего я хочу сказать, что я не являюсь профессиональным переводчиком
    и ранее не занимался переводами технической документации. Возможно, где то
    в тексте будут встречаться литературные огрехи, но в любом случае —
    документация на английском языке из любопытной вещи превратилась во вполне
    понятное руководство, пригодное к повседневной работе.

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

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

    Проектирование процессора с плавающей точкой (стр. 1 из 4)

    Пояснительная записка к курсовому проекту по дисциплине

    «Организация ЭВМ и систем»

    «Проектирование процессора с плавающей точкой»

    Выполнил студент гр.343

    1. Описание команд

    1.1. FMul ST, ST(i) — умножение

    1.2. FSt m32real — сохранение

    2. Форматы данных

    2.1. Внутренний формат

    2.2. Внешний формат

    2.3. Пример формата m80real

    2.4. Пример формата m32real

    3. Программная модель процессора

    4. Блок – схема процессора

    5. Алгоритмы операций

    5.1. Алгоритм операции FMulSt,St(i)

    5.2. Алгоритм операции FSt m32real

    6. Структурные схемы блоков процессора

    6.2. Блок преобразования форматов

    6.3. Блок регистров

    6.4. Блок обработки данных (блок умножения)

    6.5. Блок микропрограммного управления

    7. Моделирование операции FMul St,St(i)

    Список использованных источников

    FMul ST, ST(i) — умножение.

    Команда умножения умножает операнды источника и получателя и возвращает произведение в получатель.

    Оба операнда находятся в регистровом стеке в формате 80real.

    Умножение с анализом младшего бита множителя со сдвигом множимого.

    Особые случаи: P, U, O, D, I.

    Особые случаи: P, U, O, D, I.

    Емкость ОП 4 Кбайт.

    Длина слова памяти 128 бит.

    С появлением процессора i486 и его сопроцессора FPU – сопроцессора с плавающей точкой, работа с вещественными числами стала аппаратной, а не программной задачей. Производительность ЭВМ увеличилась. Возможности использования ЭВМ в бухгалтерии и многих других областях деятельности человека дали толчок массовому внедрению их в повседневную жизнь. Были переписаны многие программы, компиляторы. Освоение архитектуры, принципов работы сопроцессора FPU стало для программистов едва ли не основной задачей.

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

    1.1. FMulST, ST(i) — умножение.

    Команда умножения умножает операнды источника и получателя и возвращает произведение в получатель.

    Оба операнда находятся в регистровом стеке в формате 80real.

    Умножение с анализом младшего бита множителя со сдвигом множимого.

    P — неточный результат;

    D — денормализованный операнд;

    I — недействительная операция.

    Формат команды представлен на рисунке 1.1

    Адрес второго операнда определяется полем ST(i), которое принимает значения от 000 до 111, где 000 – вершина стека, 111 – восьмой элемент регистрового стека.

    Бит R показывает, возвращается ли результат в вершину стека. В данном случае R = 0.

    Бит P указывает, что после операции производится извлечение из стека. P = 0, так как извлечения нет.

    Команда FSt m32real передает значение из регистра ST в ОП. Содержимое ST остается неизменным.

    P — неточный результат;

    D — денормализованный операнд;

    I — недействительная операция.

    Формат команды представлен на рисунке 1.2

    Адрес операнда m32real определяется полями mod, r/m, SIB, Disp. Адрес вычисляется целочисленным процессором. К началу операции он уже сформирован. Бит [0] первого байта команды определяет тип операции.

    В данном случае Бит [0] = 1 – передача данного из стека в память.

    Поле MF определяет тип операнда. При m32realMF = 00.

    2.1. Внутренний формат.

    Во внутренних операциях процессор с плавающей точкой (ППТ) использует представление вещественных чисел в формате с расширенной точностью (РТ, m80real) (рис.2.1). Длина формата 80 бит.

    Значащие цифры числа находятся в поле мантиссы (М). Длина мантиссы 64 бита. Поле порядка (E) показывает фактическое положение двоичной точки в разрядах мантиссы. Длина порядка 15 бит. Бит знака (S) определяет знак числа. Мантисса представлена в прямом коде. Порядок задается в смещенной форме; он равен истинному порядку (П), увеличенному на значение смещения – смещ РТ = 16383:

    Истинный порядок изменяется от –16382 до 16383. Порядки 000…0b и 111…1b зарезервированы для специальных значений. Числа в формате РТ имеют явный бит F0.

    Значение числа в формате РТ равно

    В данном курсовом проекте рассматривается один внешний формат m32real – формат обычной точности (ОТ) (рис.2.2). Длина формата 32 бита.

    Значащие цифры числа находятся в поле мантиссы (М). Длина мантиссы 23 бита. Поле порядка (E) показывает фактическое положение двоичной точки в разрядах мантиссы. Длина порядка 8 бит. Бит знака (S) определяет знак числа. Мантисса представлена в прямом коде. Порядок задается в смещенной форме; он равен истинному порядку (П), увеличенному на значение смещения – смещ ОТ = 127:

    Истинный порядок изменяется от –126 до 127. Порядки 000…0b и 111…1b зарезервированы для специальных значений. Явный бит F0 в формате ОТ отсутствует и мантисса оказывается правильной дробью.

    Значение числа в формате ОТ равно

    Покажем представление десятичного числа 24789.8125 в формате РТ. Двоичный код числа равен 110000011010101.1101b, истинный порядок равен 14. Смещенный порядок E=14+16383=16397=100000000001101b. Число в формате РТ приведено на рис. 2.3.

    Покажем представление десятичного числа -85.125 в формате ОТ. Двоичный код числа равен -1010101.001b, истинный порядок равен 6. Смещенный порядок E=6+127=133=10000101b. Число в формате ОТ приведено на рис. 2.4.

    Программная модель (рис. 3.1) включает в себя кольцевой стек из восьми регистров R0-R7, слово тэгов TW, слово состояния SW и слово управления CW. В стеке хранятся числа в формате РТ. В полях S, Е и М регистров записаны соответственно знак, порядок и мантисса. Вершина стека определяется полем TOP слова состояния SW и обозначается ST(0), или просто ST. На рисунке вершиной стека является физический регистр R3. ST(0) содержит последнее включенное в стек значение, регистр ST(1) предпоследнее и т.д. Включение в стек осуществляет декремент TOP и загрузку в новую вершину стека. При извлечении из стека данное читается из ST(0), а затем производится инкремент TOP.

    С каждым регистром стека ассоциируется двухбитный тэг, характеризующий хранимое число:

    00 — нормализованное число;

    01 — истинный нуль;

    10 — денормализованное число, бесконечность или неопределенность;

    11 — пустой регистр.

    В слове состояния SW поле TOP содержит адрес текущей вершины стека. Биты кода условия C0-C3 фиксируют результаты команд сравнения, проверки и анализа. Восемь бит отведены для регистрации особых случаев (ошибок) (рис.3.2).

    При выполнении команд с ПТ возможны следующие особые случаи:

    ·P – неточный результат (точность);

    ·D – денормализованный операнд;

    ·I – недействительная операция;

    ·Z – деление на нуль.

    Особым случаям соответствуют флажки в слове состояния SW (рис.3.2): IE, ZE, DE, OE, UE, PE. При любом особом случае устанавливается бит суммарной ошибки ES, а также вырабатывается активный сигнал ошибки FERR.

    В слове управления CW поле RCзадает режим округления, когда формат получателя не позволяет точно представить результат. Пусть B – точный результат, A и C – ближайшие к нему представимые в заданном формате числа: A

    Илон Маск рекомендует:  border-top-right-radius в CSS
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL