Компиляторы Intel. Совместное использование модулей на Фортране и Си

Компиляторы Intel C++ и Fortran и библиотека MKL

Наряду со стандартными для Linux компиляторами GNU, на кластерах вычислительного комплекса НИВЦ установлены компиляторы Intel C++ и Fortran. На настоящее время (начало 2006 года) на всех кластерах установлены компиляторы версии 9.1. Настоящая страница посвящена описанию наиболее важных опций и настроек этих компиляторов, а также их основных отличий от компиляторов GNU . Страница ориентирована, в основном, на пользователей кластеров НИВЦ МГУ, но может быть полезна и другим русскоязычным пользователям. Здесь не затрагиваются вопросы, связанные с компиляцией для платформы IA-64.

Также на всех кластерах установлена библиотека Intel Kernel Math Library (MKL) версии 8.0.2. Библиотека располагается в каталоге /usr/mkl. Обращаем внимание на то, что в каталоге lib доступны подкаталоги 32, 64 и em64t. На кластере Ant необходимо использовать библиотеки из подкаталога em64t, а на остальных кластерах - из подкаталога 32. Вся необходимая документация и примеры могут быть получены из каталога /usr/mkl/doc.

Для чего потребовались новые компиляторы?

Необходимость в новых компиляторах возникла, главным образом, а) для поддержки программирования на языке Фортран 90, а также б) для более мощной оптимизации программ на языке Фортран, чем обеспечивает компилятор g77, использующий трансляцию в язык Си и затем компиляцию с помощью gcc.

Этим требованиям удовлетворяют также компиляторы PGI (Portland Group), но компания-разработчик отказалась поставлять их в Россию.

Как воспользоваться?

Компиляторы Intel вызываются с помощью команд icc (C или C++), icpc (C++) и ifort (Фортран 77/90). Команды mpicc, mpiCC и mpif77 для компиляции и сборки MPI-программ также настроены на использование компиляторов Intel.

Сохраняется также возможность пользоваться компиляторами GNU с помощью команд mpigcc, mpig++ и mpig77 (Фортран 90 не поддерживается).

Входные файлы

По умолчанию, файлы с расширением .cpp и .cxx считаются исходными текстами на языке С++, файлы с расширением .c - исходными текстами на языке Си, а компилятор icpc также компилирует файлы.c как исходные тексты на С++.

Файлы с расширениями .f , .ftn и .for распознаются как исходные тексты на языке Фотран, с фиксированной формой записи, а файлы .fpp и .F дополнительно пропускаются через препроцессор языка Фортран. Файлы с расширением .f90 считаются исходными текстами Фортран 90/95 со свободной формой записи. Явным образом можно задать фиксированную или свободную форму записи Фортран-программ с помощью опций -FI и -FR соответственно.

Файлы с расширением .s распознаются как код на языке ассемблера для IA-32.

Характеристики компиляторов Intel

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

  • Значительная оптимизация
    видимо, здесь имеется в виду оптимизация кода еще на высоком уровне, т.е. прежде всего, различные преобразования циклов, что с большим или меньшим успехом делают почти все компиляторы
  • Оптимизация вычислений с плавающей точкой
    видимо, имеется в виду прежде всего максимальное использование команд, реализованных на аппаратном уровне
  • Межпроцедурные оптимизации
    т.е. глобальная оптимизация всей программы, в отличие от обычной оптимизации, которая затрагивает только код конкретных функций
  • Оптимизация на базе профилей
    т.е. возможность прогнать программу в тестовом режиме, собрать данные о времени прохождение тех или иных фрагментов кода внутри часто используемых функций, а затем использовать эти данные для оптимизации
  • Поддержка системы команд SSE в процессорах Pentium III
    примечание: для вычислительных задач больший интерес представляют команды SSE2, т.е. векторные команды над 64-разрядными вещественными числами, но они поддерживаются только в процессорах Pentium 4, которых в нашем распоряжении пока нет
  • Автоматическая векторизация
    т.е. опять же, использование команд SSE и SSE2, вставляемых автоматически компилятором
  • Поддержка OpenMP для программирования на SMP-системах
    примечание: на кластере рекомендуется преимущественно пользоваться интерфейсом MPI; широкое использование OpenMP на кластере не предполагается и таких экспериментов пока не проводилось; но, вероятно, имеет смысл пользоваться библиотеками (BLAS и др.), распараллеленными для общей памяти.
  • Предвыборка данных
    т.е. видимо, использование команд предварительной загрузки из памяти в кэш данных, которые понадобятся через некоторое время
  • "Диспетчеризация" кода для различных процессоров
    т.е. возможность генерации кода для различных процессоров в одном исполняемом файле, что позволяет использовать преимущества новейших процессоров для достижения на них наибольшей производительности, при сохранении двоичной совместимости программ с более ранними процессорами; на нашем кластере это пока не актуально, т.к. используются только процессоры Pentium III, а также не предполагается передача и запуск на других машинах программ, откомпилированных на кластере

Основные опции компиляторов

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

Уровни оптимизации
Опция Описание
-O0 Отключает оптимизацию
-O1 или -O2 Базовая оптимизация на скорость работы. Отключается инлайн-вставка библиотечных функций. Для компилятора С++ эти опции дают одинаковую оптимизацию, для компилятора Фортрана опция -O2 предпочтительнее, т.к. включает еще раскрутку циклов.
-O3 Более мощная оптимизация, включая преобразования циклов, предвыборку данных, использование OpenMP. На некоторых программах может не гарантироваться повышенная производительность по сравнению с -O2 . Имеет смысл использовать вместе с опциями векторизации -xK и -xW .
-unroll[n] Включает раскрутку циклов до n раз.
Оптимизации под конкретный процессор
Опция Описание
-tpp6 Оптимизация для процессоров Penitum Pro, Pentium II и Pentium III
-tpp7 Оптимизация для процессоров Penitum 4 (эта опция включена по умолчанию для компилятора на IA-32)
-xM Генерация кода с использованием расширений MMX, специфических для процессоров Pentium MMX, Pentium II и более поздних
-xK Генерация кода с использованием расширений SSE, специфических для процессоров Pentium III
-xW Генерация кода с использованием расширений SSE2, специфических для процессоров Pentium 4
Межпроцедурная оптимизация
-ip Включается межпроцедурная оптимизация внутри одного файла. Если при этом указать опцию -ip_no_inlining , то отключаются инлайн-вставки функций.
-ipo Включается межпроцедурная оптимизация между различными файлами
Оптимизации с использованием профилей
-prof_gen Генерируется "профилировочный" код, который будет использован для профилировки, т.е. сбора данных о частоте прохождения тех или иных мест в программе
-prof_use Производится оптимизация на основе данных, полученных на этапе профилировки. Имеет смысл использовать вместе с опцией межпроцедурной оптимизации -ipo .
Распараллеливание для SMP-систем
-openmp Включается поддержка стандарта OpenMP 2.0
-parallel Включается автоматическое распараллеливание циклов

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

Согласно результатам прогона тестов SPEC CPU2000, опубликованным на сервере ixbt.com, компиляторы Intel версии 6.0 практически везде оказались лучше по сравнению с компиляторами gcc версий 2.95.3, 2.96 и 3.1, и PGI версии 4.0.2. Эти тесты проводились в 2002 году на компьютере с процессором Pentium 4/1.7 ГГц и ОС RedHat Linux 7.3.

Согласно результатам тестов, проведенных компанией Polyhedron, компилятор Intel Fortran версии 7.0 почти везде оказался лучше по сравнению с другими компиляторами Fortran 77 для Linux (Absoft, GNU, Lahey, NAG, NAS, PGI). Только в некоторых тестах компилятор Intel незначительно проигрывает компиляторам Absoft, NAG и Lahey. Эти тесты были проведены на компьютере с процессором Pentium 4/1.8 ГГц и ОС Mandrake Linux 8.1.

Компиляторы Intel версии 9.1 также обгоняют по производительности компиялторы gcc, и показывают производительность сравнимую с Absoft, PathScale и PGI.

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

Библиотеки

Компилятор языка Си использует runtime-библиотеку, разработанную в рамках проекта GNU (libc.a ).

Вместе с компилятором Intel C++ поставляются следующие библиотеки:

  • libcprts.a - runtime-библиотека языка С++ разработки Dinkumware .
  • libcxa.a - дополнительная runtime-библиотека для С++ разработки Intel.
  • libimf.a - библиотека математических функций разработки Intel, в которую входят оптимизированные и высокоточные реализации тригонометрических, гиперболических, экспоненциальных, специальных, комплексных и других функций (подробнее см. список функций).
  • libirc.a - runtime-поддержка профилировки (PGO) и "диспетчеризации" кода в зависимости от процессора (см. выше).
  • libguide.a - реализация OpenMP.

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

Вместе с компилятором Фортрана поставляются следующие библиотеки: libCEPCF90.a , libIEPCF90.a , libintrins.a , libF90.a , также используется библиотека математических функций libimf.a.

Сборка исполняемого файла

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

Таким образом, если Вы установили компилятор Intel на своей машине с Linux и хотите запускать собранные исполняемые файлы на других машинах, то нужно или использовать статическую сборку (что проще) или скопировать на эти машины динамические библиотеки Intel (обычно из директории вида /opt/intel/compiler70/ia32/lib) в одну из директорий, перечисленных в файле /etc/ld.so.conf, а также позаботиться о том, чтобы на этих машинах был установлен одинаковый набор динамических библиотек GNU/Linux.

По умолчанию, все библиотеки разработки Intel (кроме libcxa.so) подключаются статически, а все системные библиотеки Linux и библиотеки GNU подключаются динамически. С помощью опции -static можно заставить сборщик (редактор связей) подключить все библиотеки статически (что увеличит объем исполняемого файла), а с помощью опции -i_dynamic можно подключать динамически все библиотеки разработки Intel.

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

С помощью опций -Bstatic и -Bdynamic можно явно задавать динамическое или статическое подключение каждой из библиотек, заданных в командной строке.

С помощью опции -c сборка исполняемого файла отключается и производится только компиляция (генерация объектного модуля).

Совместное использование модулей на Фортране и Си

Чтобы совместно использовать модули, написанные на языках Фортран и Си, нужно согласовать именование процедур в объектных модулях, передачу параметров, а также доступ к глобальным переменным, если такие есть.

По умолчанию, компилятор Intel Fortran переводит имена процедур в нижний регистр и добавляет в конец имени знак подчеркивания. Компилятор Си никогда не изменяет имена функций. Таким образом, если мы хотим из модуля на Фортране вызвать функцию или процедуру FNNAME, реализованную на Си, то в модуле на Си она должна именоваться fnname_.

Компилятор Фортрана поддерживает опцию -nus [имя файла] , которая позволяет отключать добавление знаков подчеркивания к внутренним именам процедур. Если задано имя файла, то это производится только для имен процедур, перечисленным в заданном файле.

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

В модулях на Си возможно использование COMMON-блоков, определенных внутри модулей на Фортране (подробнее об этом см. Intel Fortran Compiler User"s Guide, глава Mixing C and Fortran).

Совместное использование компиляторов Intel и GCC

Объектные модули на языке Си, полученные компилятором Intel C++, совместимы с модулями, полученными компилятором GCC и библиотекой GNU для языка Си. Таким образом, эти модули могут совместно использоваться в одной программе, собираемой с помощью команд icc или gcc, но для корректного подключения библиотек Intel рекомендуется использовать icc.

Компилятор Intel поддерживает ряд нестандартных расширений языка Си, используемых в рамках проекта GNU и поддерживаемых компилятором GCC (но не все из них, подробнее см. здесь).

О совместимости объектных модулей на языках С++ и Фортран в руководстве пользователя ничего не сказано, видимо, она не поддерживается.

Поддержка стандартов

Компилятор Intel C++ Compiler 7.0 for Linux поддерживает стандарт языка Си ANSI/ISO (ISO/IEC 9899/1990). Возможно установка строгой совместимости cо стадартом ANSI C (-ansi ) или расширенного диалекта ANSI C (-Xa ). При использовании опции -c99

  • Руководства по компиляторам в формате HTML (доступны в "онлайн" на нашем сервере, но требуется поддержка языка Java)
    • Intel C++ Compiler User"s Guide.
    • Intel Fortran Compiler User"s Guide.
  • Руководства по компиляторам на английском языке в формате PDF (требуется программа Acrobat Reader, нужно скачать PDF-файлы на свой компьютер)
    • Руководство пользователя по компилятору Intel С++: Intel C++ Compiler User"s Guide (1.3 Мбайт, 395 страниц).
    • Руководство пользователя по компилятору Intel Fortran: Intel Fortran Compiler User"s Guide (1.1 Мбайт, 285 страниц).
    • Справочник программиста на языке Фортран: Intel Fortran Programmer"s Reference (7 Мбайт, 566 страниц).
    • Справочник по библиотекам для языка Фортран: Intel Fortran Libraries Reference Manual (9.5 Мбайт, 881 страница).
  • Руководство по отладчику Intel Application Debugger.
  • Сравнение компиляторов на тестах SPEC CPU2000 (статья на сайте ixbt.com на русском языке).
  • На сайте компании Polyhedron представлены результаты сравнения различных компиляторов.
  • Ты - не раб!
    Закрытый образовательный курс для детей элиты: "Истинное обустройство мира".
    http://noslave.org

    Материал из Википедии - свободной энциклопедии

    Intel C++ Compiler
    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).
    Тип
    Автор

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Разработчик
    Разработчики

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Написана на

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Интерфейс

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Операционная система
    Языки интерфейса

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Первый выпуск

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Аппаратная платформа
    Последняя версия
    Кандидат в релизы

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Бета-версия

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Альфа-версия

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Тестовая версия

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Читаемые форматы файлов

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Создаваемые форматы файлов

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Состояние

    Ошибка Lua в Модуль:Wikidata на строке 170: attempt to index field "wikibase" (a nil value).

    Лицензия

    Основные возможности:

    • Векторизация для SSE , SSE2 , SSE3 , SSE4

    Компилятор поддерживает стандарт OpenMP 3.0 для написания параллельных программ. Также содержит модификацию OpenMP под названием Cluster OpenMP, при помощи которой можно запускать приложения написанные в соответствии с OpenMP на кластерах , использующих MPI .

    Intel C++ Compiler использует фронтэнд (часть компилятора, занимающаяся синтаксическим анализом компилируемой программы) от Edison Design Group . Этот же фронтэнд используется компиляторами SGI MIPSpro , Comeau C++ , Portland Group .

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

    Существует 4 серии продуктов от Intel , содержащих компилятор:

    • Intel C++ Compiler Professional Edition
    • Intel Cluster Toolkit (Compiler Edition)

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

    Экспериментальные варианты

    Публиковались следующие экспериментальные варианты компилятора:

    • Intel STM Compiler Prototype Edition от 17 сентября 2007 года. Поддержка Software Transactional Memory (STM). Выпущен для Linux и Windows, только для IA-32 (x86-процессоров);
    • Intel Concurrent Collections for C/C++ 0.3 от сентября 2008 года. Содержит механизмы, облегчающие написание параллельных C++ программ.

    Основные флаги

    Windows Linux, MacOSX Описание
    /Od -O0 Отключить оптимизации
    /O1 -O1 Оптимизировать для минимизации размера исполняемого файла
    /O2 -O2 Оптимизировать для повышения скорости. Включены некоторые оптимизации
    /O3 -O3 Включить все оптимизации из O2. Также выполнить интенсивные оптимизации циклов
    /Oip -Oip Включить пофайловую межпроцедурную оптимизацию
    /Oipo -Oipo Включить глобальную межпроцедурную оптимизацию
    /QxO -xO Разрешить использование SSE3, SSE2 и SSE расширений для процессоров производства любых компаний
    /fast -fast «Быстрый режим». Эквивалентен опциям «/O3 /Qipo /QxHost /no-prec-div» на Windows и «-O3 -ipo -static -xHOST -no-prec-div» на Linux. Заметьте, флаг «-xHOST» означает оптимизацию для того процессора, на котором запущен компилятор.
    /Qprof-gen -prof_gen Создать инструментированную версию программы, которая соберет профиль исполнения
    /Qprof-use -prof_use Воспользоваться профильной информацией от запусков программы собранной с флагом prof_gen.

    Напишите отзыв о статье "Intel C++ compiler"

    Примечания

    См. также

    Ссылки

    Отрывок, характеризующий Intel C++ compiler

    А ещё, она вернулась для того, чтобы в последний раз увидеть Белого Волхва... Своего супруга и вернейшего друга, которого так и не смогла никогда забыть. В своём сердце она простила его. Но, к его великому сожалению, не смогла принести ему прощение Магдалины.... Так что, как видишь, Изидора, великая христианская басня о «всепрощении» это просто детская ложь для наивных верующих, чтобы разрешить им творить любое Зло, зная, что чего бы они ни сделали, в конечном итоге их простят. Но прощать можно лишь то, что по-настоящему достойно прощения. Человек должен понимать, что за любое свершённое Зло ему приходится отвечать... И не перед каким-то таинственным Богом, а перед собой, заставляя себя же жестоко страдать. Магдалина не простила Владыко, хотя глубоко уважала и искренне любила его. Так же, как она не сумела простить и всех нас за страшную смерть Радомира. Ведь именно ОНА лучше всех понимала – мы могли помочь ему, могли спасти его от жестокой смерти... Но не захотели. Считая вину Белого Волхва слишком жестокой, она оставила его жить с этой виной, ни на минуту не забывая её... Она не захотела даровать ему лёгкого прощения. Мы так больше никогда и не увидели её. Как никогда не увидели и их малышей. Через одного из рыцарей своего Храма – нашего волхва – Магдалина передала ответ Владыке на его просьбу вернуться к нам: «Солнце не восходит в один день дважды... Радость вашего мира (Радомир) уже никогда не вернётся к вам, как не вернусь к вам и я... Я нашла свою ВЕРУ и свою ПРАВДУ, они ЖИВЫЕ, ваша же – МЕРТВА... Оплакивайте своих сыновей – они вас любили. Я же никогда не прощу вам их смерти, пока жива. И пусть вина ваша остаётся с вами. Возможно, когда-нибудь она принесёт вам Свет и Прощение... Но не от меня». Голову же Волхва Иоанна не привезли в Мэтэору по той же самой причине – никто из рыцарей Храма не захотел возвращаться к нам... Мы потеряли их, как теряли не раз многих других, кто не хотел понять и принять наших жертв... Кто так же, как ты – ушли, осуждая нас.
    У меня кружилась голова!.. Как жаждущий, утоляя свой вечный голод знания, я жадно впитывала поток удивительной информации, щедро даримой Севером... И мне хотелось намного больше!.. Хотелось знать всё до конца. Это было глотком свежей воды в выжженной болью и бедами пустыне! И я никак не могла вдоволь напиться...
    – У меня тысячи вопросов! Но не осталось времени... Что же мне делать, Север?..
    – Спрашивай, Изидора!.. Спрашивай, я постараюсь ответить тебе...
    – Скажи, Север, почему мне кажется, что в этой истории как бы соединились две истории жизни, оплетённые схожими событиями, и преподносятся они, как жизнь одного лица? Или я не права?
    – Ты абсолютно права, Изидора. Как я уже говорил тебе ранее, «сильные мира сего», кто создавал фальшивую историю человечества, «надели» на истинную жизнь Христа чужую жизнь иудейского пророка Джошуа (Joshua), жившего полторы тысячи лет тому назад (со времени рассказа Севера). И не только его самого, но и его семьи, его родных и близких, его друзей и последователей. Ведь именно у жены пророка Джошуа, иудейки Марии, была сестра Марта и брат Лазарь, сестра его матери Мария Якобе, и другие, которых никогда не было рядом с Радомиром и Магдалиной. Так же, как не было рядом с ними и чужих «апостолов» – Павла, Матфея, Петра, Луки и остальных...
    Именно семья пророка Джошуа перебралась полторы тысячи лет назад в Прованс (который в те времена назывался Гаул (Transalpine Gaul), в греческий город Массалию (теперешний Марсель), так как Массалия в то время была «воротами» между Европой и Азией, и это было самым лёгким путём для всех «гонимых» во избежание преследований и бед.

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

    Последние версии компиляторов Intel Intel C++ и Intel Fortran для ОС Windows и Linux позволяют получить выигрыш в производительности приложений для систем на базе процессоров Intel Itanium 2, Intel Xeon и Intel Pentium 4 до 40% по сравнению с существующими компиляторами от других производителей за счет использования таких особенностей указанных процессоров, как технология Hyper-Threading.

    К отличиям, связанным с оптимизацией кода данным семейством компиляторов, следует отнести применение стека для выполнения операций с плавающей точкой, межпроцедурную оптимизацию (Interprocedural Optimization, IPO), оптимизацию в соответствии с профилем приложения (Profile Guided Optimization, PGO), предварительную загрузку данных в кэш (Data prefetching), которая позволяет избежать задержки, связанной с доступом к памяти, поддержку характерных особенностей процессоров Intel (например, расширений для потоковой обработки данных Intel Streaming SIMD Extensions 2, характерных для Intel Pentium 4), автоматическое распараллеливание выполнения кода, создание приложений, выполняющихся на нескольких разных типах процессоров при оптимизации для одного из них, средства «предсказания» последующего кода (branch prediction), расширенную поддержку работы с потоками выполнения.

    Отметим, что компиляторы Intel применяются в таких известных компаниях, как Alias/Wavefront, Oracle, Fujitsu Siemens, ABAQUS, Silicon Graphics, IBM. По данным независимого тестирования, проведенного рядом компаний, производительность компиляторов Intel значительно превышает производительность компиляторов других производителей (см., например, http://intel.com/software/products/compilers/techtopics/compiler_gnu_perf.pdf).

    Ниже мы рассмотрим некоторые особенности последних версий компиляторов Intel для настольных и серверных операционных систем.

    Компиляторы для платформы Microsoft Windows

    Intel C++ Compiler 7.1 для Windows

    Intel C++ Compiler 7.1 — это компилятор, выпущенный в начале этого года, который позволяет достичь высокой степени оптимизации кода для процессоров Intel Itanium, Intel Itanium 2, Intel Pentium 4 и Intel Xeon, а также для процессора Intel Pentium M, использующего технологию Intel Centrino и предназначенного для применения в мобильных устройствах.

    Указанный компилятор полностью совместим со средствами разработки Microsoft Visual C++ 6.0 и Microsoft Visual Studio .NET: он может быть встроен в соответствующие среды разработки.

    Данный компилятор поддерживает стандарты ANSI и ISO C/C++.

    Intel Fortran Compiler 7.1 для Windows

    Компилятор Intel Fortran Compiler 7.1 для Windows, также выпущенный в начале текущего года, позволяет создавать оптимизированный код для процессоров Intel Itanium, Intel Itanium 2, Intel Pentium 4 и Intel Xeon, Intel Pentium M.

    Этот компилятор полностью совместим со средствами разработки Microsoft Visual C++ 6.0 и Microsoft Visual Studio .NET, то есть может быть встроен в соответствующие среды разработки. Кроме того, данный компилятор позволяет вести разработку 64-разрядных приложений для операционных систем, выполняющихся на процессорах Itanium/Itanium 2, с помощью Microsoft Visual Studio на 32-разрядном процессоре Pentium с применением 64-разрядного компилятора Intel Fortran Compiler. При отладке кода данный компилятор позволяет применять отладчик для платформы Microsoft .NET.

    При наличии установленного продукта Compaq Visual Fortran 6.6 можно применять вместо исходного компилятора Intel Fortran Compiler 7.1, так как указанные компиляторы совместимы на уровне исходного кода.

    Компилятор Intel Fortran Compiler 7.1 для Windows полностью совместим со стандартом ISO Fortran 95 и поддерживает создание и отладку приложений, содержащих код на двух языках — С и Fortran.

    Компиляторы для платформы Linux

    Intel C++ Compiler 7.1 для Linux

    Еще один компилятор, увидевший свет в начале года, Intel C++ Compiler 7.1 для Linux, позволяет достичь высокой степени оптимизации кода для процессоров Intel Itanium, Intel Itanium 2, Intel Pentium 4 , Intel Pentium M. Данный компилятор полностью совместим с компилятором GNU C на уровне исходного кода и объектных модулей, что без дополнительных затрат позволяет осуществлять миграцию на него приложений, созданных с помощью GNU C. Компилятор Intel C++ Compiler поддерживает C++ ABI (дополнение к ядру Linux, позволяющее выполнять под управлением Linux скомпилированный код для других платформ, таких как ранние операционные системы SCO, ранние версии Sun Solaris и др.), а это означает полную совместимость с компилятором gcc 3.2 на уровне двоичного кода. Наконец, с помощью компилятора Intel C++ Compiler 7.1 для Linux можно даже перекомпилировать ядро Linux, сделав несколько незначительных изменений в его исходном коде.

    Intel Fortran Compiler 7.1 для Linux

    Компилятор Intel Fortran Compiler 7.1 для Linux позволяет создавать оптимизированный код для процессоров Intel Itanium, Intel Itanium 2, Intel Pentium 4, Intel Pentium M. Данный компилятор полностью совместим с компилятором Compaq Visual Fortran 6.6 на уровне исходного кода, позволяет осуществлять с его помощью перекомпиляцию приложений, созданных с помощью Compaq Visual Fortran, повышая таким образом их производительность.

    Кроме того, указанный компилятор совместим с такими применяемыми разработчиками утилитами, как редактор emacs, отладчик gdb, утилита для сборки приложений make.

    Как и Windows-версия данного компилятора, Intel Fortran Compiler 7.1 для Linux полностью совместим со стандартом ISO Fortran 95 и поддерживает создание и отладку приложений, содержащих код на двух языках — С и Fortran.

    Следует особо подчеркнуть, что существенный вклад в создание перечисленных компиляторов Intel внесли специалисты Российского центра Intel по разработке программного обеспечения в Нижнем Новгороде. Более подробную информацию о компиляторах Intel можно найти на Web-сайте корпорации Intel по адресу: www.intel.com/software/products/ .

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

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

    Новая серия включает компиляторы Intel для языков C++ и Fortran для ОС Windows и Linux, а также компиляторы Intel для языка C++ для ОС Windows CE .NET. Компиляторы ориентированы на системы на базе следующих процессоров Intel: Intel Itanium 2, Intel Xeon, Intel Pentium 4, процессоров с архитектурой Intel Personal Internet Client Architecture для мобильных телефонов и карманных ПК и процессора Intel Pentium M для мобильных ПК (компонент технологии Intel Centrino для мобильных ПК).

    В компиляторе Intel Visual Fortran для ОС Windows реализованы технологии компиляции нового поколения для высокопроизводительных вычислительных решений. Он соединяет в себе функциональность языка Compaq Visual Fortran (CVF) и повышение производительности, ставшее возможным благодаря технологиям оптимизации компиляции и генерации кода корпорации Intel, и упрощает задачу переноса исходного кода, разработанного с помощью CVF, в среду Intel Visual Fortran. В этом компиляторе функции CVF впервые реализованы как для 32-разрядных систем Intel, так и для систем на базе процессоров семейства Intel Itanium, работающих в среде Windows. Кроме того, этот компилятор позволяет реализовать языковые функции CVF в системах под управлением ОС Linux на базе 32-разрядных процессоров Intel и процессоров семейства Intel Itanium. В 2004 году планируется выпустить расширенную версию этого компилятора - компилятор Intel Visual Fortran Compiler Professional Edition для ОС Windows, в состав которой будет включена библиотека IMSL Fortran 5.0 Library, разработанная компанией Visual Numerics, Inc.


    "Новые компиляторы поддерживают также будущие процессоры Intel, известные под кодовым названием Prescott, в которых предусмотрены новые команды для повышения производительности графики и видео, а также другие средства увеличения производительности. Они также поддерживают новую технологию Mobile MMX(tm), аналогичным образом повышающую производительность графических, звуковых и видеоприложений для мобильных телефонов и карманных ПК, - отметил со-директор Центра Intel по разработке ПО в Нижнем Новгороде Алексей Одиноков. - Эти компиляторы предоставляют разработчикам приложений единый комплекс инструментальных средств для построения новых приложений для беспроводных сетей на основе архитектуры Intel. Новые компиляторы Intel также поддерживают технологию Hyper-Threading корпорации Intel и отраслевую спецификацию OpenMP 2.0, определяющую использование директив высокого уровня для управления потоками инструкций в приложениях".

    Среди новых инструментов, включенных в компиляторы - средства Intel Code Coverage и Intel Test Prioritization. Вместе эти средства позволяют ускорить разработку приложений и повысить их качество за счет улучшения процесса тестирования программного обеспечения.

    Средство Code Coverage в ходе тестирования приложения предоставляет полные сведения об использовании логики приложения и о расположении используемых участков в исходном коде приложения. В случае, если в приложение вносятся изменения или если данный тест не позволяет проверить часть приложения, интересующую разработчика, средство Test Prioritization позволяет проверить работу выбранного участка программного кода.

    Новые компиляторы Intel выпускаются в разных комплектациях стоимостью от 399 до 1499 долларов. Их можно приобрести уже сегодня в корпорации Intel или у реселлеров по всему миру, список которых расположен на сайте http://www.intel.com/software/products/reseller.htm#Russia .

    Поддержка процессоров Prescott

    Поддержка процессора Intel Pentium 4 (Prescott) в восьмой версии компилятора заключается в следующем:

    1. Поддержка команд SSE3 (или PNI, Prescott New Instructions). Здесь стоит выделить три способа:

    а. Ассемблерные вставки (Inline assembly). Например, компилятор распознает нижеследующее использование команды из набора SSE3 _asm{addsubpd xmm0, xmm1}. Таким образом пользователи, заинтересованные в низкоуровневой оптимизации, могут получить прямой доступ к ассемблерным командам.

    б. В С/C++ компиляторе новые инструкции доступны и с более высокого уровня, чем использование ассемблерных вставок. А именно, посредством встроенных функций (intrinsic functions):

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

    Встроенная функция Генерируемая команда
    _mm_addsub_ps Addsubps
    _mm_hadd_ps Haddps
    _mm_hsub_ps Msubps
    _mm_moveldup_ps Movsldup
    _mm_movehdup_ps Movshdup
    _mm_addsub_pd Addsubpd
    _mm_hadd_pd Haddpd
    _mm_hsub_pd Hsubpd
    _mm_loaddup_pd movddup xmm, m64
    _mm_movedup_pd movddup reg, reg
    _mm_lddqu_si128 Lddqu

    В таблице показаны встроенные функции и соответствующие ассемблерные команды из набора SSE3. Такая же поддержка существует и для команд из наборов MMX\SSE\SSE2. Это позволяет программисту осуществлять низкоуровневую оптимизацию кода, не прибегая к программированию на ассемблере: компилятор сам заботится об отображении (mapping"е) встроенных функций на соответствующие команды процессора и оптимальном использовании регистров. Программист может сконцентрироваться на создании алгоритма, эффективно использующего новые наборы команд.

    в. Автоматическая генерация новых команд компилятором. Предыдущие два способа предполагают использование программистом новых команд. Но компилятор способен также (при использовании соответствующих опций - см. секцию 3 ниже) автоматически генерировать новые команды из набора SSE3 для программного кода на языках С/C++ и Fortran. Например, оптимизированную команду невыровненной загрузки (lddqu), использование которой позволяет получить выигрыш по производительности до 40% (например, в задачах видео- и аудиокодирования). Другие команды из набора SSE3 позволяют получить существенное ускорение в задачах 3D графики или расчетных задачах с использованием комплексных чисел. Например, график в секции 3.1 ниже показывает, что для приложения 168.wupwise из набора SPEC CPU2000 FP ускорение, полученное от автоматической генерации команд SSE3 составило ~25%. Производительность этого приложения существенно зависит от скорости работы арифметики комплексных чисел.

    2. Использование микроархитектурных преимуществ процессора Prescott. При генерации кода компилятор учитывает микроархитектурные изменения в новом процессоре. Например, выполнение некоторых операций (таких как целочисленные сдвиги, умножение целых чисел или преобразования чисел между различными форматами с плавающей точкой в SSE2) ускорилось на новом процессоре по отношению к предыдущим версиям (скажем, целочисленный сдвиг занимает теперь один процессорный такт против четырех для предыдущей версии процессора Intel Pentium 4). Более интенсивное использование таких команд позволяет получить существенное ускорение работы приложений.
    Другим примером микроархитектурных изменений служит улучшенный механизм store forwarding (быстрой загрузки данных, сохраняемых ранее в памяти); реальное сохранение происходит даже не в кэш-память, а в некоторый промежуточный буфер сохранения, что позволяет осуществить затем очень быстрый доступ к данным. Такая особенность архитектуры дает возможность, например, осуществить более агрессивную автоматическую векторизацию программного кода.
    Компилятор также учитывает возросший объем кэш-памяти первого и второго уровня.

    3. Улучшенная поддержка технологии Hyper-Threading. Данный пункт вполне может быть отнесен к предыдущему - микроархитектурным изменениям и их использованию в компиляторе. Например, библиотека времени исполнения, в которой реализуется поддержка отраслевой спецификации OpenMP, была оптимизирована для выполнения на новом процессоре.

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

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


    1.1 Оптимизация программ с помощью перекомпиляции и изменения настроек компилятора


    Зачастую первым шагом в переходе на новый оптимизирующий компилятор является его использование с настройками по умолчанию. Следующий логичный шаг - использование опций для более агрессивной оптимизации. На рисунках 1, 2, 3 и 4 показан эффект от перехода на интеловский компилятор версии 8.0 по сравнению с использованием других лидирующих в отрасли продуктов (-O2 - настройки компиляторов по умолчанию, base - настройки на максимальную производительность). Сравнение проводится на 32- и 64-битных архитектурах Intel. В качестве тестового набора используются приложения из SPEC CPU2000.


    Рисунок 1




    Рисунок 2




    Рисунок 3




    Рисунок 4


    Ниже перечислены некоторые опции (далее по тексту опции приведены для семейства ОС Windows; для семейства ОС Linux существуют опции с тем же действием, но название может отличаться; например, -Od или QxK для Windows оказывают аналогичное действие с -O0 или -xK для Linux соответственно; более подробную информацию можно найти в руководстве по использованию компилятора), поддерживаемые компилятором Intel.


    Контроль уровней оптимизации : Опции -Od (отсутствие оптимизаций; применяется для отладки программ), -O1 (максимальная скорость при минимизации размера кода), -O2 (оптимизация по скорости исполнения кода; применяется по умолчанию), -O3 (включает наиболее агрессивные оптимизации по скорости исполнения кода; в некоторых случаях может приводить к обратному эффекту, т.е. к замедлению; нужно отметить, что на IА-64 использование -O3 ведет к ускорению в большинстве случаев, тогда как положительный эффект на IA-32 менее ярко выражен). Примеры оптимизаций, включаемых по -O3: перестановка порядка вложенных циклов (loop interchange), слияние циклов (loop fusion), разделение цикла(-ов) (loop distribution; оптимизация, обратная loop fusion), программная предвыборка (software prefetch) данных. Причина, по которой возможно замедление при использовании -O3, может заключаться в том, что компилятор использовал эвристический подход к выбору агрессивной оптимизации для конкретного случая, не имея достаточной информации о программе (например, сгенерировал команды предвыборки для данных, используемых в цикле, полагая, что цикл выполняется большое количество раз, тогда как на самом деле он имеет лишь несколько итераций). Интерпроцедурная оптимизация по профилированию, а также разнообразные "подсказки" программиста (см. секцию 3.2) могут помочь в данной ситуации.

    Интерпроцедурная оптимизация : -Qip (в рамках одного файла) и -Qipo (в рамках нескольких или всех файлов проекта). Включает такие оптимизации, как, например, инлайн-подстановка часто использующегося кода (сокращение расходов на вызов функции/процедуры). Представляет информацию другим стадиям оптимизации - например, информацию о верхней границе цикла (скажем, если это константа времени компиляции, определенная в одном файле, а используемая во многих) или информацию о выравнивании данных в памяти (многие команды MMX\SSE\SSE2\SSE3 работают быстрее, если операнды выровнены в памяти на границу в 8 или 16 байт). Анализ процедур аллокации памяти (реализованных\вызванных в одном из файлов проекта) передается в те функции\процедуры, где эта память используется (это может помочь компилятору отказаться от консервативного предположения, что данные не выровнены в памяти должным образом; а предположение должно быть консервативным при отсутствии дополнительной информации). Еще одним примером может служить анализ пересечений по памяти (disambiguation, data aliasing analysis): при отсутствии дополнительной информации и невозможности доказать отсутствие пересечений, компилятор исходит из консервативного предположения, что пересечения есть. Такое решение может негативно сказаться на качестве таких оптимизаций, как, например, автоматическая векторизация на IA-32 или программная конвейеризация (software pipelining или SWP) на IA-64. Интерпроцедурная оптимизация может помочь в анализе наличия пересечений по памяти.

    Оптимизация по профилированию : Включает в себя три стадии. 1) генерацию инструментированного кода с помощью опции -Qprof_gen. 2) полученный код запускается на репрезентативных данных, во время работы собирается информация о различных характеристиках выполнения кода (например, вероятности перехода или типичное значение для количества итераций цикла). 3) Повторная компиляция с опцией -Qprof_use, которая обеспечивает использование компилятором информации, собранной на предыдущем шаге. Таким образом, компилятор имеет возможность использовать не только статические оценки важных характеристик программы, но и данные, полученные во время реального прогона программы. Это может помочь при последующем выборе тех или иных оптимизаций (например, более эффективное расположение в памяти различных веток программы, основываясь на информации о том, какие ветки выполнялись с какой частотой; или применение оптимизации к циклу на основе информации о типичном количестве итераций в нем). Оптимизация по профилированию особенно полезна в тех случаях, когда удается подобрать небольшой, но репрезентативный набор данных (для шага №2), который хорошо иллюстрирует наиболее типичные случаи будущего использования программы. В некоторых предметных областях выбор такого репрезентативного набора вполне возможен. Например, оптимизация по профилированию используется разработчиками СУБД.

    Оптимизации, перечисленные выше относятся к общему (generic) типу, т.е. сгенерированный код будет работать на всех различных процессорах семейства (скажем, в случае 32-х разрядной архитектуры - на всех нижеперечисленных процессорах: Intel Pentium-III, Pentium 4, включая ядро Prescott, Intel Pentium M). Существуют также оптимизации под конкретный процессор.

    Оптимизации, ориентированные на конкретный процессор : -QxK (Pentium-III; использование команд набора SSE, особенностей микроархитектуры), -QxW и -QxN (Pentium 4; использование команд SSE и SSE2, особенностей микроархитектуры), -QxB (Pentium M; использование команд SSE и SSE2, особенностей микроархитектуры), QxP (Prescott; использование команд SSE, SSE2, и SSE3, особенностей микроархитектуры). В данном случае код, сгенерированный с использованием таких опций, может не работать на других представителях процессорной линейки (например, -QxW код может привести к исполнению недопустимой команды, если выполняется на системе на базе процессора Intel Pentium-III). Или работать не с максимальной эффективностью (например, -QxB код на процессоре Pentium 4 в силу отличий в микроархитектуре). При таких опциях возможно также использование библиотек времени исполнения, оптимизированных под конкретный процессор с использованием его системы команд. Для контроля того, что код выполняется действительно на целевом процессоре, реализован механизм диспетчеризации (cpu-dispatch): проверка процессора во время исполнения программы. В различных ситуациях этот механизм может быть либо задействован, либо нет. Диспетчеризация используется всегда, если применяется вариация опций -Qax{KWNP}. В этом случае генерируется две версии кода: оптимизированная под конкретный процессор и "общая" (generic), выбор происходит во время выполнения программы. Таким образом, за счет увеличения размера кода можно добиться выполнения программы на всех процессорах линейки и оптимального выполнения на целевом процессоре. Другой вариант состоит в использовании оптимизации кода под предыдущего представителя линейки и использование этого кода на этом и последующих процессорах. Например, -QxN код может выполняться на Pentium 4 как с ядром Northwood, так и Prescott. Увеличения размера кода не происходит. При таком подходе можно получить хорошую, но все же не оптимальную производительность на системе с процессором Prescott (т.к. не используется SSE3 и не учитываются различия в микроархитектуре) при оптимальной производительности на Northwood. Для процессоров архитектуры IA-64 также существуют подобные опции. На данный момент их две: -G1 (Itanium) и -G2 (Itanium 2; опция по умолчанию).

    Приведенный ниже график (рисунок 5) показывает ускорение (за начало отсчета принята единица - отсутствие какого-либо ускорения) от использования некоторых перечисленных выше оптимизаций (а именно -O3 -Qipo -Qprof_use -Qx{N,P}) на процессоре Prescott по сравнению с установками по умолчанию (-О2). Использование -QxP помогает в некоторых случаях получить ускорение по сравнению с -QxN. Наибольшее ускорение достигается в приложении 168.wupwise, уже упоминавшемся в предыдущей секции (за счет интенсивной оптимизации комплексной арифметики с использованием команд SSE3).


    Рисунок 5


    На рисунке 6 ниже показано соотношение (в разах) скорости работы кода с оптимальными настройками по сравнению с вовсе неоптимизированным кодом (-Od) на процессорах Pentium 4 и Itanium 2. Видно, что Itanium 2 гораздо сильнее зависит от качества оптимизации. Особенно ярко это выражено для вычислений с плавающей точкой (FP), где отношение составляет примерно 36 раз. Вычисления с плавающей точкой являются сильной стороной архитектуры IA-64, но при этом надо тщательно подходить к использованию максимально эффективных настроек компилятора. Полученный выигрыш в производительности окупает трудозатраты на их поиск.


    Рисунок 6. Ускорение при применении лучших опций оптимизации SPEC CPU200


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

    График на рисунке 7 показывает ускорение от использования явного распараллеливания на инженерном (pre-production) образце системы на базе процессора Intel Pentium 4 (Prescott) с поддержкой технологии Hyper-Threading: 2.8GHz, 2GB RAM, 8K L1-Cache, 512K L2-Cache. В качестве набора тестов используется SPEC OMPM2001. Этот набор ориентируется на малые и средние SMP системы, расход памяти составляет до двух гигабайт. Приложения скомпилированы с помощью Intel 8.0 C/C++ и Fortran c двумя наборами опций: -Qopenmp -Qipo -O3 -QxN и -Qopenmp -Qipo -O3 -QxP, с каждым из которых приложения запускались с включенной и выключенной технологией Hyper-Threading. Значения ускорений на графике нормализованы на производительность однопотоковой версии при выключенной технологии Hyper-Threading.


    Рисунок 7: Приложения из набора SPEC OMPM2001 на процессоре Prescott


    Видно, что в 9-ти из 11-ти случаев использование явного распараллеливания с помощью OpenMP дает прирост производительности при включении технологии Hyper-Threading. В одном из приложений (312.swim) наблюдается замедление. Это известный факт: данное приложение характеризуется высокой степенью зависимости от пропускной способности памяти. Так же, как и в случае со SPEC CPU2000, приложение wupwise значительно выигрывает от применения оптимизаций под Prescott (-QxP).


    1.2 Оптимизация программ с внесением изменений в исходный текст и использованием диагностики компилятора


    В предыдущих секциях мы рассматривали влияние компилятора (и его настроек) на скорость выполнения программного кода. В то же время компиляторы Intel представляют более широкие возможности для оптимизации кода, чем просто изменения настроек. В частности, компиляторы дают возможность программисту делать "подсказки" (hints) в коде программы, которые позволяют осуществлять генерацию более эффективного кода с точки зрения производительности. Ниже - некоторые примеры для языка С/C++ (для языка Fortran существуют аналогичные средства, отличающиеся лишь синтаксисом).

    #pragma ivdep (где ivdep означает ignore vector dependencies) применяется перед программными циклами, чтобы сообщить компилятору, что внутри нет зависимостей по данным. Эта подсказка работает в том случае, когда компилятор (на основе анализа) консервативно предполагает, что такие зависимости могут быть (если компилятор в результате анализа может доказать, что зависимость существует, то "подсказка" не оказывает никакого действия), тогда как автор кода знает, что таких зависимостей не может возникнуть. С помощью этой подсказки компилятор может сгенерировать более эффективный код: автоматическая векторизация для IA-32 (использование векторных команд из наборов MMX\SSE\SSE2\SSE3 для программных циклов на С/C++ и Fortran; более подробно познакомится с этой техникой можно, например, в следующей статье в Intel Technology Journal ), программная конвейеризация (SWP) для IA-64.

    #pragma vector always применяется, чтобы компилятор изменил решение о неэффективности векторизации цикла (как автоматической для IA-32, так и SWP для IA-64), сделанное на основе анализа количественных и качественных характеристик работы на каждой итерации.

    #pragma novector оказывает действие, обратное #pragma vector always.

    #pragma vector aligned используется, чтобы сообщить компилятору, что данные, используемые в цикле, выровнены на границу в 16 байт. Это позволяет генерировать более эффективный и/или компактный (из-за отсутствия проверок во время исполнения) код.

    #pragma vector unaligned оказывает действие, обратное #pragma aligned. О выигрыше в производительности в этом случае говорить сложно, но можно рассчитывать на более компактный код.

    #pragma distribute point используется внутри программного цикла, для того, чтобы компилятор мог разбить цикл (loop distribution) в этой точке на несколько более мелких. Например, подобная "подсказка" может быть использована в том случае, когда компилятору не удается сделать автоматическую векторизацию исходного цикла (например, из-за зависимости по данным, которую нельзя игнорировать даже при наличии #pragma ivdep), тогда как каждый (или часть) из вновь образованных циклов может быть эффективно векторизован.

    #pragma loop count (N), применяется для того, чтобы сообщить компилятору, что наиболее вероятное значение количества итераций цикла будет равно N. Эта информация помогает принять решение о наиболее эффективной оптимизации для этого цикла (например, нужно ли делать развертку, нужно ли делать SWP или автоматическую векторизацию, нужно ли использовать команды программной предвыборки данных, ...)

    "Подсказка" _assume_aligned(p, base) применяется для того, чтобы сообщить компилятору, что область памяти, ассоциирующаяся с указателем p, выровнена на границу в base = 2^n байт.

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

    Во-первых, можно использовать диагностику компилятора в виде отчетов, которые он предоставляет программисту. Например, при использовании опции -Qvec_reportN (где N изменяется от 0 до 3 и означает уровень детализации) можно получить отчет об автоматической векторизации. Программисту будет доступна информация о том, какие циклы были векторизованы, а какие - нет. В отрицательном случае компилятор указывает в отчете причины, по которым векторизация не удалась. Предположим, что причиной явилась консервативно предполагаемая зависимость по данным. В таком случае, если программист уверен, что зависимости возникнуть не может, то возможно применение #pragma ivdep. Аналогичные (сравнивая с Qvec_reportN для IA-32) возможности компилятор представляет на IA-64 для контроля наличия и эффективности SWP. В целом, компиляторы Intel представляют широкие возможности для диагностики оптимизаций.

    Во-вторых, другие программные продукты (такие, например, как профилировщик Intel VTune) могут использоваться для поиска "узких мест" в коде с точки зрения производительности. Результаты анализа могут помочь программисту сделать необходимые изменения.

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


    Рисунок 8


    Выше на рисунке 8 показан пошаговый процесс оптимизации приложения с помощью компилятора (и других программных продуктов) Intel на языке Fortran для архитектуры IA-64. В качестве примера рассматривается неадиабатическая региональная схема прогноза на 48 часов Росгидрометцентра (можно прочитать о ней, например, в этой статье . В статье говорится о времени расчета порядка 25 минут, но со времени ее написания произошли значительные изменения. В качестве точки отсчета взята производительность кода на системе Cray-YMP. Неизмененный код с опциями компилятора по умолчанию (-O2) показал прирост производительности в 20% на четырехпроцессорной системе на базе процессора Intel Itanium 2 900 MHz. Применение более агрессивной оптимизации (-О3) привело к ускорению в ~2.5 раза без изменения кода в основном за счет SWP и предвыборки данных. Анализ с помощью диагностики компилятора и профилировщика Intel VTune выявил некоторые "узкие места". Например, компилятор не сделал программную конвейеризацию нескольких важных для производительности циклов, сообщив в отчете, что предполагает зависимость по данным. Небольшие изменения кода (директива ivdep) помогли добиться эффективной конвейеризации. С помощью профилировщика VTune удалось обнаружить (а отчет компилятора это подтвердил), что компилятор не сделал изменения порядка вложенных циклов (loop interchange) для более эффективного использования кэш-памяти. Причиной опять явились консервативные предположения о зависимости по данным. Изменения были сделаны в исходном тексте программы. В итоге удалось добиться 4-кратного ускорения по отношению к начальной версии. Использование явного распараллеливания с помощью директив стандарта OpenMP, а затем переход на систему с процессорами более высокой частоты позволили сократить время счета до показателя менее 8 минут, что дало более чем 16-кратное ускорение по сравнению с начальной версией.

    Intel Visual Fortran

    В Intel Visual Fortran 8.0 используются front-end (часть компилятора, отвечающая за преобразование программы из текста на языке программирования во внутреннее представление компилятора, которое во многом не зависит ни от языка программирования, ни от целевой машины) технологии компилятора CVF и компоненты интеловского компилятора, отвечающие за набор оптимизаций и генерацию кода.


    Рисунок 9




    Рисунок 10


    На рисунках 9 и 10 даны графики сравнения производительности Intel Visual Fortran 8.0 с предыдущей версией Intel Fortran 7.1 и с другими популярными в отрасли компиляторами с этого языка, работающими под управлением ОС семейств Windows и Linux. Для сравнения использовались тесты, исходные тексты которых, удовлетворяющие стандартам F77 и F90, доступны на сайте http://www.polyhedron.com/ . На этом же сайте доступна более детальная информация о сравнении производительности компиляторов (Win32 Compiler Comparisons -> Fortran {77, 90} Execution Time Benchmarks и Linux Compiler Comparisons -> Fortran {77, 90} Execution Time Benchmarks): показано больше различных компиляторов, а геометрическое среднее дано в сочетании с индивидуальными результатами каждого теста.

    Примеры реальных взломов: Intel C++ 7.0 Compiler — Архив WASM.RU

    …компилятор Intel C++ 7.0 докачался глубокой ночью, часу где-то в пятом утра. Спать хотелось неимоверно, но и любопытство: была ли усилена защита или нет, тоже раздирало. Решив, что до тех пор пока не разберусь с защитой я все равно не усну, я, открыв новую консоль, и переустановив системные переменные TEMP и TMP на каталог C:\TEMP, наскоро набил неприлично длинное имя инсталлятора W_CC_P_7.0.073.exe в командной строке (необходимость в установке переменных TEMP и TMP объясняется тем, что в Windows 2000 они по умолчанию указывают на очень глубоко вложенный каталог, а инсталлятор Intel C++ - да и не только он - не поддерживает путей такого огромного размера).

    Сразу же выяснилось, что политика защиты была кардинально пересмотрена и теперь наличие лицензии проверялось уже на стадии установки программы (в версии 5.x установка осуществлялось без проблем). ОК, даем команду dir и смотрим на содержимое того, с чем нам сейчас предстоит воевать:

      Содержимое папки C:\TMP\IntelC++Compiler70

      17.03.2003 05:10

      html

      17.03.2003 05:11

      x86

      17.03.2003 05:11

      Itanium

      17.03.2003 05:11

      notes

      05.06.2002 10:35 45 056 AutoRun.exe

      10.07.2001 12:56 27 autorun.inf

      29.10.2002 11:25 2 831 ccompindex.htm

      24.10.2002 08:12 126 976 ChkLic.dll

      18.10.2002 22:37 552 960 chklic.exe

      17.10.2002 16:29 28 663 CLicense.rtf

      17.10.2002 16:35 386 credist.txt

      16.10.2002 17:02 34 136 Crelnotes.htm

      19.03.2002 14:28 4 635 PLSuite.htm

      21.02.2002 12:39 2 478 register.htm

      02.10.2002 14:51 40 960 Setup.exe

      02.10.2002 10:40 151 Setup.ini

      10.07.2001 12:56 184 setup.mwg

      19 файлов 2 519 238 байт

      6 папок 886 571 008 байт свободно

    Ага! Программа установки setup.exe занимает всего сорок с хвостиком килобайт. Очень хорошо! В такой объем серьезную защиту навряд ли спрячешь, а если даже так - этот крохотный файл ничего не стоит проанализировать целиком - до последнего байта дизассемблерного листинга. Впрочем, не факт, что защитный код расположен именно в setup.exe, он может находится и в другой месте, вот например… ChkLic.dll/ChkLic.exe, занимающими в совокупности немногим менее семисот килобайт. Постой, какой такой ChkLic? Это сокращение от Check License что ли?! Гм, у ребят из Intel очевидно серьезные проблемы с чувством юмора. Уж лучше бы они назвали этот файл "Hack Me" честное слово! Ладно, судя по объему, ChkLic это тот самый FLEX lm и есть, а с ним мы уже сталкивались (см. "Intel C++ 5.0 Compiler") и приблизительно представляем как его ломать.

    Даем команду "dumpbin /EXPORTS ChkLic.dll" для исследования экспортируемых функций и… крепко держимся за Клаву, чтобы не упасть со стула:

      Dump of file ChkLic.dll

    1. Section contains the following exports for ChkLic.dll

      0 characteristics

      3DB438B4 time date stamp Mon Oct 21 21:26:12 2002

    2. 1 number of functions

      1 number of names

      ordinal hint RVA name

      1 0 000010A0 _CheckValidLicense

    Черт побери! Защита экспортирует всего одну-единственную функцию с замечательным именем CheckValidLicense. "Замечательным" - потому, что назначение функции становится понятным ее названия и появляется возможность избежать кропотливого анализа дизассемблерного кода. Ну вот, отбили весь интерес… уж лучше бы они ее по ординалу экспортировали что ли, или, по крайней мере, окрестили ее каким ни будь отпугивающим именем типа DES Decrypt.

    …размечтались! Ладно, вернемся к нашим баранам. Давайте рассуждать логически: если весь защитный код сосредоточен непосредственно в ChkLic.dll (а, судя по "навесному" характеру защиты, это действительно так), то вся "защита" сводится к вызову CheckValidLicense из Setup.exe и проверке возращенного ею результата. Поэтому для "взлома" достаточно лишь пропадчить ChkLic.dll, заставляя функцию ChekValidLicense всегда возвращать… да, кстати, что она должна возвращать? Точнее: какое именно возвращаемое значение соответствует успешной проверки лицензии? Нет, не торопитесь дизассемблировать setup.exe для определения, ведь возможных вариантов не так уже и много: либо FALSE, либо TRUE. Вы делаете ставку на TRUE? Что ж, в каком-то смысле это логично, но с другой стороны: а почему мы, собственно, решили, что функция CheckValidLicense возвращает именно флаг успешности операции, а не код ошибки? Ведь должна же она как-то мотивировать причины отказа устанавливать компилятор: файл с лицензией не найден, файл поврежден, лицензия просрочена и так далее? Хорошо, попробуем возвратить ноль, а если это не прокатит, возвратим единицу.

    ОК, пристегивайтесь, поехали! Запускаем HIEW, открываем файл ChkLic.dll (если же он не открывается - трижды помянув сусликов, временно скопируем его в корневую или любую другую директорию, не содержащую в своем имени спецсимволов, которые так не нравятся hiew"у). Затем, обратившись еще раз к таблице экспорта, полученной с помощью dumpbin, определяем адрес функции CheckValidLicense (в данном случае 010A0h) и через, "10A0" переходим в ее начало. Теперь, - режем по "живому", перезаписывая поверх старого кода "XOR EAX, EAX/RETN 4". Почему именно "REN 4", а не просто "RET"? Да потому, что функция поддерживает соглашение stdcall, о чем можно узнать взглянув в HIEW"e на ее эпилог (просто пролистывайте экран дизассемблера вниз до тех пор, пока не встретите RET).

    Проверяем… Это работает!!! Несмотря на отсутствие лицензии, инсталлятор, не задавая лишних вопросов, начинает установку! Стало быть, защита пала. Ой, не верится нам, что все так просто и, чтобы не сидеть, тупо уставившись в монитор в ожидании завершения процесса инсталляции программы, мы натравливаем на setup.exe свой любимый дизассемблер IDA. Первое, что бросается в глаза, отсутствие CheckValidLicense в списке импортируемых функций. Может быть, она файл ChkLic.exe как-то запускает? Пробуем найти соответствующую ссылку среди автоматически распознанных строк: "~View аNames", "ChkLic"… ага, строки "Chklic.exe" здесь вообще нет, но зато обнаруживается "Chklic.dll". Ага, понятно, значит, библиотека ChkLic загружается явной компоновкой через LoadLibrary. И переход по перекрестной ссылке подтверждает это:

      Text:0040175D push offset aChklic_dll ; lpLibFileName

      Text:00401762 call ds:LoadLibraryA

      Text:00401762 ; загружаем ChkLic.dll ^^^^^^^^^^^^^^^^^

      Text:00401762 ;

      Text:00401768 mov esi, eax

      Text:0040176A push offset a_checkvalidlic ; lpProcName

      Text:0040176F push esi ; hModule

      Text:00401770 call ds:GetProcAddress

      Text:00401770 ; получаем адрес функции CheckValidLicense

      Text:00401770 ;

      Text:00401776 cmp esi, ebx

      Text:00401778 jz loc_40192E

      Text:00401778 ; если такой библиотеки нет, то выходим из программы установки

      Text:00401778 ;

      Text:0040177E cmp eax, ebx

      Text:00401780 jz loc_40192E

      Text:00401780 ; если такой функции в библиотеке нет, то выходим из установки

      Text:00401780 ;

      Text:00401786 push ebx

      Text:00401787 call eax

      Text:00401787 ; вызываем функцию ChekValidLicense

      Text:00401787 ;

      Text:00401789 test eax, eax

      Text:0040178B jnz loc_4019A3

    Text:0040178 ; если функция возвратила не ноль, то выходим из программы установки

    Невероятно, но эта до ужаса примитивная защита построена именно так! Причем, полуметровый файл ChkLic.exe вообще не нужен! И чего ради стоило тащить его из Интернета? Кстати, если вы надумаете сохранять дистрибьютив компилятора (внимание: я не говорил "распространять"!), то для экономии дискового места ChkLic.* можно стереть: либо пропадчив setup.exe, навсегда отучив его к ним обращаться, либо же просто создав свою собственную ChkLic.dll, экспортирующую stdcall функцию CheckValidLicence вида: int CheckValidLicence(int some_flag) { return 0;}

    Так-с, пока мы все это обсуждали, инсталлятор закончил установку компилятора и благополучно завершил свою работу. Интересно ли запустится ли компилятор или все самое интересное только начинается? Лихорадочно спускаемся вниз по разветвленной иерархии вложенных папок, находим icl.exe, который как и следовало ожидать, находится в каталоге bin, нажимаем и… Компилятор естественно не запускается, ссылаясь на то, что "icl: error: could not checkout FLEX lm license", без которой он не может продолжить свою работу.

    Выходит, что Intel применила многоуровневую защиту и первый уровень оказался грубой защитой от дураков. Что ж! Мы принимаем этот вызов и, опираясь на свой предыдущий опыт, машинально ищем файл LMGR*.DLL в каталоге компилятора. Бесполезно! На этот раз такого файла здесь не оказывается, зато выясняется, что icl.exe сильно прибавил в весе, перевалив за отметку шестиста килобайт… Стоп! А не прилинковали ли разработчики компилятора этот самый FLEX lm статической компоновкой? Смотрим: в Intel C++ 5.0 сумма размеров lmgr327.dll и icl.exe составляла 598 Кб, а сейчас одни лишь icl.exe занимает 684 Кб. С учетом поправки на естественное старческое "ожирение", цифры очень хорошо сходятся. Значит, все-таки FLEX lm! Ой-ой! А ведь теперь, - без символических имен функций, ломать защиту будет намного труднее… Впрочем, не будем раньше времени паниковать! Давайте думать, только спокойно! Навряд ли команда разработчиков полностью переписала весь код, взаимодействующей с этой "конвертной" защитой. Скорее всего, ее "усовершенствование" одной лишь сменой типа компоновки и закончилось. А раз так, то шансы взломать программу по прежнему велики!

    Памятуя о том, что в прошлый раз защитный код находится в функции main, мы, определив ее адрес, просто устанавливаем точку останова и, дождавшись всплытия отладчика, тупо трассируем код, попеременно поглядывая то на отладчик, то на окно вывода программы: не появилась ли там ругательное сообщение? При этом, все встретившиеся нам условные переходы, мы отмечаем на отдельном листке бумаги (или откладываем в своей собственной памяти, если вы так хотите), не забыв указать выполнялся ли каждый условный переход или нет… Стоп! Что-то заболтались мы с вами, а ведь ругательное сообщение уже выскочило! ОК, хорошо! Посмотрим, какой условный переход ему соответствовал. Наши записи показывают, что последним встретившимся переходом, был условный переход JNZ, расположенный по адресу 0401075h и "реагирующий" на результат, возращенной процедурой sub_404C0E:

  • Text:0040107F loc_40107F: ; CODE XREF: _main+75^j

    Text:0040107F mov eax, offset aFfrps ; "FFrps"

    Text:00401084 mov edx, 21h

    Text:00401089 call sub_404C0E

    Text:0040108E test eax, eax

    Text:00401090 jnz short loc_40109A

    Очевидно, что sub_404C0E и есть та самая защитная процедура, которая осуществляет проверку лицензии на ее наличие. Как ее обхитрить? Ну, тут много вариантов… Во-первых, можно, вдумчиво и скрупулезно проанализировать содержимое sub_404C0E на предмет выяснения: что именно и как именно она проверяет. Во-вторых, можно просто заменить JNZ short loc_40107F на JZ short loc_40107F или даже NOP, NOP. В-третьих, команду проверки результата возврата TEST EAX, EAX можно превратить в команду установки нуля: XOR EAX, EAX. В-четвертых, можно пропадчить саму sub_404C0E, чтобы она всегда возвращала ноль. Не знаю, как вы, но мне больше всех приглянулся способ номер три. Меняем два байта и запускаем компилятор. Если никаких других проверок его "лицензионности" в защите нет, то программа заработает и, соответственно, наоборот. (Как мы помним, в пятой версии таких проверок было две). Поразительно, но компилятор больше не ругается и работает!!! Действительно, как и следовало ожидать, его разработчики ничуть не усилили защиту, а, напротив, даже ослабили ее! Крис Касперски

    • Сергей Савенков

      какой то “куцый” обзор… как будто спешили куда то