System Image Building

Building the Julia system image

Julia поставляется с предварительно обработанным системным образом, содержащим содержимое модуля Base, названным sys.ji. Этот файл также предварительно скомпилирован в общую библиотеку, называемую sys.{so,dll,dylib}, на как можно большем количестве платформ, чтобы обеспечить значительно улучшенное время запуска. На системах, которые не поставляются с предварительно скомпилированным файлом системного образа, его можно сгенерировать из исходных файлов, поставляемых в папке DATAROOTDIR/julia/base Julia.

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

Эта операция полезна по нескольким причинам. Пользователь может:

  • Создайте предварительно скомпилированное изображение системной библиотеки на платформе, которая не поставлялась с ним, тем самым улучшив время запуска.
  • Измените Base, перестройте образ системы и используйте новый Base в следующий раз, когда будет запущен Julia.
  • Включите файл userimg.jl, который включает пакеты в системный образ, тем самым создавая системный образ с встроенными пакетами в среду запуска.

PackageCompiler.jl package содержит удобные обертки функций для автоматизации этого процесса.

System image optimized for multiple microarchitectures

Системный образ может быть скомпилирован одновременно для нескольких микроархитектур ЦПУ под одной и той же архитектурой набора инструкций (ISA). Могут быть созданы несколько версий одной и той же функции с минимальной точкой диспетчеризации, вставленной в общие функции, чтобы воспользоваться различными расширениями ISA или другими особенностями микроархитектуры. Версия, которая предлагает наилучшие характеристики производительности, будет автоматически выбрана во время выполнения на основе доступных функций ЦПУ.

Specifying multiple system image targets

Многоархитектурное изображение системы может быть включено, если передать несколько целей во время компиляции изображения системы. Это можно сделать либо с помощью опции сборки JULIA_CPU_TARGET, либо с помощью командной строки -C, когда вы вручную запускаете команду компиляции. Несколько целей разделяются ; в строке опции. Синтаксис для каждой цели — это имя ЦП, за которым следуют несколько функций, разделенных ,. Все функции, поддерживаемые LLVM, поддерживаются, и функцию можно отключить с помощью префикса -. (Префикс + также разрешен и игнорируется для согласованности с синтаксисом LLVM). Кроме того, поддерживается несколько специальных функций для управления поведением клонирования функций.

Note

Хорошей практикой является указание либо clone_all, либо base(<n>) для каждой цели, кроме первой. Это делает явным, какие цели имеют все функции клонированными, а какие цели основаны на других целях. Если этого не сделать, поведение по умолчанию заключается в том, чтобы не клонировать каждую функцию и использовать определение функции первой цели в качестве резервного варианта, когда функция не клонируется.

  1. clone_all

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

  2. base(<n>)

    Где <n> является заполнителем для неотрицательного числа (например, base(0), base(1)). По умолчанию частично клонированная (т.е. не clone_all) цель будет использовать функции из целевой по умолчанию (первой указанной), если функция не клонирована. Это поведение можно изменить, указав другую базу с помощью параметра base(<n>). Цель с номером n (индексация с нуля) будет использоваться в качестве базовой цели вместо целевой по умолчанию (0-й). Базовая цель должна быть либо 0, либо другой целью clone_all. Указание не clone_all цели в качестве базовой цели приведет к ошибке.

  3. opt_size

    Это приводит к оптимизации функции для целевого размера, когда нет значительного влияния на производительность во время выполнения. Это соответствует опции -Os в GCC и Clang.

  4. min_size

    Это приводит к тому, что функция для цели оптимизируется по размеру, что может значительно повлиять на производительность во время выполнения. Это соответствует опции Clang -Oz.

В качестве примера, на момент написания этой статьи, следующая строка используется для создания официальных бинарных файлов x86_64 Julia, доступных для загрузки с julialang.org:

generic;sandybridge,-xsaveopt,clone_all;haswell,-rdrnd,base(1)

Это создает системный образ с тремя отдельными целями; одна для общего процессора x86_64, одна с ISA sandybridge (явно исключая xsaveopt), которая явно клонирует все функции, и одна, нацеленная на ISA haswell, основанная на версии sysimg sandybridge, также исключающая rdrnd. Когда реализация Julia загружает сгенерированный sysimg, она проверяет процессор хоста на наличие соответствующих флагов возможностей ЦП, включая самый высокий уровень ISA, возможный для использования. Обратите внимание, что базовый уровень (generic) требует инструкции cx16, которая отключена в некоторых виртуализационных программах и должна быть включена, чтобы целевой generic мог быть загружен. В качестве альтернативы, sysimg может быть сгенерирован с целью generic,-cx16 для большей совместимости, однако обратите внимание, что это может вызвать проблемы с производительностью и стабильностью в некотором коде.

Implementation overview

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

  1. Компиляция образа системы

    Решения о парсинге и клонировании принимаются в src/processor*. В настоящее время мы поддерживаем клонирование функций на основе наличия циклов, инструкций simd или других математических операций (например, fastmath, fma, muladd). Эта информация передается в src/llvm-multiversioning.cpp, который выполняет фактическое клонирование. В дополнение к клонированию и вставке слотов диспетчера (см. комментарии в MultiVersioning::runOnModule о том, как это делается), проход также генерирует метаданные, чтобы время выполнения могло правильно загрузить и инициализировать системный образ. Подробное описание метаданных доступно в src/processor.h.

  2. Загрузка системного образа

    Загрузка и инициализация системного образа выполняется в src/processor* путем анализа метаданных, сохраненных во время генерации системного образа. Обнаружение функций хоста и принятие решений о выборе выполняются в src/processor_*.cpp в зависимости от ISA. Выбор цели будет предпочитать точное совпадение имени ЦП, больший размер векторного регистра и большее количество функций. Обзор этого процесса находится в src/processor.cpp.