Для создания исполняемого файла система GHC компилирует ваш код, а затем связывает его с нетривиальной системой выполнения (RTS), которая обрабатывает управление памятью, планирование потоков, профилирование и так далее.
RTS имеет множество параметров для управления его поведением. Например, вы можете изменить интервал переключения контекстов, размер кучи по умолчанию и включить профилирование кучи. Эти параметры могут быть переданы системе выполнения различными способами; следующий раздел (Настройка параметров RTS) описывает различные методы, а следующие разделы описывают сами параметры RTS.
5.7.1. Настройка параметров RTS
Существует четыре способа настройки параметров RTS:
- в командной строке между
+RTS ... -RTS, при запуске программы (Настройка параметров RTS в командной строке) - на этапе компиляции, используя
-with-rtsopts=⟨opts⟩(Настройка параметров RTS во время компиляции) - с помощью переменной окружения
GHCRTS(Настройка параметров RTS с помощью переменной окружения GHCRTS) - переопределяя «хуки» в системе выполнения («Хуки» для изменения поведения RTS)
5.7.1.1. Настройка параметров RTS в командной строке
Если вы установите флаг -rtsopts[=⟨none|some|all|ignore|ignoreAll⟩] соответствующим образом при линковке (см. Параметры, влияющие на линковку), вы можете указать параметры RTS в командной строке при запуске вашей программы.
Когда ваша программа Haskell запускается, RTS извлекает аргументы командной строки, заключённые между +RTS и -RTS, как свои собственные. Например:
$ ghc prog.hs -rtsopts [1 of 1] Compiling Main ( prog.hs, prog.o ) Linking prog ... $ ./prog -f +RTS -H32m -S -RTS -h foo bar
RTS заберет -H32m -S для себя, а оставшиеся аргументы -f -h foo bar будут доступны вашей программе, если/когда она вызовет System.Environment.getArgs.
Флаг -RTS не требуется, если параметры системы выполнения простираются до конца командной строки, как в этом примере:
% hls -ltr /usr/etc +RTS -A5m
Если вы абсолютно хотите, чтобы все остальные параметры в командной строке перешли к программе (а не к RTS), используйте --RTS или --. Разница заключается в том, что --RTS не будет передано программе, в то время как -- будет.
Как всегда, для параметров RTS, принимающих ⟨размер⟩: Если последняя буква ⟨размера⟩ - K или k, умножьте на 1024; если M или m, на 1024*1024; если G или G, на 1024^3. (И любая переполняемость счётчиков - ваша вина!)
Указание параметра +RTS -? RTS выведет параметры RTS, фактически доступные в вашей программе (которые различаются в зависимости от того, как вы её скомпилировали).
Примечание
Поскольку сам GHC скомпилирован с помощью GHC, вы можете изменить параметры RTS в компиляторе, используя стандартную комбинацию +RTS ... -RTS. Например, чтобы установить максимальный размер кучи для компиляции в 128М, вы бы добавили +RTS -M128m -RTS в командную строку.
5.7.1.2. Настройка параметров RTS во время компиляции
GHC позволяет изменить параметры RTS по умолчанию для программы на этапе компиляции, используя флаг -with-rtsopts (Параметры, влияющие на линковку). Общее применение этого - предоставить программе значения кучи и/или стека по умолчанию, большие, чем значения по умолчанию. Например, чтобы установить -H128m -K64m, свяжите с -with-rtsopts="-H128m -K64m".
5.7.1.3. Настройка параметров RTS с помощью переменной окружения GHCRTS
-
GHCRTS -
Если флаг
-rtsoptsустановлен на значение, отличное отnoneилиignoreAllпри линковке, параметры RTS также берутся из переменной окруженияGHCRTS. Например, чтобы установить максимальный размер кучи на 2Г для всех программ, скомпилированных GHC (используя оболочку типаsh):GHCRTS='-M2G' export GHCRTS
Параметры RTS, взятые из переменной окружения
GHCRTS, могут быть переопределены параметрами, заданными в командной строке.
Подсказка
Указание чего-либо вроде GHCRTS=-M2G в вашей среде - это удобный способ избежать того, чтобы программы Haskell выходили за пределы реальной памяти вашей машины, что легко сделать случайно и может привести к тому, что машина будет работать очень медленно, пока операционная система не решит убить процесс (и вы надеетесь, что это нужный процесс).
5.7.1.4. «Хуки» для изменения поведения RTS
GHC позволяет осуществлять элементарное управление определёнными настройками RTS для любой программы, компилируя «хук», который вызывается системой выполнения. RTS содержит заглушки для этих хуков, но написав собственную версию и связав её в командной строке GHC, вы можете переопределить значения по умолчанию.
Из-за особенностей связывания DLL эти хуки не работают под Windows, когда программа построена динамически.
5.7.1.4.1. События выполнения
Вы можете изменить сообщения, печатаемые, когда система выполнения «вылетает», например, при переполнении стека. Хуки для них следующие:
-
void OutOfHeapHook(unsigned long, unsigned long) -
Сообщение о переполнении кучи.
-
void StackOverflowHook(long int) -
Сообщение о переполнении стека.
-
void MallocFailHook(long int) -
Сообщение, выводимое, если
mallocзавершится неудачно.
5.7.1.4.2. Вывод журнала событий
Кроме того, GHC позволяет задать способ записи данных журнала событий (см. -l
⟨flags⟩) через пользовательский EventLogWriter:
-
type size_t -
- Скрытый:
-
type EventLogWriter -
Приёмник данных журнала событий.
-
void initEventLogWriter(void) -
Инициализирует ваш
EventLogWriter. Это необязательно.
-
bool writeEventLog(void *eventlog, size_t eventlog_size) -
Передает буферизованные данные журнала событий вашему обработчику журнала событий. Возвращает true при успехе. Требуется для пользовательского
EventLogWriter.Обратите внимание, что эта функция может вызываться несколькими потоками одновременно.
-
void flushEventLog(void) -
Очистка буферов (если таковые имеются) вашего пользовательского
EventLogWriter. Это может бытьNULL.Обратите внимание, что эта функция может вызываться несколькими потоками одновременно.
-
void stopEventLogWriter(void) -
Вызывается, когда запись в журнал событий собирается остановить. Это может быть
NULL.
-
Для использования EventLogWriter API RTS предоставляет следующие функции:
-
EventLogStatus eventLogStatus(void) -
Запрос о том, поддерживает ли текущая система выполнения журнал событий (например, был ли текущий исполняемый файл связан с
-eventlog) и, если он поддерживается, ведётся ли в данный момент его запись.
-
bool startEventLogging(const EventLogWriter *writer) -
Начать запись событий в заданный
EventLogWriter. Возвращает true при успехе или false, если другой обработчик уже настроен.
-
void endEventLogging() -
Закрыть активный
EventLogWriter.
где enum EventLogStatus:
-
type EventLogStatus -
-
EVENTLOG_NOT_SUPPORTED: Система выполнения не была скомпилирована с поддержкой журнала событий. -
EVENTLOG_NOT_CONFIGURED: ОбработчикEventLogWriterещё не настроен. -
EVENTLOG_RUNNING: ОбработчикEventLogWriterнастроен и работает.
-