Вывод здесь:
Насколько лучше на самом деле компиляторы Фортрана?
в том, что gfortran и gcc так же быстры для простого кода. Поэтому я хотел попробовать что-то более сложное. Я взял пример спектральной нормы. Сначала я рассчитываю 2D матрицу A (:, :), а затем вычисляю норму. (Это решение не допускается в перестрелке, я думаю.) Я реализовал Fortran и C-версию. Вот код:
https://github.com/certik/spectral_norm
Самые быстрые версии gfortran - spectral_norm2.f90 и spectral_norm6.f90 (одна использует встроенные в Fortran matmul и dot_product, другая реализует эти две функции в коде - без разницы в скорости). Самый быстрый код C / C ++, который мне удалось написать, это spectral_norm7.cpp. Начиная с версии git 457d9d9 на моем ноутбуке:
$ time ./spectral_norm6 5500
1.274224153
real 0m2.675s
user 0m2.520s
sys 0m0.132s
$ time ./spectral_norm7 5500
1.274224153
real 0m2.871s
user 0m2.724s
sys 0m0.124s
Так что версия Gfortran немного быстрее. Это почему? Если вы отправите запрос извлечения с более быстрой реализацией C (или просто вставите код), я обновлю репозиторий.
В Фортране я передаю 2D-массив, в то время как в CI я использую 1D-массив. Не стесняйтесь использовать 2D-массив или любым другим способом, который вы считаете нужным.
Что касается компиляторов, давайте сравним gcc против gfortran, icc против ifort и так далее. (В отличие от страницы перестрелки, которая сравнивает ifort с gcc.)
Обновление : используя версию 179dae2, которая улучшает matmul3 () в моей версии C, они теперь так же быстры:
$ time ./spectral_norm6 5500
1.274224153
real 0m2.669s
user 0m2.500s
sys 0m0.144s
$ time ./spectral_norm7 5500
1.274224153
real 0m2.665s
user 0m2.472s
sys 0m0.168s
Векторизованная версия Педро ниже:
$ time ./spectral_norm8 5500
1.274224153
real 0m2.523s
user 0m2.336s
sys 0m0.156s
И, наконец, как сообщает laxxy ниже для компиляторов Intel, здесь нет большой разницы, и даже самый простой код на Фортране (spectral_norm1) является одним из самых быстрых.
Ответы:
Прежде всего, спасибо за размещение этого вопроса / задачи! Как заявление об отказе от ответственности, я - нативный программист на Си с некоторым опытом работы на Фортране, и чувствую себя как дома в Си, поэтому я сосредоточусь только на улучшении версии Си. Я приглашаю всех хаков Фортрана, чтобы они тоже пошли!
Просто чтобы напомнить новичкам о том, что это такое: основная предпосылка в этом потоке заключалась в том, что gcc / fortran и icc / ifort должны, поскольку они имеют одинаковые серверные части соответственно, генерировать эквивалентный код для одной и той же (семантически идентичной) программы, независимо от того, это быть в C или Fortran. Качество результата зависит только от качества соответствующих реализаций.
Я немного поиграл с кодом и на своем компьютере (ThinkPad 201x, Intel Core i5 M560, 2,67 ГГц), используя
gcc
4.6.1 и следующие флаги компилятора:Я также пошел дальше и написал SIM-векторизованную версию C ++ на C-языке
spectral_norm_vec.c
:Все три версии были скомпилированы с одинаковыми флагами и одинаковой
gcc
версией. Обратите внимание, что я обернул вызов основной функции в цикле с 0..9, чтобы получить более точные значения времени.Таким образом, с «лучшими» флагами компилятора версия C ++ превосходит версию Fortran, а векторизованные циклы с ручным кодированием обеспечивают лишь незначительное улучшение. Беглый взгляд на ассемблер для версии C ++ показывает, что основные циклы также были векторизованы, хотя и развернуты более агрессивно.
Я также взглянул на ассемблер, сгенерированный
gfortran
и вот большой сюрприз: нет векторизации. Я связываю тот факт, что это только незначительно медленнее с проблемой ограничения пропускной способности, по крайней мере, в моей архитектуре. Для каждого умножения матрицы пройдено 230 МБ данных, что в значительной степени перекрывает все уровни кэша. Если вы используете меньшее входное значение, например100
, различия в производительности значительно возрастут.В качестве дополнительного примечания, вместо того, чтобы зацикливаться на флагах векторизации, выравнивания и компилятора, наиболее очевидной оптимизацией будет вычисление первых нескольких итераций в арифметике с одинарной точностью, пока мы не получим ~ 8 цифр результата. Инструкции одинарной точности не только быстрее, но и объем памяти, который необходимо перемещать, также уменьшается вдвое.
источник
gcc
/gfortran
вы используете? В предыдущих темах разные версии давали существенно разные результаты.matmul2
в версии на Фортране это семантически эквивалентноmatmul3
моей версии на Си. Две версии на самом деле теперь одинаковы и, следовательно,gcc
/gfortran
должны давать одинаковые результаты для обоих, например, ни один интерфейс / язык не лучше, чем другой в этом случае.gcc
просто имеет то преимущество, что мы можем использовать векторизованные инструкции, если захотим.vector_size
атрибут для того, чтобы сделать код независимым от платформы, то есть, используя этот синтаксис,gcc
должен иметь возможность генерировать векторизованный код для других платформ, например, с использованием AltiVec в архитектуре IBM Power.Ответ user389 был удален, но позвольте мне заявить, что я твердо нахожусь в его лагере: я не вижу того, что мы узнаем, сравнивая микропроцессоры на разных языках. Меня не удивляет, что C и Fortran показывают примерно одинаковую производительность в этом тесте, учитывая, насколько он короткий. Но эталонный тест также скучен, поскольку его легко можно записать на обоих языках в пару десятков строк. С точки зрения программного обеспечения это не типичный случай: мы должны заботиться о программном обеспечении, содержащем 10000 или 100000 строк кода, и о том, как это делают компиляторы. Конечно, в этом масштабе быстро обнаружатся другие вещи: этот язык A требует 10 000 строк, а язык B требует 50 000. Или наоборот, в зависимости от того, что вы хотите сделать. И вдруг это
Другими словами, для меня не имеет большого значения, что, возможно, мое приложение могло бы быть на 50% быстрее, если бы я разработал его в Fortran 77, если бы вместо этого мне потребовалось всего 1 месяц, чтобы заставить его работать правильно, в то время как это заняло бы 3 месяца. в F77. Проблема с этим вопросом заключается в том, что он фокусируется на аспекте (отдельных ядрах), который, на мой взгляд, не имеет отношения к практике.
источник
Оказывается, я могу писать код на Python (используя numpy для выполнения операций BLAS) быстрее, чем код на Fortran, скомпилированный с помощью моего системного компилятора gfortran.
foo1.py:
и sn6a.f90, очень слегка измененный spectral_norm6.f90:
источник
Проверял это с компиляторами Intel. С 11.1 (-быстрым, подразумевающим -O3) и с 12.0 (-O2) самыми быстрыми являются 1,2,6,7 и 8 (т. Е. «Простейшие» коды Фортрана и C, а также C с векторным векторизацией) - они неотличимы друг от друга на ~ 1,5 с. Тесты 3 и 5 (с массивом как функцией) медленнее; # 4 Я не мог скомпилировать.
Примечательно, что при компиляции с 12.0 и -O3, а не с -O2, первые 2 («простейших») кода на Фортране замедляются на LOT (1,5 -> 10,2 с) - это не первый раз, когда я вижу что-то подобное это, но это может быть самым драматичным примером. Если это все еще относится к текущей версии, я думаю, что было бы неплохо сообщить об этом в Intel, поскольку в их довольно простом случае явно что-то идет не так с их оптимизацией.
В противном случае я согласен с Джонатаном, что это не особенно информативное упражнение :)
источник