Почему -march = native используется так редко?

С большинством компиляторов C/C++ имеется флаг, -march=native для компилятора, -march=native, который сообщает компилятору настроить сгенерированный код для -march=native и расширений ISA центрального процессора. Даже если это не одно имя, обычно существует эквивалентная опция для компиляторов на основе LLVM, таких как rustc или swiftc.

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

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

  • Я не могу думать о какой-либо среде IDE, которая позволяет это по умолчанию.

  • Я не могу придумать какую-либо общую систему сборки, с которой я работал (cmake, automake, cargo, spm и т.д.), Что позволяет использовать ее по умолчанию даже для оптимизированных сборок.

Я могу придумать несколько причин для этого, но ни один из них не является действительно удовлетворительным:

  • Использование -march=native не подходит для двоичных файлов, которые будут распространены на другие машины. Тем не менее, я считаю, что компиляция источников для своей собственной машины гораздо чаще, чем для других, и это не объясняет ее отсутствие использования в отладочных сборках, где нет намерения для распространения.

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

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

Ответ 1

консерватор

Если вы более подробно рассмотрите настройки gcc, старейшего компилятора в своем списке, вы поймете, что они очень консервативны:

  • По умолчанию на x86 активируется только SSE 2; даже SSE 4.
  • Набор флагов в -Wall и -Wextra не менялся годами; есть новые полезные предупреждения, они НЕ добавляются в -Wall или -Wextra.

Зачем? Потому что это сломает вещи!

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

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

Примечание: rustc будет по умолчанию статической привязкой, и может похвастаться тем, что вы можете просто скопировать двоичный файл и отбросить его на другой компьютер; очевидно, -march=native будет препятствием.

Массы дружелюбные

И, по правде говоря, это, вероятно, не имеет значения. Вы сами это узнали:

По моему собственному опыту, этот флаг может обеспечить массовые ускорения для численно-интенсивного кода

Большинство кодов заполнены виртуальными вызовами и ветвями (как правило, OO-кодом) и вовсе не численно-интенсивными. Таким образом, для большинства кодов часто бывает достаточно SSE 2.

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

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

Заключение

Не активировать -march=native по умолчанию облегчает -march=native пользователей; так как даже искатели производительности могут не заботиться об этом, это означает, что больше потерять, чем получить.


В альтернативной истории, когда по умолчанию было -march=native с самого начала; пользователи будут использоваться для указания целевой архитектуры, и мы не будем обсуждать эту тему.

Ответ 2

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

Еще одна важная вещь, которую следует учитывать, заключается в том, что -march=native main end use - оптимизация. Флаг оптимизации по умолчанию - -O0 (без оптимизации), поэтому с этой точки зрения не имеет смысла либо включить его по умолчанию.

Ответ 3

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

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

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