Сборка образа системы
Сборка образа системы Julia
В состав Julia входит предварительно проанализированный образ системы с содержимым модуля Base
с именем sys.ji
. Этот файл также предварительно скомпилирован в общую библиотеку sys.{so,dll,dylib}
для максимально возможного количества платформ, чтобы значительно улучшить время запуска. В системах, которые не поставляются с предварительно скомпилированным файлом образа системы, этот файл может быть сгенерирован из файлов исходного кода, находящихся в папке DATAROOTDIR/julia/base
Julia.
Эта операция полезна по нескольким причинам. Пользователь может выполнить следующие задачи.
-
Собрать предварительно скомпилированный образ системы общих библиотек на платформе, которая не поставляется с таким образом, тем самым улучшая время запуска.
-
Изменить модуль
Base
, повторно собрать образ системы и использовать новый модульBase
при следующем запуске Julia. -
Включить файл
userimg.jl
, который содержит пакеты, в образ системы, тем самым создавая образ системы, в котором пакеты внедрены в среду запуска.
Пакет PackageCompiler.jl
содержит удобные функции-оболочки для автоматизации этого процесса.
Образ системы, оптимизированный для нескольких микроархитектур
Образ системы может быть скомпилирован одновременно для нескольких микроархитектур ЦП в одной и той же архитектуре набора инструкций (ISA). Можно создать несколько версий одной и той же функции с минимальной точкой диспетчеризации, вставленной в общие функции, чтобы использовать преимущества различных расширений ISA или других возможностей микроархитектуры. Версия, обеспечивающая наилучшую производительность, будет выбрана автоматически во время выполнения на основе доступных характеристик ЦП.
Указание нескольких целевых объектов образа системы
Образ системы с несколькими микроархитектурами может быть включен путем передачи нескольких целевых объектов время компиляции образа системы. Это можно сделать либо с помощью параметра создания JULIA_CPU_TARGET
, либо с помощью параметра -C
командной строки при выполнении команды компиляции вручную. Несколько целевых объектов разделяются в строке параметров символом ;
. Синтаксис для каждого целевого объекта представляет собой имя ЦП, за которым следует несколько функций, разделенных символом ,
. Поддерживаются все функции, поддерживаемые LLVM. Функцию можно отключить с помощью префикса -
. (Префикс +
также разрешен и игнорируется для согласования с синтаксисом LLVM.) Кроме того, поддерживается несколько специальных функций для управления поведением клонирования функций.
Рекомендуется указывать либо |
-
clone_all
По умолчанию будут клонироваться только те функции, которые с наибольшей вероятностью смогут повысить свою эффективность благодаря возможностям микроархитектуры. Однако, если для целевого объекта указана функция
clone_all
, все функции образа системы будут клонированы для целевого объекта. Отрицательная форма функции-clone_all
может быть использована для запрета клонирования всех функций встроенной эвристикой. -
base(<n>)
<n>
— это местозаполнитель для неотрицательного числа (например,base(0)
,base(1)
). По умолчанию частично клонированный (т. е. безclone_all
) целевой объект будет использовать функции из целевого объекта по умолчанию (первого указанного), если функция не клонирована. Это поведение можно изменить, указав другую основу с помощью параметраbase(<n>)
.n
-й целевой объект (на основе 0) будет использоваться в качестве базового целевого объекта вместо стандартного (0
-го). Базовый целевой объект должен быть либо0
, либо другим целевым объектомclone_all
. Указание целевого объекта, отличного отclone_all
, в качестве базового приведет к ошибке. -
opt_size
В результате функция для целевого объекта будет оптимизирована по размеру, что не оказывает значительного влияния на производительность во время выполнения. Это соответствует параметру
-Os
GCC и Clang. -
min_size
В результате функция для целевого объекта будет оптимизирована по размеру, что может оказать значительное влияние на производительность во время выполнения. Это соответствует параметру
-Oz
Clang.
Например, на момент написания этого документа при создании официальных двоичных файлов x86_64
Julia, скачиваемых с сайта julialang.org, используется следующая строка.
generic;sandybridge,-xsaveopt,clone_all;haswell,-rdrnd,base(1)
При этом создается образ системы с тремя отдельными целевыми объектами: один для универсального процессора x86_64
, один с sandybridge
ISA (явно исключая xsaveopt
), который явным образом клонирует все функции, и один, предназначенный для haswell
ISA, основанный на версии sysimg sandybridge
и также исключающий rdrnd
. Когда реализация Julia загружает сгенерированный sysimg, она проверяет ведущий процессор на наличие соответствующих флагов возможностей ЦП, позволяющих использовать самый высокий уровень ISA. Обратите внимание, что для базового уровня (generic
) требуется инструкция cx16
, которая отключена в некоторых программах виртуализации и должна быть включена для загрузки целевого объекта generic
. В качестве альтернативы можно сгенерировать sysimg с целевым объектом generic,-cx16
для большей совместимости. Однако следует учесть, что это может привести к проблемам с производительностью и стабильностью в некоторых кодах.
Обзор реализации
Это краткий обзор различных частей, задействованных в процессе реализации. Подробности реализации приведены в комментариях к коду каждого компонента.
-
Компиляция образа системы
Анализ и клонирование выполняются в
src/processor*
. В настоящее время поддерживается клонирование функции на основе наличия циклов, инструкций simd или других математических операций (например, fastmath, fma, muladd). Эта информация передается в файлsrc/llvm-multiversioning.cpp
, который выполняет фактическое клонирование. Помимо клонирования и вставки слотов диспетчеризации (о том, как это делается, см. в комментариях вMultiVersioning::runOnModule
), передача также генерирует метаданные, чтобы среда выполнения могла правильно загрузить и инициализировать образ системы. Подробное описание метаданных доступно в файлеsrc/processor.h
. -
Загрузка образа системы
Загрузка и инициализация образа системы выполняется в
src/processor*
путем анализа метаданных, сохраненных при генерации образа системы. Определение основных функций и их выбор осуществляются в файлеsrc/processor_*.cpp
в зависимости от ISA. При выборе целевого объекта рекомендуется придерживаться точного соответствия имени ЦП, а также выбрать большой размер векторного регистра и большее количество функций. Обзор этого процесса приведен в файлеsrc/processor.cpp
.