Новосибирский Государственный Университет
Опубликован: 18.02.2011 | Доступ: свободный | Студентов: 936 / 287 | Оценка: 4.27 / 3.95 | Длительность: 04:10:00
Специальности: Программист
Лекция 1:

Архитектура микропроцессора Intel и основные факторы, влияющие на его производительность

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

Цели спецкурса:

Получить базовые представление о:

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

После изучения спецкурса вы будете в состоянии:

  • Описать главные проблемы, влияющие на производительность процессора.
  • Исследовать приложение с помощью VTune Performance Analyser и найти проблемные места.
  • Идентифицировать главные проблемы анализируемого приложения.
  • Разработать стратегию улучшения производительности приложения.
  • Описать главные компоненты компилятора, их основные функции.
  • Управлять уровнем оптимизации с помощью ключей компилятора.

План курса:

  1. Архитектура микропроцессора Intel и основные факторы, влияющие на производительность процессора.
  2. Использование VTune Performance Analyser.
  3. Роль компилятора в улучшении производительности приложения.
  4. Некоторые базовые понятия. Граф управления, эффективный анализ потока данных.
  5. Перестановочные оптимизации и их применимость. Зависимости.
  6. Векторизация.
  7. Параллелизация с помощью OMP директив и автопараллелизацияю
  8. Основные компоненты компилятора, их задачи и взаимосвязь

Архитектура микропроцессора Intel и основные факторы, влияющие на производительность процессора.

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

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

Что такое производительность? Сложно дать однозначное определение производительности. Можно формально привязать его к процессору – сколько, инструкций за единицу времени может выполнять тот или иной процессор. Но проще дать сравнительное определение – взять два процессора и тот, который выполняет некий набор инструкций быстрее, тот более производительный. То есть, очень условно, можно сказать, что производительность – это количество инструкций на время выполнения. Мы здесь в основном будем исследовать те микропроцессорные архитектуры, которые выпускает Intel, то есть архитектуры IA32, которые сейчас называются Intel 64. Это архитектуры, которые с одной стороны поддерживает старые инструкции из набора IA32, с другой стороны имеют EM64T – это некое расширение, которое позволяет использовать 64 битные адреса, т.е. адресовать большие размеры памяти , а также включает в себя какие-то полезные дополнения, типа увеличенного количества системных регистров, увеличенное количество векторных регистров.

Какие факторы влияют на производительность? Перечислим все, которые приходят в голову. Это

  • Тактовая частота
  • Объем адресуемой памяти и скорость доступа к памяти
  • Скорость выполнение инструкций, полнота базового набора инструкций.
  • Использование внутренней памяти регистров.
  • Качество конвейеризации.
  • Качество предсказания переходов.
  • Качество упреждающей выборки
  • Суперскалярность.
  • Векторизация, использование векторных инструкций.
  • Параллелизация и многоядерность.

Тактовая частота.

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

Объем адресуемой памяти и скорость доступа к памяти.

Объём памяти - необходимо, чтобы памяти хватало для нашей программы и наших данных. То есть, технология EM64T позволяет адресовать огромное количество памяти и на данный момент вопрос с тем, что нам не хватает адресуемой памяти не стоит.

Поскольку на эти факторы разработчики в общем случае не имеют возможности влиять, то я только упоминаю о них.

Скорость выполнения инструкция и полнота базового набора инструкций.

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

Использование регистров и оперативной памяти.

Регистры – самые быстрые элементы памяти, они находятся непосредственно на ядре, и доступ к ним практически мгновенный. Если ваша программа делает какие-то вычисления, хотелось бы, чтобы все промежуточные данные хранились на регистрах. Понятно, что это невозможно. Одна из возможных проблем производительности– это проблема вытеснения регистров. Когда вы под каким-нибудь анализатором производительности смотрите на ассемблерный код, вы видите, что у вас очень много движения со стека в регистры и обратно выгрузка регистров на стек. Стоит вопрос – как оптимизировать код так, чтобы самые горячие адреса, самые горячие промежуточные данные, лежали именно на системных регистрах.

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

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

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

Существуют разные реализации кэш-памяти. Бывает полностью ассоциативная кэш-память, когда каждый блок может отображаться в любое место кэша. Существует память с прямым отображением, когда каждый блок может отображаться в одно место, также существуют различные гибридные варианты – например кэш с множественно-ассоциативным доступом. В чём разница? Разница во времени и сложности проверки на наличие нужного адреса в кэш-памяти. Предположим, что нам нужен определённый адрес. В случае с ассоциативной памятью нам нужно проверить весь кэш – убедиться, что этого адреса в кэше нет. В случае с прямым отображением нам нужно проверить только одну ячейку. В случае с гибридными вариантами, например, когда используется кэш с множественно-ассоциативным доступом, нам нужно проверить, к примеру, четыре или восемь ячеек. То есть, задача определить есть ли адрес в кэша – тоже важна. Качество использования кэша – важное условие быстродействия. Если нам удастся написать программу так, чтобы как можно чаще те данные, с которыми мы собирались работать, находились в кэше, то такая программа будет работать гораздо быстрее.

Для примера возьмём наш последний процессор Nehalem: i7.

Здесь мы имеем не просто кэш, а некий иерархический кэш. Долгое время он был двухуровневый, в современной системе Nehalem он трёхуровневый – совсем немного очень быстрого кэша, чуть побольше кэша второго уровня и достаточно большое количество кэша третьего уровня. При этом, эта система построена так, что если какой-то адрес находится в кэше первого уровня, он автоматически находится во втором и в третьем уровнях. Это и есть иерархическая система. Для кэша первого уровня задержка – 4 такта, для второго – 11, третьего – 38 и время отклика оперативной памяти – больше 100 тактов процессора.

Второй вариант улучшения быстродействия и работы с памятью, про который мы упомянули – это подкладывать в кэш заранее необходимые адреса – упреждающий механизм доступа к памяти (Hardware Prefetching). Этот механизм выявляет закономерности, с которыми вы обращаетесь к памяти, и заранее закачивает в кэш адреса, которые могут вам понадобиться. Если вы обрабатываете несколько массивов, движетесь по ним последовательно или с каким-то постоянным шагом, то, скорее всего, этот механизм начнёт эти адреса заранее подгружать. Есть специальный набор инструкций, позволяющий загрузить в кэш память, расположенную по определённому адресу. (Software Prefetching)

Кэш имеет внутренние алгоритмы работы. Введём несколько понятий.

Локальность ссылки – переиспользование переменных или взаимосвязанных данных. Различают временную локальность – переиспользование определённых данных и ресурсов и пространственную локальность - использование данных, имеющих относительно близкие области хранения.

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

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

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

Качество конвейеризации.

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

  • выборка команды;
  • декодирования команды;
  • выполнение операции;
  • обращение к памяти;
  • запоминание результатов.

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

Качество предсказания переходов.

В программе есть некая управляющая логика, и эта логика включает в себя различные переходы внутри кода. Если встречаются if'ы и на основании вычисления какого-то условия принимается решение, какую выполнять инструкцию дальше? Как быть с загрузкой конвейера, в случае если встречается зависимость по управляющей логике? Можно остановить конвейер и ждать, пока вычислится условие перехода и после этого определить, какую инструкцию выполнять дальше и загружать ее на конвейер. Понятно, что в этом случае произойдет замедление работы конвейера, поэтому выбран другой метод. Процессор пытается предсказать по какому пути будет передаваться управление и продолжает выполнять инструкции с этого направления. Причем пока процессор не убедится, что выполняются правильные инструкции, они недействительны. Как только процессор убеждается, что путь угадан верно, все инструкции признаются правильными. Если предсказатель ошибся и реальное управление пошло по другому пути, недействительные инструкции удаляются из буферов, где они ожидали своей судьбы. Это приводит к некой задержке, приходится тратить время на то, чтобы инструкции удалять и загружать правильные инструкции на конвейер. Ошибка предсказателя (branch misprediction) вызывает замедление работы конвейера.

В процессоре есть статический и динамический предсказатель.

Статический предсказатель действует по простым правилам и принимает решения для тех переходов для которых нет собранной статистики.

Если встречается условный переход вперед, то статический предсказатель считает, что перехода не будет (в случае с оператором if управление пойдет по ветке if а не else).

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

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

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

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

Существуют разные проблемы. Проблема с КЭШем, например. Если у вас идет неугадывание по КЭШу, и вы не можете вовремя получить из памяти какие-то адреса, то эта проблема заслонит ту проблему, что вы не можете правильно определить цель ветвления, потому что процессор будет простаивать много времени по другой причине.

Суперскалярность.

Теперь обсудим суперскалярность. Мы рассуждали о командном управляющем устройстве и об арифметически-логических устройствах. Суперскалярность — это процессор, который имеет несколько исполняющих устройств, то есть одновременно он может выполнять несколько арифметических и логических операций. Мы обсуждали конвейер, где обрабатывались инструкции, и была часть конвейера, которая выполняла операцию и называлась "исполняющее устройство", где непосредственно делалась основная работа, для которой эта инструкция была написана. Суперскалярность означает, что построен конвейер имеющий несколько исполняющих устройств и одновременно может исполняться несколько различных команд. Исполняющие устройства специфицированы, они не могут исполнить любую инструкцию, у них у каждого своя должность (один выполняет одни виды команд, другой – другие и так далее). То есть у нас появилась возможность выполнять одновременно несколько инструкций на этих исполняющих устройствах. Например до 6 инструкций на микропроцессорах семейства IA32 последних моделей.

Первым суперскалярным процессором интеловской архитектуры был Pentium, и в нем было реализовано исполняемое устройство U и исполняемое устройство V. Одно умело делать все операции, а второе — самые простенькие, например, инкрементирование.

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

Теперь мы берем и изменяем несколько упрощенную модель нашего микропроцессора, чтобы схематично отобразить на ней те свойства, которые мы только что обсуждали. На системной шине работает упреждающая выборка, которая из памяти подгружает данные в систему КЭШа, базируясь на логике железного предсказателя. Отображаем систему КЭШей. В микропроцессоре будет работать конвейер и предсказатель переходов, то есть управляющее устройство будет брать не только те инструкции, которые оно в данный момент собирается выполнять, а также те, которые ему рекомендует брать предсказатель переходов (чтобы конвейер более плотно нагружать). Регистров увеличенное количество, ну и суперскалярность, которую мы можем отобразить как наличие нескольких вычислительно-логических устройств.

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

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

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

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

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

Т.е. в микроархитектурах семейства IA32 реализовано исполнение с изменением последовательности операций (out-of-order-execution). То есть программисты написали какие-то инструкции, подали их на процессор, а он сам выбрал, в каком порядке их выполнять. В данном случае важная часть работы – планирование инструкций выполняется непосредственно микропроцессором.

Это не единственный возможный вариант работы микропроцессора. Есть микропроцессор Intel Atom, предназначенный для различных планшетных устройств, который последовательно выполняет получаемые микроинструкции, или например, процессор Itenium, в котором в процессор поступают инструкции уже объединенные в группы. То есть работа по определению того, какие инструкции независимы и в каком порядке их подавать процессору переложена на компилятор. В этом случае работа по определению оптимального порядка инструкций выполняется один раз — во время компиляции. Это должно быть выгодно с точки зрения энергопотребления.

Если кто-то хочет более подробно с этим все ознакомиться, я отсылаю к инструкциям, к документации от Интел. Вы можете скачать документацию и после этого сидеть и перед сном ее почитывать. Документация содержит много схем, объясняющих более подробно работу микропроцессора и взаимодействия между различными компонентами процессора. Пример, который показывает спецификацию исполняемых устройств. То есть существует внутри конвейера некий распределитель, который поступающие инструкции распределяет на то или иное подходящее исполняющее устройство.

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

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

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

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

Теперь плавно переходя от факторов влияющих на производительность процессора к факторам влияющим на производительность приложения сформулируем какие характеристики приложения влияют на его производительность.

Основные характеристики приложения, влияющие на его производительность:

  • эффективность вычислений.
  • Эффективность работы с памятью
  • Правильное предсказание переходов
  • Эффективность использования векторных инструкций
  • Эффективность параллелизации
  • Уровень инструкционного параллелизма.

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

Правильное предсказание переходов. Мы можем повлиять на этот фактор, удалив лишние переходы, правильно if'ы и else'ы расставить, чтобы у нас статический предсказатель реже ошибался.

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

Измерение производительности – довольно сложная тема. Как вы должны были догадаться из предыдущих рассуждений производительность зависит от двух факторов: от непосредственной качественной работы микропроцессора (МП) и от качества работы оптимизирующего компилятора. То есть качество работы оптимизирующего компилятора влияет непосредственно на результаты измерения производительности. Есть специальная организация – Standard Performance Evaluated Corporation — некоммерческая организация, которая делает аудиторскую независимую оценку производительности разных вычислительных систем. Она занимается сбором типичных задач, предоставляет своим пользователям некую универсальную систему тестирования и гарантирует независимое мнение о производительности микропроцессоров.

Соответственно, если вас интересует вопрос о производительности, вы можете зайти на сайт этой организации, заплатить небольшие деньги и скачать оттуда пакет для измерения производительности, получить доступ к двум различным вычислительным системам, взять этот пакет, инсталлировать его. Пакет позволяет построить и прогнать специальные программы, получить цифры и сказать: "с использованием представительной выборки задач из сюиты такой-то мы получили результат, что вот эта система в таких-то задачах эту систему превосходит, а на таких задачах немного проигрывает". В мире существуют аналитики, которые на этом зарабатывают деньги. Перед публикацией в научных компьютерных журналах своих отчетов, они используют этот пакет. Есть различные пакеты CPU2006, OMP2001 и так далее для тестирования различных аспектов производительности. Поскольку производительность зависит от микропроцессора и от компилятора, то компилятор — это важная часть в борьбе за признание высокой производительностей изделий. Если появляется новый микропроцессор, которые реализует какие-то новые команды, трудно показать улучшение его производительности из-за этих команд если не будет компилятора способного использовать эти команды в исполняемой программе. Другой фактор влияния компилятора на производительность связан с тем, что если в процессе эксплуатации процессора обнаружены какие-то инструкции, которые на процессоре почему-либо выполняются медленно, то с помощью компилятора мы можем каким-то образом заменить плохие инструкции на хорошие. Компилятор также активно используется при тестировании и разработке новых архитектур.

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

Можно провести некую аналогию на использование компилятора. Например, выполнение какой-то расчетной задачи мы можем сравнить с прохождением человеком некоего маршрута по пересеченной местности из точки А в точку В. Примерную схему маршрута и контрольные точки определил разработчик, написавший алгоритм и запрашивающий результаты рассчетов. Процессор в данном случае будет отвечать за физические кондиции того человека, который пойдет через лес. То есть он может быть очень сильный и может идти по ровной местности со скоростью 6 км/ч. Другой процессор может идти со скоростью 5 км/ч. А дальше вопрос стоит в выборе маршрута. Умный компилятор найдет места, где мы можем срезать путь и пойти более короткой дорогой. Формально, может случиться так, что процессор, который обеспечивает меньшую скорость, за счет компилятора данную задачу по перемещению из точки А в точку В выполнит быстрее.