Spec-Zone.ru › Haskell 9

5.3. Оптимизация (улучшение кода)

Параметры -O* задают удобные «пакеты» флагов оптимизации; параметры -f* (описанные позже) задают отдельные оптимизации, которые следует включить/выключить; параметры -m* задают специфичные для машины оптимизации, которые следует включить/выключить.

Большинство этих параметров являются булевыми и имеют параметры для включения и выключения (начинаются с префикса no-). Например, в то время как -fspecialise включает специализацию, -fno-specialise её отключает. Когда несколько флагов для одного и того же параметра появляются в командной строке, они оцениваются слева направо. Например, -fno-specialise -fspecialise включит специализацию.

Важно отметить, что флаги -O* примерно эквивалентны комбинациям флагов -f*. По этой причине эффект флагов -O* и -f* зависит от порядка их появления в командной строке.

Например, рассмотрим пример -fno-specialise -O1. Несмотря на то, что -fno-specialise появляется в командной строке, специализация по-прежнему будет включена. Это так, потому что -O1 подразумевает -fspecialise, переопределяя предыдущий флаг. В противоположность этому, -O1 -fno-specialise будет компилироваться без специализации, как и ожидалось.

5.3.1. -O*: удобные «пакеты» флагов оптимизации.

Существует множество параметров, влияющих на качество кода, генерируемого GHC. У большинства людей есть только общая цель, например, «Компилировать быстро» или «Заставить мою программу работать как по маслу». Следующие «пакеты» оптимизаций (или их отсутствие) должны быть достаточными.

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

Если параметр типа ``-O*`` не указан: это означает «Пожалуйста, скомпилируйте быстро; я не слишком беспокоюсь о качестве скомпилированного кода». Например, ghc -c Foo.hs

-O0

Означает «выключить все оптимизации», возвращаясь к тем же настройкам, что и без указания параметров -O. Указание -O0 может быть полезно, если, например, make уже вставил -O в командную строку.

-O
-O1

Означает: «Сгенерировать код хорошего качества, не тратя слишком много времени». Например: ghc -c -O Main.lhs

-O2

Означает: «Применить все безопасные оптимизации, даже если это займет значительно больше времени на компиляцию».

Избегаемые «опасные» оптимизации — это те, которые могут ухудшить время выполнения или занимаемое пространство, если вам не повезёт. Обычно они включаются или выключаются индивидуально.

-O⟨n⟩

Любой -On, где n > 2, эквивалентен -O2.

Мы не используем флаг -O* для повседневной работы. Мы используем -O для получения приемлемой скорости; например, когда мы хотим что-то измерить. Когда мы хотим пойти ва-банк, мы, как правило, используем -O2 (и делаем много кофе-пауз).

Самый простой способ понять, что -O (и т. д.) «на самом деле означают», — это запустить -v и откинуться назад, поражёнными.

5.3.2. -f*: независимые от платформы флаги

Эти флаги включают и отключают отдельные оптимизации. Флаги, помеченные как включенные по умолчанию, включены на всех уровнях оптимизации по умолчанию, и поэтому вам, вероятно, не нужно явно их устанавливать. Флаг -fwombat может быть отрицаем, сказав -fno-wombat.

-fcore-constant-folding
Значение по умолчанию:

выключено, но включено -O.

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

-fcase-merge
Значение по умолчанию:

выключено, но включено -O.

Объединить вложенные выражения case, которые проверяют одну и ту же переменную. Например,

case x of
   Red -> e1
   _   -> case x of
            Blue -> e2
            Green -> e3

Преобразуется в,

case x of
   Red -> e1
   Blue -> e2
   Green -> e2
-fcase-folding
Значение по умолчанию:

выключено, но включено -O.

Разрешить свёртку констант в выражениях case, которые проверяют некоторые primops: Например,

case x `minusWord#` 10## of
   10## -> e1
   20## -> e2
   v    -> e3

Преобразуется в,

case x of
   20## -> e1
   30## -> e2
   _    -> let v = x `minusWord#` 10## in e3
-fcall-arity
Значение по умолчанию:

выключено, но включено -O.

Включить анализ арности вызова.

-fexitification
Значение по умолчанию:

выключено, но включено -O.

Включает перемещение выходов из рекурсивных функций.

-fcmm-elim-common-blocks
Значение по умолчанию:

выключено, но включено -O.

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

-fcmm-sink
Значение по умолчанию:

выключено, но включено -O.

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

-fcmm-static-pred
Значение по умолчанию:

выключено, но включено -O.

Это включает статическое прогнозирование потока управления в коде Cmm. Если включено, GHC применит определённые эвристики для идентификации циклов и горячих путей кода. Эта информация затем используется для распределения регистров и размещения кода.

-fcmm-control-flow
Значение по умолчанию:

выключено, но включено -O.

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

-fasm-shortcutting
Значение по умолчанию:

выключено, но включено -O2.

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

Это в основном делается во время проходов Cmm. Однако это может пропустить частные случаи. Поэтому при -O2 этот флаг снова запускает проход на стадии сборки, чтобы поймать эти случаи. Обратите внимание, что из-за ограничений платформы (#21972) этот флаг ничего не делает на macOS.

-fblock-layout-cfg
Значение по умолчанию:

выключено, но включено -O.

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

Ожидается, что это улучшит производительность в среднем, но реальная разница в производительности может варьироваться.

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

-fblock-layout-weights

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

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

-fblock-layout-weightless
Значение по умолчанию:

выключено

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

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

Когда этот флаг включён, а -fblock-layout-cfg выключен, размещение блоков ведёт себя так же, как в 8.6 и более ранних версиях.

-fcpr-anal
Значение по умолчанию:

выключено, но включено -O.

Включить анализ CPR, который включает преобразование worker/wrapper (см. -fworker-wrapper) для разворачивания результата функции, например

sum :: [Int] -> Int
sum []     = 0
sum (x:xs) = x + sum xs

Анализ CPR увидит, что каждый путь кода производит составной продукт, такой как I# 0# в первой ветви (где GHC.Exts.I# — конструктор данных Int, упаковывающий примитивный целочисленный литерал 0# типа Int#) и оптимизирует до

sum xs = I# ($wsum xs)
$wsum []        = 0#
$wsum (I# x:xs) = x# +# $wsum xs

и затем sum может встроенно потенциально отменить ящик I#.

Вот пример функции, которая не возвращает составной продукт:

f :: [Int] -> (Int -> Int) -> Int
f []     g = g 0
f (x:xs) g = x + f xs g

Выражение g 0 не является составным продуктом, потому что мы ничего не знаем о g.

Анализ CPR также работает вложенно, например

sumIO :: [Int] -> IO Int
sumIO []     = return 0
sumIO (x:xs) = do
  r <- sumIO xs
  return $! x + r

Обратите внимание на использование $!: без него GHC не смог бы увидеть, что вычисление r и x завершается (и быстро). Альтернативой было бы вычисление обоих с шаблоном bang или seq, но конструкция return $! <res> должна работать надёжнее и требует меньше размышлений. Приведённый выше пример будет оптимизирован до

sumIO :: [Int] -> IO Int
sumIO xs = IO $ \s -> case $wsum xs s of
  (# s', r #) -> (# s', I# r #)
$wsumIO :: [Int] -> (# State# RealWorld, Int# #)
$wsumIO []        s = (# s, 0# #)
$wsumIO (I# x:xs) s = case $wsumIO xs of
  (# s', r #) -> (# s', x +# r#)

И последний может встроенно sumIO и отменить конструктор I#. Разворачивание результата действия State должно работать аналогично.

-fcse
Значение по умолчанию:

выключено, но включено -O.

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

-fstg-cse
Значение по умолчанию:

выключено, но включено -O.

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

-fdicts-cheap
По умолчанию:

выключено

Очень экспериментальный флаг, который заставляет оптимизатор считать выражения со словарями «дешёвыми».

-fdicts-strict
По умолчанию:

выключено, но включено флагом -O2.

Сделать словари строгими.

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

Если включение этого флага приводит к регрессии, попробуйте увеличить порог развертывания с помощью -funfolding-use-threshold=⟨n⟩ на небольшое количество (~30), так как это, вероятно, результат известного ограничения, описанного в #18421.

-fdmd-tx-dict-sel
По умолчанию:

включено

Использовать специальный преобразователь запросов для селекторов словарей. Поведение безусловно включено начиная с версии 9.2.

-fdo-eta-reduction
По умолчанию:

включено

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

-fdo-lambda-eta-expansion
По умолчанию:

включено

Эта-расширять let-связывания, чтобы увеличить их арность.

-fdo-clever-arg-eta-expansion
По умолчанию:

выключено

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

-feager-blackholing
По умолчанию:

выключено

Обычно GHC делает тхунки доступными только при переключении потоков. Этот флаг заставляет это делать сразу же после входа в тхунк. См. Haskell on a shared-memory multiprocessor.

См. Параллельные параметры компиляции для SMP для обсуждения его использования.

-fexcess-precision
По умолчанию:

выключено

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

Обратите внимание, что 32-битный x86-генератор кода поддерживает режим сверхточности, поэтому ни -fexcess-precision ни -fno-excess-precision не имеют никакого эффекта. Это известный баг, см. Ошибки в GHC.

-fexpose-all-unfoldings
По умолчанию:

выключено

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

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

  • -fspecialise-aggressively для принудительного максимального уровня специализации.
  • {-# SPECIALIZE #-} директивы для обеспечения специализации к определённым типам.
  • Использование волшебной функции inline для принудительного встраивания.
-fexpose-overloaded-unfoldings
По умолчанию:

выключено

Этот экспериментальный флаг — немного менее тяжеловесная альтернатива -fexpose-all-unfoldings.

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

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

newtype NT a = NT (Integral a => a)

foo :: NT a -> T1 -> TR

GHC не будет распознавать foo как специализируемый и не будет отображать развертывание даже при включенном -fexpose-overloaded-unfoldings.

Все другие замечания о -fexpose-overloaded-unfoldings всё ещё актуальны, поэтому см. там дополнительные подробности.

-ffloat-in
По умолчанию:

выключено, но включено флагом -O.

Перемещение let-связываний с плавающей точкой внутрь, ближе к месту их связывания. См. Let-floating: moving bindings to give faster programs (ICFP’96).

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

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

-ffull-laziness
По умолчанию:

выключено, но включено флагом -O.

Выполнить полную оптимизацию ленивости (также известную как let-перемещение), которая перемещает let-связывания за пределы окружающих лямбда-выражений, в надежде, что они будут вычисляться реже. См. Let-floating: moving bindings to give faster programs (ICFP’96). Полная ленивость увеличивает совместное использование, что может привести к увеличению постоянного присутствия в памяти.

Примечание

GHC не реализует полную ленивость. Хотя оптимизация полной ленивости GHC позволяет выполнять некоторые преобразования, которые выполнялись бы при полной ленивости (например, извлечение повторяющихся вычислений из циклов), эти преобразования не применяются последовательно, поэтому не полагайтесь на них.

-ffun-to-thunk
По умолчанию:

выключено

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

Этот флаг был неэффективен в присутствии -ffull-laziness, который вытащит тхунк из константной рабочей функции, даже если -ffun-to-thunk был выключен.

Поэтому использование этого флага устарело с GHC 9.4.1, и мы рекомендуем вместо этого использовать -fno-full-laziness. Это подразумевает, что работник/обёртка не сможет превратить функцию в тхунк при наличии -fno-full-laziness. Если это неудобно для вас, пожалуйста, оставьте комментарий на странице отслеживания проблем (#21204).

-fignore-asserts
По умолчанию:

выключено, но включено флагом -O.

Заставляет GHC игнорировать использование функции Exception.assert в исходном коде (другими словами, переписывая Exception.assert p e в e (см. Утверждения).

-fignore-interface-pragmas
Значение по умолчанию:

Подразумевается флагом -O0, в противном случае выключен.

Указывает GHC игнорировать всю неважную информацию при чтении файлов интерфейса. То есть, даже если M.hi содержит информацию о развертывании или строгости для функции, GHC проигнорирует эту информацию.

-fkeep-auto-rules
Значение по умолчанию:

выключено

С версии:

9.10.1

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

Вы можете изменить это поведение с помощью -fkeep-auto-rules. Включив его, вы сохраняете все сгенерированные правила.

-flate-dmd-anal
Значение по умолчанию:

выключено

Повторный запуск анализа спроса в конце упрощающего конвейера. Были обнаружены возможности определения строгости, которые ранее не были видны; и оптимизации, такие как -fspec-constr, могут создавать функции с неиспользуемыми аргументами, которые устраняются поздним анализом спроса. Улучшения скромные, как и затраты. См. заметки на странице вики.

-fliberate-case
Значение по умолчанию:

выключено, но включено флагом -O2.

Включение преобразования liberate-case. Это разворачивает рекурсивную функцию один раз в своём правом члене, чтобы избежать повторного анализа случаев свободных переменных. Это немного похоже на специализацию по шаблонам вызова (-fspec-constr), но для свободных переменных, а не аргументов.

-fliberate-case-threshold=⟨n⟩
Значение по умолчанию:

2000

Установите пороговое значение размера для преобразования liberate-case.

-floopification
Значение по умолчанию:

выключено, но включено флагом -O.

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

-fllvm-pass-vectors-in-regs
Значение по умолчанию:

включено

Этот флаг не имеет эффекта с GHC 8.8 – его поведение всегда включено. Раньше он указывал GHC использовать системные векторные регистры для передачи векторных аргументов при вызовах функций.

-fmax-inline-alloc-size=⟨n⟩
Значение по умолчанию:

128

Установите максимальный размер встраиваемых массивов выделения до n байт. GHC выделит не закреплённые массивы с известным размером в текущем блоке выделения, если они не больше n байт, игнорируя переполнение. Это значение должно быть значительно меньше размера блока (обычно: 4096).

-fmax-inline-memcpy-insns=⟨n⟩
Значение по умолчанию:

32

Встраивание вызовов memcpy если они сгенерируют не более ⟨n⟩ псевдоинструкций.

-fmax-inline-memset-insns=⟨n⟩
Значение по умолчанию:

32

Встраивание вызовов memset если они сгенерируют не более n псевдоинструкций.

-fmax-relevant-binds=⟨n⟩
Значение по умолчанию:

6

Проверка типов иногда отображает фрагмент окружения типов в сообщения об ошибках, но только до определённого максимального количества, установленного этим флагом. Выключив его с помощью -fno-max-relevant-binds , вы получите неограниченное количество. Синтаксические верхнеуровневые связи обычно также исключаются (поскольку их может быть много), но -fno-max-relevant-binds включает их тоже.

-fmax-uncovered-patterns=⟨n⟩
Значение по умолчанию:

4

Максимальное число несовпадающих шаблонов, которые будут показаны в предупреждениях, сгенерированных с помощью -Wincomplete-patterns и -Wincomplete-uni-patterns.

-fmax-simplifier-iterations=⟨n⟩
Значение по умолчанию:

4

Устанавливает максимальное количество итераций упростителя.

-flocal-float-out
Значение по умолчанию:

включено

Включение локального перемещения связей из правой части let(rec) в упростителе. Например

let x = let y = rhs_y in rhs_x in blah
==>
let y = rhs_y in let x = rhs_x in blah

См. статью «Let-floating: moving bindings to give faster programs», Partain, Santos и Peyton Jones; ICFP 1996. https://www.microsoft.com/en-us/research/publication/let-floating-moving-bindings-to-give-faster-programs/

Примечание

Это отличается от глобального перемещения, которое можно отключить с помощью -fno-full-laziness.

-flocal-float-out-top-level
Значение по умолчанию:

включено

Включение локального перемещения верхнеуровневых связей из правой части let(rec) в упростителе. Например

x = let y = e in (a,b) ===> y = e; x = (a,b)

См. статью «Let-floating: moving bindings to give faster programs», Partain, Santos и Peyton Jones; ICFP 1996. https://www.microsoft.com/en-us/research/publication/let-floating-moving-bindings-to-give-faster-programs/

Обратите внимание, что если установлен -fno-local-float-out, он будет иметь приоритет.

Примечание

Это отличается от глобального перемещения, которое можно отключить с помощью -fno-full-laziness.

-fmax-worker-args=⟨n⟩
Значение по умолчанию:

10

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

-fmax-forced-spec-args=⟨n⟩
Значение по умолчанию:

512

При использовании SPEC от GHC.Types для принудительного запуска SpecConstr на функции, иногда это может привести к тому, что функции будут принимать нелепо большое количество аргументов, что приведёт к очень большим затратам времени компиляции для незначительных преимуществ производительности.

Поскольку это, как правило, непреднамеренно, мы предотвращаем запуск SpecConstr и генерируем предупреждение, если количество аргументов в результирующей функции превысит значение, заданное -fmax-forced-spec-args.

-fno-opt-coercion
Значение по умолчанию:

оптимизация приведения включена.

Отключение оптимизатора приведения.

-fno-pre-inlining
Значение по умолчанию:

встраивание предварительно включено

Отключение предварительного встраивания.

-fno-state-hack
Значение по умолчанию:

включен режим «state hack»

Отключает «state hack», в котором любая лямбда с маркером State# в качестве аргумента считается однократной, поэтому допустимо встраивать в неё вещи. Это может повысить производительность кода монады IO и ST, но существует риск снижения совместного использования.

-fomit-interface-pragmas
Значение по умолчанию:

Включается по умолчанию флагом -O0, иначе выключено.

Указывает GHC опустить всю ненужную информацию из файла интерфейса, сгенерированного для компилируемого модуля (например, M). Это означает, что модуль, импортирующий M, увидит только типы функций, которые экспортирует M, но не их развертывания, информацию о строгости и т. д. Следовательно, например, ни одна функция, экспортируемая M, не будет внедрена в импортирующий модуль. Преимущество заключается в том, что модулям, импортирующим M, потребуется рекомпилировать их реже (только при изменении типа экспорта M, а не при изменении реализации).

-fomit-yields
Значение по умолчанию:

включено (yield не вставляются)

Указывает GHC опустить проверки кучи, когда не производится выделение памяти. Хотя это улучшает размер бинарных файлов примерно на 5%, это также означает, что потоки, выполняющие узкие циклы без выделения памяти, не будут своевременно прерываться. Если важно всегда иметь возможность прерывать такие потоки, следует отключить эту оптимизацию. Также следует перекомпилировать все библиотеки с этой оптимизацией отключенной, если необходимо гарантировать прерывание.

-fobject-determinism
Значение по умолчанию:

детерминизм объектов отключен

Указывает GHC создать полностью детерминированный объектный код. Для создания детерминированных объектов требуется дополнительный этап переименования перед конвейером Cmm, который переименовывает все уникальные элементы детерминированно. Это может немного замедлить скорость компиляции, но гарантирует детерминированные объекты.

-fpedantic-bottoms
Значение по умолчанию:

выключено

Делает GHC более точным в отношении обработки значений bottom (но см. также -fno-state-hack). В частности, останавливает GHC от eta-распространения через выражение case, что хорошо для производительности, но плохо, если вы используете seq для частичных применений.

-fregs-graph
Значение по умолчанию:

выключено из-за проблемы с регрессией производительности (#7679)

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

-fregs-iterative
Значение по умолчанию:

выключено

Применяется только в сочетании с генератором кода нативном языке. Использует итеративный алгоритм слияния для раскраски графа для распределения регистров в генераторе кода нативном языке. Этот алгоритм такой же, как и -fregs-graph, но также включает итеративное слияние при распределении регистров.

-fsimplifier-phases=⟨n⟩
Значение по умолчанию:

2

Устанавливает количество фаз для упростителя. Игнорируется с -O0.

-fsimpl-tick-factor=⟨n⟩
Значение по умолчанию:

100

Оптимизатор GHC может расходиться, если вы пишете правила переписывания (Правила переписывания), которые не завершаются, или (менее удовлетворительно) если вы реализуете рекурсию через типы данных (Ошибки в GHC). Чтобы избежать зацикливания компилятора, оптимизатор использует «счётчик тиков» и прекращает встраивание и применение правил переписывания, когда этот счётчик превышен. Предел задаётся как кратное размеру программы, поэтому более крупные программы получают больше тиков. Флаг -fsimpl-tick-factor позволяет изменить множитель. Значение по умолчанию равно 100; числа больше 100 дают больше тиков, а числа меньше 100 — меньше.

Если счётчик тиков истекает, GHC суммирует выполненные им шаги упрощения; вы можете использовать -fddump-simpl-stats для получения гораздо более подробного списка. Обычно это довольно точно определяет цикл, так как некоторые числа очень большие.

-fdmd-unbox-width=⟨n⟩
Значение по умолчанию:

3

Анализ boxity оптимистично предполагает, что функция, возвращающая запись с не более чем -fdmd-unbox-width полями, имеет только места вызова, которым не требуется коробка возвращаемой записи. Это, в свою очередь, может позволить большему количеству аргументов быть разложенными из коробки. Установите значение 0, чтобы быть полностью консервативным (что гарантирует, что переупаковка не произойдёт из-за этого механизма).

-fspec-constr
Значение по умолчанию:

выключено, но включено флагом -O2.

Включает специализацию шаблонов вызовов; см. Специализация шаблонов вызовов для программ Haskell.

Эта оптимизация специализирует рекурсивные функции в соответствии с «форматами» их аргументов. Лучше всего это объяснить на примере, поэтому рассмотрим:

last :: [a] -> a
last [] = error "last"
last (x : []) = x
last (x : xs) = last xs

В этом коде, после начальной проверки на пустой список, мы знаем, что в рекурсивном случае эта проверка шаблона избыточна. Поэтому -fspec-constr преобразует приведенный выше код в:

last :: [a] -> a
last []       = error "last"
last (x : xs) = last' x xs
    where
      last' x []       = x
      last' x (y : ys) = last' y ys

Помимо избежания ненужных проверок шаблонов, это также помогает избежать ненужных выделений. Это применимо, когда аргумент является строгим в рекурсивном вызове к самому себе, но не при начальном вызове. Создаётся строгая рекурсивная ветвь функции, подобная приведенному выше примеру.

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

import GHC.Types (SPEC(..))

foldl :: (a -> b -> a) -> a -> Stream b -> a
{-# INLINE foldl #-}
foldl f z (Stream step s _) = foldl_loop SPEC z s
  where
    foldl_loop !sPEC z s = case step s of
                            Yield x s' -> foldl_loop sPEC (f z x) s'
                            Skip       -> foldl_loop sPEC z s'
                            Done       -> z

Здесь, после встраивания GHC тела foldl в место вызова, он выполнит очень агрессивную специализацию шаблона вызова foldl_loop из-за использования SPEC в аргументе тела цикла. SPEC из GHC.Types распознаётся компилятором.

(Примечание: крайне важно использовать seq или шаблон bang для аргумента SPEC!)

В частности, после встраивания это позволит напрямую передать f в тело цикла, что позволит выполнять сильную специализацию рекурсивных случаев.

-fspec-constr-keen
Значение по умолчанию:

выключено

Если этот флаг включён, специализация шаблонов вызовов будет специализировать вызов (f (Just x)) с явным аргументом конструктора, даже если аргумент не проверяется в теле функции. Это иногда выгодно; например, аргумент может быть передан другой функции, которая сама может быть специализирована.

-fspec-constr-count=⟨n⟩
Значение по умолчанию:

3

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

-fspec-constr-threshold=⟨n⟩
Значение по умолчанию:

2000

Устанавливает пороговое значение размера для преобразования SpecConstr.

-fspecialise
Значение по умолчанию:

выключено, но включено флагом -O.

Специализирует каждую функцию с перегрузкой типа класса, определённую в этом модуле, для типов, на которых она вызывается в этом модуле. Если установлен -fcross-module-specialise, также будут специализированы импортированные функции, имеющие прагму INLINABLE (INLINABLE прагма).

-fspecialise-aggressively
По умолчанию:

выключено

Этот флаг управляет специализацией только импортированных функций. По умолчанию импортированная функция специализируется только если она помечена как INLINEABLE или INLINE. Но с -fspecialise-aggressively, импортированная функция специализируется, если её развертывание доступно в файле интерфейса. (Используйте -fexpose-all-unfoldings или -fexpose-overloaded-unfoldings для того, чтобы убедиться, что развертывание включено в файл интерфейса.)

-fspecialise-aggressively не включен в любой уровень оптимизации, так как он может значительно увеличить размер кода.

-fcross-module-specialise
По умолчанию:

выключено, но включено -O.

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

-fpolymorphic-specialisation
По умолчанию:

выключено

Предупреждение, эта функция сильно экспериментальна и может привести к неверным результатам выполнения. Используйте на свой страх и риск (#23469, #23109, #21229, #23445).

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

-flate-specialise
По умолчанию:

выключено

Выполняет дополнительный проход специализации в конце конвейера оптимизации. Это может выявить возможности специализации, возникшие из предыдущего прохода специализации или других встроенных функций.

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

-fspecialise-incoherents
По умолчанию:

включено

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

-finline-generics
По умолчанию:

выключено, но включено -O.

С:

9.2.1

Добавляет анотации INLINE[1] к методам производных экземпляров Generic и Generic1 на основе эвристик, зависящих от размера типа. Улучшает производительность алгоритмов, основанных на генериках, так как GHC может чаще оптимизировать промежуточное представление.

-finline-generics-aggressively
По умолчанию:

выключено

С:

9.2.1

Добавляет анотации INLINE[1] к методам всех производных экземпляров Generic и Generic1.

Этот флаг следует использовать только в модулях, производящих экземпляры Generic, которые не считались подходящими для аннотаций INLINE[1] эвристиками -finline-generics, но вы знаете, что это принесёт пользу.

Если включить его глобально, это, скорее всего, приведёт к ухудшению времени компиляции и увеличению размера кода без прироста производительности во время выполнения.

-fsolve-constant-dicts
По умолчанию:

выключено, но включено -O.

При решении ограничений попытайтесь решать суперклассы с использованием доступных словарей.

Например:

class M a b where m :: a -> b

type C a b = (Num a, M a b)

f :: C Int b => b -> Int -> Int
f _ x = x + 1

Тело f требует экземпляр Num Int. Мы могли бы решить это ограничение из контекста, так как у нас есть C Int b, что предоставляет нам решение для Num Int. Однако, мы часто можем получить гораздо лучший код, напрямую решив для доступного словаря Num Int, который у нас есть под рукой. Это устраняет потенциально множество уровней косвенности и, что крайне важно, позволяет запуститься другим оптимизациям, так как словарь будет статически известен, а функции-селекторы можно будет встроить.

Оптимизация также работает для GADTs, которые связывают словари. Если мы статически знаем, какой словарь класса нам нужен, то мы решим его напрямую, а не косвенно, используя тот, который передаётся во время выполнения.

-fstatic-argument-transformation
По умолчанию:

выключено

Включить статическую трансформацию аргументов, которая превращает рекурсивную функцию в нерекурсивную с локальным рекурсивным циклом. См. главу 7 диссертации Андрея Сантоса Compilation Transformation Non-Strict Functional Languages.

-fstg-lift-lams
По умолчанию:

выключено, но включено -O2.

Включает оптимизацию позднего подъёма лямбда-выражений в промежуточном языке STG. Это выборочно поднимает локальные функции на верхний уровень, преобразуя свободные переменные в параметры функции.

-fstg-lift-lams-known
По умолчанию:

выключено

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

-fstg-lift-lams-non-rec-args
По умолчанию:

5

Создавать верхнеуровневые нерекурсивные функции с не более чем <n> параметрами при выполнении позднего подъёма лямбда-выражений. По умолчанию 5, количество доступных регистров параметров на x86_64.

-fstg-lift-lams-rec-args
По умолчанию:

5

Создавать верхнеуровневые рекурсивные функции с не более чем <n> параметрами при выполнении позднего подъёма лямбда-выражений. По умолчанию 5, количество доступных регистров параметров на x86_64.

-fstrictness
По умолчанию:

выключено, но включено с помощью -O.

Включить анализ спроса.

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

Помимо анализа строгости, анализ спроса также выполняет анализ использования: если строгость означает «вычислено по крайней мере один раз», анализ использования спрашивает, являются ли аргументы и привязки «вычисленными не более одного раза» или вообще не «вычисленными» («вычислены не более нуля раз»), например, «отсутствуют». В первом случае GHC может использовать вызов по имени вместо вызова по потребности, фактически превращая отложенные вычисления в не запоминающие функции. Во втором случае вообще не нужно генерировать код: отсутствующий аргумент можно просто заменить на фиктивное значение в месте вызова или вовсе опустить.

Преобразование «рабочий/обёрточный» (-fworker-wrapper) отвечает за использование возможностей без упаковки и замену отсутствующих аргументов фиктивными значениями. Для аргументов, которые нельзя упаковать без упаковки, возможности вызова по значению и вызова по имени используются в CorePrep при переводе в STG.

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

Нотация

Итак, анализ спроса заключается в консервативном выводе нижних и верхних границ того, сколько раз что-то вычисляется/вызывается. Мы называем часть «сколько раз» мощностью. В компиляторе и отладке мы различаем следующие интервалы мощности как приближения к мощности:

Интервал

Множество обозначаемых мощностей

Синтаксис

Пояснение связи синтаксиса с семантикой

[1,0]

{}

B

Нижний элемент

[0,0]

{0}

A

Отсутствует

[0,1]

{0,1}

M

Используется не более одного раза («Возможно»)

[0,ω]

{0,1,ω}

L

Ленивый. Верхний элемент, нет информации, используется по крайней мере 0, не более много раз

[1,1]

{1}

1

Строго, используется ровно один раз

[1,ω]

{1,ω}

S

Строго, возможно используется много раз

Обратите внимание, что никогда не интересно различать мощность 2 и 3, или даже 4232123. Мы просто приближаем случай >1 с помощью ω, обозначающего «много раз».

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

Это полный синтаксис для мощностей, запросов и подзапросов в BNF:

card ::= B | A | M | L | 1 | S    semantics as in the table above

d    ::= card sd                  card = how often, sd = how deep
      |  card                     abbreviation: Same as "card card"

sd   ::= card                     polymorphic sub-demand, card at every level
      |  P(d,d,..)                product sub-demand
      |  C(card,sd)               call sub-demand

Например, fst строго относится к своему аргументу и также к первому компоненту аргумента. Он не будет оценивать второй компонент аргумента. Это выражается требованием 1P(1L,A). P относится к «подтребованию произведения», имеющему требование для каждого поля произведения. Запись 1L просто говорит «вычислено строго (1), при этом всё вложенное вычисляется в соответствии с L» — например, нет информации, так как это зависело бы от контекста вычисления места вызова fst . Роль L в 1L заключается в качестве полиморфного подтребования, являющегося семантически эквивалентным подтребованию P(LP(..)), которое мы просто сокращаем записью (следовательно, перегруженной) синтаксической нотацией L.

Другой пример, выражение x + 1 вычисляет x в соответствии с требованием 1P(L). Мы видели, что одиночные буквы обозначают мощности и полиморфные подзапросы, но что означает одиночная буква L для требования? Такое одиночное требование просто расширяется до мощности и полиморфного подтребования той же буквы: например, L эквивалентно LL путем расширения одиночного требования, что эквивалентно LP(LP(..)), поэтому L все время вниз. Из контекста всегда понятно, говорим ли мы о мощности, подтребовании или требовании.

Подписи требований

Мы обобщаем свойства требований функции в ее подписи требований. Вот общий синтаксис:

{x->dx,y->dy,z->dz...}<d1><d2><d3>...<dn>div
        ^              ^   ^   ^      ^   ^
        |              |   |   |      |   |
        |              \---+---+------/   |
        |                  |              |
   demand on free        demand on      divergence
     variables           arguments      information
 (omitted if empty)                     (omitted if
                                      no information)

Мы обобщаем fst’s свойства требований в его подписи требований <1P(1L,A)>, которая просто говорит «Если fst применяется к одному аргументу, этот аргумент вычисляется в соответствии с 1P(1L,A)». Для другого примера, подпись требований seq будет <1A><1L>, а + — <1P(L)><1P(L)>.

Если не опущено, информация о расхождении может быть b (безусловно расходится) или x (безусловно расходится или генерирует точное исключение). Например, error имеет подпись требований <S>b и throwIO (который является единственным способом сгенерировать точное исключение) имеет подпись требований <_><L><L>x (без учёта сложного требования к Exception словарю).

Подтребования вызовов

Рассмотрим maybe:

maybe :: b -> (a -> b) -> Maybe a -> b
maybe n _ Nothing  = n
maybe _ s (Just a) = s a

Мы предоставляем подпись требования <L><MC(M,L)><1L>. C(M,L) является подтребованием вызова, которое говорит «Вызывается не более одного раза, где результат используется в соответствии с L». Выражение f `seq` f 1 помещает f под требование SC(1,L) и служит примером, когда верхняя граница мощности вычисления не совпадает с мощностью вызова.

Мощность всегда относительна к мощности окружающего вызова, поэтому g 1 2 + g 3 4 помещает g под требование SC(S,C(1,L)), что означает «вызывается много раз (S), но каждый раз при вызове с одним аргументом он применяется ровно один раз к другому аргументу (1)».

-fstrictness-before=⟨n⟩

Выполнить дополнительный анализ спроса перед фазой упрощения ⟨n⟩.

-funbox-small-strict-fields
По умолчанию:

выключено, но включено с помощью -O.

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

Например, поля конструкторов в следующих типах данных

data A = A !Int
data B = B !A
newtype C = C B
data D = D !C

все будут представлены одним значением Int# (см. Упакованные типы и примитивные операции) с -funbox-small-strict-fields включенным.

Этот параметр менее радикален, чем -funbox-strict-fields: он редко ухудшает ситуацию. Если вы используете -funbox-small-strict-fields для включения без упаковки по умолчанию, вы можете отключить её для определённых полей конструкторов, используя псевдокод NOUNPACK (см. Псевдокод NOUNPACK).

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

-funbox-strict-fields
По умолчанию:

выключено

Этот параметр вызывает распаковку всех полей конструкторов, помеченных как строгие (т.е. !), если это возможно. Это эквивалентно добавлению псевдокода UNPACK к каждому строгому полю конструктора (см. Псевдокод UNPACK).

Этот параметр несколько радикален: иногда он может ухудшить ситуацию. Возможно, лучше выбрать частичную без упаковку полей с использованием псевдокода UNPACK. Альтернативой является использование -funbox-strict-fields для включения без упаковки по умолчанию, но отключить её для определённых полей конструкторов, используя псевдокод NOUNPACK (см. Псевдокод NOUNPACK).

В качестве альтернативы можно использовать -funbox-small-strict-fields для распаковки только строгих полей, которые являются «малыми».

-funfolding-creation-threshold=⟨n⟩
Значение по умолчанию:

750

Определяет максимальный размер, который GHC позволит функции развертывания. (Развертывание имеет «размер», отражающий затраты с точки зрения «раздутия кода» при расширении (т.е. встраивании) этого развертывания в месте вызова. Более большая функция получила бы большую стоимость.)

Последствия:

  1. ничего большего, чем это, не будет встраиваться (если у него нет INLINE pragma)
  2. ничего большего, чем это, не будет выводиться в файл интерфейса.

Увеличение этого значения скорее приведет к более длительному времени компиляции, чем к более быстрому коду. Флаг -funfolding-use-threshold=⟨n⟩ более полезен.

-funfolding-dict-discount=⟨n⟩
Значение по умолчанию:

30

Насколько рьяно компилятор должен встраивать словари?

-funfolding-fun-discount=⟨n⟩
Значение по умолчанию:

60

Насколько рьяно компилятор должен встраивать функции?

-funfolding-keeness-factor=⟨n⟩

Этот фактор устарел в GHC 9.0.1. См. #15304 для подробностей. Пользователи, которым нужно управлять встраиванием, должны рассмотреть -funfolding-use-threshold=⟨n⟩.

-funfolding-use-threshold=⟨n⟩
Значение по умолчанию:

80

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

Различие между этим и -funfolding-creation-threshold=⟨n⟩ заключается в том, что этот вариант определяет, будет ли определение функции встраиваться *в месте вызова*. Другой вариант определяет, будет ли определение функции вообще сохранено для потенциального встраивания.

-funfolding-case-threshold=⟨n⟩
Значение по умолчанию:

2

GHC, как правило, достаточно рьяно встраивает небольшие функции. Однако иногда эти функции будут расширены дополнительным встраиванием после встраивания. Поскольку они теперь применяются к «интересным» аргументам. Хуже того, их расширенная форма может снова ссылаться на небольшую функцию, которая будет встроена и расширена впоследствии. Это может часто повторяться и привести к взрывному росту программ.

Как это произошло в #18730.

Начиная с GHC 9.0, мы будем менее рьяно встраивать глубоко вложенные случаи. Мы достигаем этого, применяя штраф за встраивание, который увеличивается по мере углубления вложения. Однако иногда ожидается определённый (возможно, очень высокий!) порог вложения.

В таких случаях этот флаг можно использовать для игнорирования первых ⟨n⟩ уровней вложения при вычислении штрафа.

Этот флаг в сочетании с -funfolding-case-scaling=⟨n⟩ можно использовать для прерывания циклов встраивания, не отключая встраивание полностью. В этих целях более низкое значение более вероятно прервет такие циклы, хотя часто достаточно и корректировки масштабирования, и предпочтительнее.

-funfolding-case-scaling=⟨n⟩
Значение по умолчанию:

30

GHC, как правило, достаточно рьяно встраивает небольшие функции. Однако иногда эти функции будут расширены дополнительным встраиванием после встраивания. Поскольку они теперь применяются к «интересным» аргументам. Хуже того, их расширенная форма может снова ссылаться на небольшую функцию, которая будет встроена и расширена впоследствии. Это может часто повторяться и привести к взрывному росту программ.

Как это произошло в #18730.

Начиная с GHC 9.0, мы будем менее рьяно встраивать глубоко вложенные случаи. Мы достигаем этого, применяя штраф за встраивание, который увеличивается по мере углубления вложения. Однако иногда мы согласны с большим встраиванием ради производительности.

В таких случаях этот флаг можно использовать для настройки того, насколько сильно мы штрафуем встраивание в глубоко вложенные случаи, превышающие порог, заданный -funfolding-case-threshold=⟨n⟩. Случаи учитываются только в отношении уровня вложенности, если они имеют более одной альтернативы.

Мы используем 1/n для масштабирования штрафа. То есть более высокое значение даёт меньший штраф.

Это можно использовать для прерывания циклов встраивания. Для этой цели рекомендуется более низкое значение. Значения в диапазоне 10 <= n <= 20 позволяют некоторому встраиванию происходить, при этом позволяя GHC компилировать модули, содержащие такие циклы встраивания.

-fworker-wrapper
Значение по умолчанию:

выключено, но включено -O.

Включить преобразование worker/wrapper после прохода анализа спроса.

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

Подразумевается -O, и -fstrictness. Отключено -fno-strictness. Включение -fworker-wrapper при отключённом анализе спроса (с помощью -fno-strictness) не имеет эффекта.

-fworker-wrapper-cbv

Отключение этого флага предотвращает разделение W/W, если единственной выгодой было бы вычисление по значениям для некоторых аргументов.

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

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

Это может привести к незначительному увеличению размера кода. Это также приведёт к тому, что многие больше функций будут разделены на функции-рабочие и функции-обёртки, что может плохо сочетаться с правилами (см. #20364), поэтому он по умолчанию отключён. В частности, если вы полагаетесь на применение правил к функциям, помеченным как NOINLINE, без пометки мест использования этих функций как INLINE или INLINEABLE, то всё сломается, если этот флаг не отключён.

Пока WorkerWrapper отключён, это не оказывает влияния.

-fbinary-blob-threshold=⟨n⟩
Значение по умолчанию:

500000

Генератор кода на родном языке может либо выгрузить двоичные фрагменты (например, строковые литералы) в файл ассемблера (используя директивы ассемблера «.asciz» или «.string»), либо выгрузить их как двоичные данные в временный файл, который затем включается ассемблером (используя директиву ассемблера «.incbin»).

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

-fwrite-if-compression=⟨n⟩
Значение по умолчанию:

2

С:

9.12.1

Этот флаг определяет уровень сжатия файлов интерфейса при записи на диск. Чем выше флаг, тем больше мы дедуплицируем файл интерфейса, за счёт более длительного времени компиляции. Дедупликация (при применении к режиму --make и режиму --interactive) уменьшает размер файлов интерфейса, а также уменьшает общее использование памяти GHC.

Сжатие не может быть полностью выключено, GHC всегда сжимает файлы интерфейса до определённой степени. В настоящее время мы поддерживаем значения 1, 2 и 3. Значения ниже или выше ограничиваются 1 и 3 соответственно.

  • 1: Сжать как можно меньше. Без влияния на время выполнения, за счёт размера файла интерфейса и использования памяти.
  • 2: Применить сжатие с минимальной задержкой во время выполнения, уменьшая размер файла интерфейса и использование памяти.
  • 3: Применить все возможные сжатия, минимальные размеры файлов интерфейса и использование памяти, за счёт задержки во время выполнения.

© 2002–2007 The University Court of the University of Glasgow. All rights reserved.
Licensed under the Glasgow Haskell Compiler License.
https://downloads.haskell.org/~ghc/9.12.1/docs/users_guide/using-optimisation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API