Spec-Zone.ru › Haskell 9

5.7. Параметры выполнения (RTS)

Для создания исполняемого файла система 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 настроен и работает.

5.7.2. Разные параметры RTS

--install-signal-handlers=⟨yes|no⟩

Если «да» (по умолчанию), RTS устанавливает обработчики сигналов для перехвата таких событий, как Ctrl-C. Этот параметр в основном полезен, когда код Haskell используется как DLL, и вы хотите установить собственные обработчики сигналов.

Обратите внимание, что даже с --install-signal-handlers=no, сигнал таймера RTS всё ещё включён. Сигнал таймера — это либо SIGVTALRM, либо SIGALRM, в зависимости от конфигурации RTS и возможностей ОС. Чтобы отключить сигнал таймера, используйте параметр RTS -V0 (см. -V ⟨secs⟩).

--install-seh-handlers=⟨yes|no⟩

Если «да» (по умолчанию), RTS на Windows устанавливает обработчики исключений для перехвата необработанных исключений с помощью механизма обработки исключений Windows. Этот параметр в основном полезен, когда вы используете код Haskell как DLL и не хотите, чтобы RTS некорректно завершал вашу программу при ошибках, таких как segfaults.

--generate-crash-dumps

Если «да» (по умолчанию), RTS на Windows создаст дамп ядра при любом сбое. Эти дампы можно просматривать с помощью отладчиков, таких как WinDBG. Дампы записывают весь код, регистры и информацию о потоках в момент сбоя. Обратите внимание, что это подразумевает --install-seh-handlers=yes.

--generate-stack-traces=<yes|no>

Если «да» (по умолчанию), RTS на Windows будет генерировать стек-трейс при сбоях, если включена обработка исключений. Для получения дополнительной информации в скомпилированных исполняемых файлах, коде C или DLL должны быть доступны символы.

--disable-delayed-os-memory-return

Если задан, использует MADV_DONTNEED вместо MADV_FREE на платформах, где это приводит к более точному отображению используемой программой физической памяти, как показано в инструментах отслеживания памяти (например, столбец RSS в top и htop).

Использование этого параметра, как ожидается, немного замедлит программу.

В Linux MADV_FREE является более новым и быстрым, потому что может избежать обнуления страниц, если они повторно используются процессом позже (см. man 2 madvise), но в обмен на это инструменты проверки памяти, такие как top, не сразу отобразят освобождение в своём отображении физической памяти (столбец RSS): Только при нехватке памяти Linux фактически удалит освобождённые страницы из процесса и обновит статистику RSS. До этого момента страницы отображаются как LazyFree в /proc/PID/smaps (см. man 5 proc).

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

--io-manager=(name)

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

В настоящее время доступны следующие менеджеры ввода-вывода:

Имя

Платформы

Способ RTS

select

Posix

Непотоковый

mio

Все

Потоковый

win32-legacy

Windows

Непотоковый

winio

Windows

Все

-xp

На 64-битных машинах runtime-линкер обычно должен отобразить объектный код в нижние 2 Гб адресного пространства из-за 32-битной модели маленькой памяти x86_64, где большинство ссылок на символы — 32-битные. Проблема в том, что эти 2 Гб адресного пространства могут заполниться, особенно если вы загружаете большое количество объектных файлов в GHCi.

Этот флаг предлагает обходной путь, хотя и несколько запутанный. Чтобы загрузить объектный файл за пределами нижних 2 Гб, объектный код необходимо скомпилировать с -fPIC -fexternal-dynamic-refs. Когда передаётся флаг +RTS -xp, линкер предположит, что все объектные файлы были скомпилированы с -fPIC -fexternal-dynamic-refs и загрузит их в любом месте адресного пространства. Вам нужно убедиться, что все загружаемые объектные файлы (включая все пакеты) были скомпилированы должным образом. Если это не так для объекта, линкер, скорее всего, выдаст сообщение об ошибке, когда проблема будет обнаружена.

На некоторых платформах, где PIC всегда используется, например, macOS и OpenBSD на x86_64, и macOS и Linux на aarch64, этот флаг включён по умолчанию. Одним из последствий этого является то, что системные библиотеки, на которые есть ссылки, также должны быть скомпилированы с -fPIC , если их нужно загрузить в runtime-линкер.

-xm ⟨address⟩

Предупреждение

Этот параметр предназначен для устранения проблем с выделением памяти. Не используйте, если GHCi завершился с сообщением, подобным «failed to mmap() memory below 2Gb». Попробуйте перекомпилировать объекты с -fPIC -fexternal-dynamic-refs и использовать флаг -xp вместо этого. Если вам необходимо использовать этот параметр, чтобы заставить GHCi работать на вашей машине, пожалуйста, подайте отчёт об ошибке.

На 64-битных машинах RTS необходимо выделять память в нижних 2 Гб адресного пространства. Поддержка этого на разных операционных системах неоднозначна и иногда не работает. Этот параметр предназначен для подсказки RTS о том, где он должен быть способен выделять память в нижних 2 Гб адресного пространства. Например, +RTS -xm20000000 -RTS подскажет RTS начать выделение с отметки 0,5 Гб. По умолчанию используется встроенная поддержка ОС для выделения памяти в нижних 2 Гб, если доступна (например, mmap с MAP_32BIT в Linux), в противном случае -xm40000000.

-xq ⟨size⟩
Значение по умолчанию:

100k

Этот параметр относится к пределам выделения; подробнее см. GHC.Conc.enableAllocationLimit. Когда поток достигает предела выделения, RTS генерирует исключение для потока, и поток получает дополнительный квоту выделения перед повторным возникновением исключения, идея заключается в том, чтобы поток мог выполнить свои обработчики исключений. -xq контролирует размер этого дополнительного квота.

-xr ⟨size⟩
Значение по умолчанию:

1T

Этот параметр контролирует размер виртуального адресного пространства, резервируемого двухуровневым аллокатором на 64-битной платформе. Это может быть полезно в сценариях, где даже резервирование большого диапазона адресов без закрепления может быть дорогостоящим (например, WSL1), или когда у вас достаточно физической памяти и вы хотите поддерживать кучу Haskell, большую, чем 1Т. -xr является бесполезным, если GHC сконфигурирован с --disable-large-address-space или если платформа 32-битная.

5.7.3. Параметры RTS для управления сборщиком мусора

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

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

on

С версии:

8.10.2

Обратное значение:

–nonmoving-gc

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

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

off

С версии:

8.10.1

Обратное значение:

–copying-gc

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

Обратите внимание, что --nonmoving-gc не может использоваться с -G1, profiling или -c.

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

off

С версии:

8.10.1

Псевдоним для --nonmoving-gc

--nonmoving-dense-allocator-count=⟨count⟩
Значение по умолчанию:

16

С версии:

9.10.1

Обратное значение:

none

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

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

Большие значения, вероятно, приведут к убывающей отдаче, поскольку на практике куча Haskell, как правило, доминирует маленькими объектами.

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

off

С версии:

давно

Обратное значение:

none

Использует стратегию сборки мусора помечания-региона для кучи старейшего поколения. Обратите внимание, что это нельзя использовать совместно с профилированием кучи (-hT), если не подключены к системе выполнения профилирования с помощью -prof.

-A ⟨size⟩
Значение по умолчанию:

4МБ

Устанавливает размер области выделения, используемой сборщиком мусора. Область выделения (на самом деле этап 0 поколения 0) фиксированная и никогда не изменяется (если вы не используете -H [⟨size⟩] ниже).

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

В общем случае, настройки >= 4МБ могут снизить производительность в некоторых случаях, особенно для однопоточного выполнения. Однако в многопоточном режиме увеличение области выделения до 16MB, или даже 64MB может значительно увеличить пропускную способность сборки мусора.

При наличии только 1 поколения (например, -G1, см. -G ⟨generations⟩) параметр -A задаёт минимальный размер области выделения, так как фактический размер области выделения будет изменяться в зависимости от количества данных в куче (см. -F ⟨factor⟩ ниже).

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

-AL ⟨size⟩
Значение по умолчанию:

значение -A

С версии:

8.2.1

Устанавливает предел общего размера «больших объектов» (объектов, больших примерно чем 3 КБ), которые можно выделить, прежде чем будет запущена сборка мусора. По умолчанию этот предел равен значению -A.

Большие объекты не выделяются из обычной области выделения, установленной флагом -A, поэтому для них есть отдельный предел. Большие объекты, как правило, намного реже, чем маленькие объекты, поэтому большинство программ достигают предела -A до предела -AL. Однако предел -A относится к каждой возможности, а предел -AL является глобальным, поэтому по мере увеличения -N возрастает вероятность того, что мы достигнем предела -AL раньше. Чтобы противодействовать этому, может потребоваться использовать больший предел -AL при использовании большого -N.

Чтобы понять, насколько эффективно вы используете всю выделенную память для области выделения (-A умножить на -N), посмотрите на вывод +RTS -S и проверьте, соответствует ли количество выделенной памяти между сборками мусора значению -A умноженному на -N. Если нет, есть два возможных решения: использовать -n для установки размера блока яслей или использовать -AL для увеличения предела для больших объектов.

-O ⟨size⟩
Значение по умолчанию:

1М

Устанавливает минимальный размер старого поколения.

Старое поколение собирается всякий раз, когда его размер достигает этого значения или значения параметра -F ⟨factor⟩, умноженного на размер активных данных на момент предыдущей основной сборки, в зависимости от того, какое из них больше.

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

4М с -A16m или больше, в противном случае 0.

Устанавливает размер блока области выделения. Установка -n0 означает, что область выделения не разделена на блоки.

[Пример: -n4m] При установке значения отличного от нуля, этот параметр разделяет область выделения (значение -A) на блоки заданного размера. Во время выполнения, когда процессор исчерпывает свой текущий блок, ему предоставляется другой блок из пула, пока пул не будет исчерпан, после чего запускается сборка.

Этот параметр полезен только при параллельной работе (-N2 или выше). Он позволяет процессорным ядрам лучше использовать доступную область выделения, даже когда ядра выделяют данные с разной скоростью. Без -n, каждое ядро получает фиксированную область выделения, заданную параметром -A, и первое ядро, которое исчерпает свою область выделения, запускает сборку мусора по всем ядрам. Это может привести к сборке мусора, когда области выделения некоторых ядер заполнены только частично, поэтому цель параметра -n заключается в том, чтобы позволить ядрам, которые выделяют быстрее, получить больше области выделения. Это означает менее частые сборки мусора, что приводит к меньшему накладным расходам сборки мусора для того же размера кучи.

Это особенно полезно в сочетании с более высокими значениями -A, например, -A64m -n4m является полезной комбинацией на больших количествах ядер (8+).

-c

Использует алгоритм уплотнения для сбора старейшего поколения. По умолчанию старейшее поколение собирается с помощью алгоритма копирования; этот параметр заставляет его вместо этого компактовать на месте. Алгоритм уплотнения медленнее, чем алгоритм копирования, но экономия памяти может быть значительной.

Для данного размера кучи (используя параметр -H [⟨size⟩]) уплотнение фактически может уменьшить затраты сборки мусора, позволяя выполнить меньше сборок. Это более вероятно, когда отношение активных данных к размеру кучи высокое, скажем, больше 30%.

Примечание

Уплотнение в настоящее время не работает, когда запрашивается одно поколение с помощью параметра -G1.

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

30

Автоматически включает компактную коллекцию, когда активные данные превышают ⟨n⟩% от максимального размера кучи (см. опцию -M ⟨size⟩). Обратите внимание, что максимальный размер кучи по умолчанию не ограничен, поэтому эта опция не действует, если максимальный размер кучи не установлен с помощью опции -M ⟨size⟩.

-F ⟨factor⟩
Значение по умолчанию:

2

Данная опция управляет объемом памяти, резервируемой для старых поколений (и, в случае коллектора с двумя пространствами, размером области выделения) как коэффициент к количеству активных данных. Например, если в старейшем поколении было 2 МБ активных данных при последней коллекции, то по умолчанию мы будем ждать, пока этот объем не достигнет 4 МБ, прежде чем производить следующую коллекцию.

Значение по умолчанию, как правило, подходит. Если у вас много памяти, обычно лучше использовать -H ⟨size⟩ (см. -H [⟨size⟩]), чем увеличивать значение -F ⟨factor⟩.

Значение -F ⟨factor⟩ автоматически уменьшается сборщиком мусора при приближении максимального размера кучи (значение -M ⟨size⟩).

-Fd ⟨factor⟩
Значение по умолчанию:

4

Обратная скорость, с которой неиспользуемая память возвращается ОС, когда она больше не требуется. После большого объёма выделений RTS начнёт удерживать выделенные блоки на случай их скорого повторного использования, но затем постепенно будет их освобождать, основываясь на значении -Fd ⟨factor⟩. При каждой последующей основной коллекции, не вызванной переполнением кучи, будет пытаться вернуть немного больше памяти, пока удерживаемый объём не станет приблизительно равен объёму активных байтов.

Увеличение этого значения замедлит возврат памяти, уменьшение – ускорит. Установка значения 0 отключит возврат памяти (что эмулирует поведение версий до 9.2).

-G ⟨generations⟩
Значение по умолчанию:

2

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

Указание 1 поколения с +RTS -G1 даёт вам простой коллектор с двумя пространствами, как ожидается. В коллекторе с двумя пространствами опция -A ⟨size⟩ определяет минимальный размер области выделения, поскольку область выделения будет увеличиваться с объёмом активных данных в куче. В многопоколенческом коллекторе область выделения имеет фиксированный размер (если не используется опция -H [⟨size⟩]).

-qg ⟨gen⟩
Значение по умолчанию:

0

С версии:

6.12.1

Использовать параллельный сбор мусора в поколении ⟨gen⟩ и выше. Отсутствие ⟨gen⟩ полностью отключает параллельный сбор мусора, возвращаясь к последовательному.

Параметры параллельного сборщика мусора по умолчанию, как правило, подходят для параллельных программ (т. е. тех, которые используют GHC.Conc.par, стратегии или с несколькими потоками). Однако иногда полезно включить параллельный сбор мусора и для однопоточных последовательных программ, особенно если программа имеет большой объем данных кучи и сбор мусора занимает значительную часть времени выполнения. Для использования параллельного сборщика мусора в последовательной программе включите параллельную среду выполнения с подходящей опцией -N ⟨x⟩, и дополнительно может быть полезно ограничить параллельный сбор мусора старым поколением с -qg1.

-qb ⟨gen⟩
Значение по умолчанию:

1 для -A < 32 МБ, в противном случае 0

С версии:

6.12.1

Использовать балансировку нагрузки в параллельном сборщике мусора в поколении ⟨gen⟩ и выше. Отсутствие ⟨gen⟩ полностью отключает балансировку нагрузки.

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

-qn ⟨x⟩
Значение по умолчанию:

значение -N или количество ядер процессора, что меньше.

С версии:

8.2.1

Установить количество потоков для использования параллельным сборщиком мусора.

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

Флаг -qn может быть полезен при работе с большим значением -A (чтобы сбор мусора был менее частым) и большим значением -N (чтобы использовать, например, гиперинструкции). Например, на 24-ядерном компьютере с 2 гиперинструкциями на ядро, мы можем использовать -N48 -qn24 -A128m для указания того, что мутатор должен использовать гиперинструкции, а сборщик мусора – только реальные ядра. Обратите внимание, что эта конфигурация будет использовать 6 ГБ для области выделения.

-H [⟨size⟩]
Значение по умолчанию:

0

Эта опция предоставляет «предлагаемый размер кучи» для сборщика мусора. Представьте себе -Hsize как переменную опцию -A ⟨size⟩. Она означает: я хочу использовать как минимум ⟨размер⟩ байт, поэтому используйте оставшееся пространство для увеличения значения -A.

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

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

-I ⟨seconds⟩
Значение по умолчанию:

0,3 секунды в многопоточной среде выполнения, 0 в однопоточной среде выполнения

Установить продолжительность простоя, которая должна пройти, прежде чем будет выполнен сбор мусора в режиме простоя. Установка -I0 отключает сбор мусора в режиме простоя.

В многопоточных и SMP-версиях RTS (см. -threaded, Параметры, влияющие на компоновку), основной сбор мусора выполняется автоматически, если среда выполнения находилась в состоянии простоя (никакие вычисления Haskell не выполнялись) в течение определенного промежутка времени.

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

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

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

-Iw ⟨seconds⟩
Default:

0 секунд

Устанавливает минимальное время ожидания между запусками GC в режиме простоя.

По умолчанию, если GC в режиме простоя включён в многопоточном исполняемом окружении, то основной GC будет выполняться каждый раз, когда процесс переходит в состояние простоя на достаточно длительное время (см. -I ⟨seconds⟩). Для больших серверных процессов, принимающих регулярные, но редкие запросы (например, один раз в секунду), дорогостоящий основной GC может запускаться после каждого запроса. В качестве альтернативы полному отключению GC в режиме простоя (с помощью -I0), можно указать минимальное время ожидания между запусками GC в режиме простоя с помощью этого флага. Например, -Iw60 гарантирует, что GC в режиме простоя будет выполняться не чаще, чем раз в минуту.

Это экспериментальная функция, сообщите нам, если она вызывает проблемы и/или нуждается в дополнительной настройке.

-ki ⟨size⟩
Default:

1k

Устанавливает начальный размер стека для новых потоков.

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

Примечание

Этот флаг раньше был просто -k, но был переименован в -ki в GHC 7.2.1. Старое имя всё ещё поддерживается для обратной совместимости, но может быть удалено в будущей версии.

-kc ⟨size⟩
Default:

32k

Устанавливает размер «фрагментов стека». Когда текущий стек потока переполняется, создаётся новый фрагмент стека и добавляется к стеку потока, пока не будет достигнут предел, установленный -K ⟨size⟩.

Преимущества меньших фрагментов стека заключаются в том, что сборщик мусора может избежать обхода фрагментов стека, если известно, что они не изменялись с момента последнего сбора, поэтому уменьшение размера фрагмента означает, что сборщик мусора может определить больше стека как неизменённый, а накладные расходы GC могут быть уменьшены. С другой стороны, слишком маленькие фрагменты стека добавляют некоторую нагрузку, так как будет больше переполнений/недостатков между фрагментами. Значение по умолчанию в 32k, по-видимому, представляет собой разумный компромисс в большинстве случаев.

-kb ⟨size⟩
Default:

1k

Устанавливает размер буфера фрагментов стека. Когда фрагмент стека переполняется и создаётся новый фрагмент стека, часть данных из предыдущего фрагмента стека перемещается в новый фрагмент, чтобы избежать непосредственного недостатка и повторного переполнения/недостатка на границе. Объём перемещённого стека задаётся параметром -kb.

Обратите внимание, что для экономии памяти это значение обычно должно быть меньше 10% от размера фрагмента стека (-kc ⟨size⟩), поскольку в цепочке фрагментов стека каждый фрагмент будет иметь пробел неиспользуемого пространства такого размера.

-K ⟨size⟩
Default:

80% физической памяти

Устанавливает максимальный размер стека для отдельного потока до ⟨size⟩ байт. Если поток пытается превысить этот предел, ему будет отправлено исключение StackOverflow. Предел может быть полностью отключён путём указания размера 0.

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

-m ⟨n⟩
Default:

3%

Минимальные % ⟨n⟩ кучи, которые должны быть доступны для выделения.

-M ⟨size⟩
Default:

без ограничений

Устанавливает максимальный размер кучи в ⟨size⟩ байт. Куча обычно увеличивается и уменьшается в зависимости от потребностей программы в памяти. Единственная причина наличия этого параметра — предотвращение бесконтростного увеличения кучи и заполнения всего доступного места обмена, что, как минимум, приведёт к тому, что программа будет немедленно убита операционной системой.

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

-Mgrace=⟨size⟩
Default:

1M

Если размер кучи программы превышает значение, установленное параметром -M ⟨size⟩, RTS выкидывает исключение для программы, и программе предоставляется дополнительный кворум выделения перед тем, как исключение будет снова выброшено. -Mgrace= управляет размером этого дополнительного кворума.

--numa
--numa=<mask>

Включить NUMA-осознающее выделение памяти в исполняемом окружении (доступно только с -threaded, и только в настоящее время на Linux и Windows).

Предыстория: некоторые системы имеют неравномерную архитектуру памяти (NUMA), при которой основная память разделена на банки, «локальные» для определённых ядер процессора. Доступ к локальной памяти быстрее, чем к удалённой памяти. Операционная система предоставляет API для выделения локальной памяти и привязки потоков к определённым ядрам процессора, чтобы обеспечить, что определённые обращения к памяти используют локальную память.

Параметр --numa сообщает RTS настроить использование памяти таким образом, чтобы максимизировать доступ к локальной памяти. В частности, RTS будет:

  • Определить количество NUMA узлов (N) путём запроса к ОС.
  • Управлять отдельными пулами памяти для каждого узла.
  • Сопоставить возможности с NUMA узлами. Возможность C сопоставляется с NUMA узлом C mod N.
  • Привязать рабочие потоки на возможности к соответствующему узлу.
  • Выделить ясли из локальной памяти узла.
  • Выполнить другие выделения памяти, включая GC, из локальной памяти узла.
  • При балансировке нагрузки, мы предпочитаем мигрировать потоки в другую возможность на том же узле.

Флаг --numa обычно выгоден, когда программа использует все ядра большой многоядерной NUMA системы с большой областью выделения (-A). Все обращения к памяти в области выделения будут направлены в локальную память, что может значительно уменьшить количество обращений к удалённой памяти. Типичное ускорение работы исполняемого окружения порядка 10%, но может сильно различаться в зависимости от оборудования и поведения памяти программы.

Обратите внимание, что RTS не устанавливает сродство ЦП для привязанных потоков и потоков, входящих в Haskell из C/C++, поэтому, если ваша программа использует привязанные потоки, вам следует убедиться, что каждый привязанный поток вызывает API RTS rts_setInCallCapability(c,1) из C/C++ перед вызовом в Haskell. В противном случае может возникнуть несоответствие между ядром, на котором работает поток, и памятью, которую он использует во время выполнения кода Haskell, что сведёт на нет любые преимущества --numa.

Если указана явная <маска>, <маска> интерпретируется как битовая карта, указывающая NUMA узлы, на которых следует запустить программу. Например, --numa=3 запустит программу на NUMA узлах 0 и 1.

--long-gc-sync
--long-gc-sync=<seconds>

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

Длительная синхронизация GC может быть вызвана мутаторным потоком, находящимся внутри вызова FFI unsafe, или работающим в цикле, который не выделяет память и, следовательно, не уступает управление. Для решения первой проблемы, сделайте вызов safe, а для решения второй — либо избегайте вызова интересующего кода, либо скомпилируйте его с -fomit-yields.

По умолчанию, флаг будет выводить предупреждение в stderr, когда время синхронизации превысит указанное время. Однако это поведение можно переопределить: обработчик longGCSync() вызывается, когда время синхронизации превышено во время периода синхронизации, а обработчик longGCSyncEnd() — в конце. Оба эти обработчика можно переопределить в RtsConfig, когда исполняемое окружение запускается с hs_init_ghc(). Стандартные реализации этих обработчиков (LongGcSync() и LongGCSyncEnd() соответственно) выдают предупреждения в stderr.

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

Время синхронизации GC, наряду с другими статистическими данными GC, доступны путём вызова функции getRTSStats() из C или GHC.Stats.getRTSStats из Haskell.

5.7.4. Параметры RTS для получения статистики выполнения

-T
-t [⟨file⟩]
-s [⟨file⟩]
-S [⟨file⟩]
--machine-readable
--internal-counters

Эти параметры производят статистику выполнения системы выполнения, такую как время, потраченное на выполнение программы и сборку мусора, количество выделенной памяти, максимальный размер кучи и так далее. Три варианта предоставляют разный уровень детализации: -T собирает данные, но не выводит ничего -t выводит одну строку вывода в том же формате, что и опция -Rghc-timing компилятора GHC, -s производит более подробный свод в конце программы, а -S дополнительно предоставляет информацию о каждом цикле сборки мусора. Передача --internal-counters многопоточному исполнителю приведет к тому, что подробный свод будет включать различные внутренние счетчики, накопленные во время выполнения; обратите внимание, что эти счетчики не определены и могут меняться между выпусками.

Вывод помещается в ⟨file⟩. Если ⟨file⟩ опущено, вывод направляется в stderr.

Если вы используете флаг -T , для доступа к статистике необходимо использовать GHC.Stats.

Если вы используете флаг -t , по завершении программы вы увидите что-то вроде этого:

<<ghc: 36169392 bytes, 69 GCs, 603392/1065272 avg/max bytes residency (2 samples), 3M in use, 0.00 INIT (0.00 elapsed), 0.02 MUT (0.02 elapsed), 0.07 GC (0.07 elapsed) :ghc>>

Это указывает на:

  • Общее количество байт, выделенных программой за весь период выполнения.
  • Общее количество выполненных сборок мусора.
  • Среднее и максимальное «проживание» (количество живых данных в байтах). Система выполнения может определить количество живых данных только во время основной сборки мусора, поэтому количество выборок соответствует количеству основных сборок мусора (и обычно является относительно небольшим). Чтобы получить более полное представление о профиле кучи вашей программы, используйте параметр RTS -hT (Параметры RTS для профилирования).
  • Пиковое количество памяти, выделенное системой выполнения от операционной системы.
  • Количество времени процессора и реальное время, затраченное на инициализацию системы выполнения (INIT), выполнение самой программы (MUT, мутатор) и сборку мусора (GC).

Вы также можете получить это в более совместимом с будущим, читаемом машиной формате, с -t --machine-readable:

[("bytes allocated", "36169392")
,("num_GCs", "69")
,("average_bytes_used", "603392")
,("max_bytes_used", "1065272")
,("num_byte_usage_samples", "2")
,("peak_megabytes_allocated", "3")
,("init_cpu_seconds", "0.00")
,("init_wall_seconds", "0.00")
,("mutator_cpu_seconds", "0.02")
,("mutator_wall_seconds", "0.02")
,("GC_cpu_seconds", "0.07")
,("GC_wall_seconds", "0.07")
]

Если вы используете флаг -s , по завершении программы вы увидите что-то вроде этого (точные детали будут зависеть от типа используемой системы выполнения, например, вы увидите данные профилирования только в том случае, если ваша система выполнения скомпилирована для профилирования):

    36,169,392 bytes allocated in the heap
     4,057,632 bytes copied during GC
     1,065,272 bytes maximum residency (2 sample(s))
        54,312 bytes maximum slop
             3 MB total memory in use (0 MB lost due to fragmentation)

Generation 0:    67 collections,     0 parallel,  0.04s,  0.03s elapsed
Generation 1:     2 collections,     0 parallel,  0.03s,  0.04s elapsed

SPARKS: 359207 (557 converted, 149591 pruned)

INIT  time    0.00s  (  0.00s elapsed)
MUT   time    0.01s  (  0.02s elapsed)
GC    time    0.07s  (  0.07s elapsed)
EXIT  time    0.00s  (  0.00s elapsed)
Total time    0.08s  (  0.09s elapsed)

%GC time      89.5%  (75.3% elapsed)

Alloc rate    4,520,608,923 bytes per MUT second

Productivity  10.5% of total user, 9.1% of total elapsed
  • «Байты, выделенные в куче» — общее количество байт, выделенных программой за весь период выполнения.
  • По умолчанию GHC использует копирующую сборку мусора. «Байты, скопированные во время сборки мусора» показывают количество байт, которые нужно было скопировать во время сборки мусора.
  • Максимальное количество пространства, фактически используемое вашей программой, — это значение «максимальное проживание в байтах». Это проверяется только во время основных сборок мусора, поэтому это лишь приближение; количество выборок показывает, сколько раз это проверялось.
  • «Максимальное количество «лишних» байт» показывает максимальное количество отходов, которые возникают из-за способа выделения памяти GHC блоками. «Лишние» байты — это память в конце блока, которая была потрачена. Управлять этим невозможно; мы просто хотим посмотреть, сколько памяти теряется таким образом.
  • «Общее используемое количество памяти» показывает пиковое количество памяти, выделенное системой выполнения от операционной системы.
  • Далее идёт информация о выполненных сборках мусора. Для каждой генерации указано количество выполненных сборок мусора, количество сборок мусора, выполненных параллельно, общее время процессора, затраченное на сборку мусора для этой генерации, и общее реальное время, затраченное на сборку мусора для этой генерации.
  • Статистика SPARKS относится к использованию Control.Parallel.par и смежных функций в программе. Каждая вспышка (spark) представляет вызов par; вспышка «преобразуется» при выполнении в параллельном режиме; и вспышка «обрезается» при обнаружении того, что она уже была вычислена, и исключается из пула сборщиком мусора. Все оставшиеся вспышки удаляются по завершении выполнения, поэтому «преобразованные» плюс «обрезанные» не обязательно суммируются с общим числом.
  • Далее указано время процессора и реальное время, затраченное, разбитое по действиям системы выполнения в данный момент. INIT — инициализация системы выполнения. MUT — время мутатора, то есть время, потраченное на фактическое выполнение вашего кода. GC — время, потраченное на сборку мусора. RP — время, потраченное на профилирование удержаний. PROF — время, потраченное на другое профилирование. EXIT — время закрытия системы выполнения. И, наконец, Total — общее время.

    %GC time указывает процент GC от Total. «Alloc rate» указывает «байты, выделенные в куче», делённые на время процессора MUT. «Производительность» указывает процент общего времени процессора и реального времени, потраченного на мутатор (MUT).

Флаг -S , а также дающий тот же вывод, что и флаг -s , печатает информацию о каждой сборке мусора по мере её выполнения:

    Alloc    Copied     Live    GC    GC     TOT     TOT  Page Flts
    bytes     bytes     bytes  user  elap    user    elap
   528496     47728    141512  0.01  0.02    0.02    0.02    0    0  (Gen:  1)
[...]
   524944    175944   1726384  0.00  0.00    0.08    0.11    0    0  (Gen:  0)

Для каждой сборки мусора выводится:

  • Сколько байт было выделено в ходе этой сборки мусора.
  • Сколько байт было скопировано в ходе этой сборки мусора.
  • Сколько байт в настоящее время активно используется.
  • Сколько времени заняла эта сборка мусора (время процессора и реальное время).
  • Сколько времени работает программа (время процессора и реальное время).
  • Сколько произошло страниц ошибок этой сборке мусора.
  • Сколько страниц ошибок произошло с момента окончания предыдущей сборки мусора.
  • Какая генерация собирается мусор.

5.7.5. Параметры RTS для конкурентности и параллелизма

Параметры RTS, относящиеся к конкурентности, описаны в Использование конкурентного Haskell, а параметры для параллелизма — в Параметры RTS для параллелизма SMP.

5.7.6. Параметры RTS для профилирования

Большинство параметров профилирования системы выполнения доступны только при компиляции программы для профилирования (см. Параметры компилятора для профилирования и Параметры RTS для профилирования кучи для параметров системы выполнения). Однако один параметр профилирования доступен для обычных исполняемых файлов без профилирования:

-hT
-h

Создаёт базовый профиль кучи в файле prog.hp. Для создания графика профиля кучи используйте hp2ps (см. hp2ps — Отрисовка профилей кучи в PostScript). Основной профиль кучи разбивается по конструкторам данных, при этом другие типы замыканий (функции, заглушки и т. д.) группируются в широкие категории (например, FUN, THUNK). Чтобы получить более подробный профиль, используйте полную поддержку профилирования (Профилирование). Может быть сокращён до -h.

Примечание

Значение сокращенного -h зависит от того, была ли ваша программа скомпилирована для профилирования. (См. Параметры RTS для профилирования кучи для подробностей.)

-L ⟨n⟩
По умолчанию:

25 символов

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

5.7.7. Отслеживание

Когда программа связана с опцией -eventlog (Параметры, влияющие на компоновку), события выполнения можно регистрировать несколькими способами:

  • В двоичном формате в файл для последующего анализа различными инструментами. Одним из таких инструментов является ThreadScope, который интерпретирует журнал событий, чтобы создать визуальный профиль параллельного выполнения программы.
  • В двоичном формате в настраиваемый записыватель журналов событий. Это позволяет проводить анализ событий в режиме реального времени во время выполнения программы.
  • В текстовом формате в стандартный вывод для целей отладки.
-l ⟨flags⟩

Записывать события в двоичном формате. Без указания ⟨флагов⟩ регистрируется набор стандартных событий, подходящий для использования с инструментами типа ThreadScope.

По умолчанию события записываются в program.eventlog, хотя механизм записи данных журнала событий может быть переопределён с помощью настраиваемого EventLogWriter.

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

  • s — события планировщика, включая создание и запуск/останов Haskell-нитей. Включены по умолчанию.
  • g — события сборки мусора, включая запуск/останов сборщика. Включены по умолчанию.
  • n — события неперемещающегося сборщика мусора (см. --nonmoving-gc) включающие начало и конец конкурентной маркировки и информацию о переписи для характеристики фрагментации кучи. Выключены по умолчанию.
  • p — параллельные искры (выборка). Включены по умолчанию.
  • f — параллельные искры (полностью точные). Выключены по умолчанию.
  • T — события ticky-ticky profiler (см. Счётчики Ticky для деталей). Выключены по умолчанию.
  • u — пользовательские события. Это события, исходящие из кода Haskell, с использованием функций, таких как Debug.Trace.traceEvent. Включены по умолчанию.

Вы можете отключить определенные классы или включить/отключить все классы сразу:

  • a — включить все перечисленные классы событий
  • -⟨x⟩ — отключить указанный класс событий
  • -a — отключить все классы

Например, -l-ag отключит все классы событий (-a) кроме событий сборки мусора (g).

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

Формат файла журнала описан в этом руководстве в Кодировки журналов событий. Его можно анализировать в Haskell с помощью библиотеки ghc-events. Для вывода содержимого файла .eventlog в текстовом формате используйте инструмент ghc-events show, поставляемый с пакетом ghc-events.

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

-ol⟨filename⟩
Значение по умолчанию:

⟨program⟩.eventlog

С версии:

8.8

Устанавливает место назначения для журнала событий, созданного с помощью флага -l ⟨flags⟩.

--eventlog-flush-interval=⟨seconds⟩
Значение по умолчанию:

выключен

С версии:

9.2

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

-v [⟨flags⟩]

Регистрировать события в виде текста в стандартный вывод, а не в файл .eventlog. Флаги ⟨flags⟩ такие же, как для -l, с дополнительным параметром t, который указывает, что перед каждым выводимым событием должно стоять значение метки времени (в двоичном файле .eventlog все события автоматически связаны со временем).

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

5.7.8. Параметры RTS для покрытия кода Haskell

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

--read-tix-file=<yes|no>
Значение по умолчанию:

включено

С версии:

9.12

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

По умолчанию этот флаг равен --read-tix-file=yes, но в будущей версии GHC он будет изменён на -read-tix-file=no в соответствии с принятым предложением GHC предложение 612.

--write-tix-file=<yes|no>
Значение по умолчанию:

включено

С версии:

9.10

По умолчанию система выполнения записывает файл <program>.tix в конце выполнения, если исполняемый файл скомпилирован с опцией -fhpc. Этот файл не записывается, если опция --write-tix-file=no передана системе выполнения.

Этот параметр полезен, если вы хотите использовать функциональность модуля Trace.Hpc.Reflect библиотеки hpc. Эти функции позволяют просматривать состояние структур данных Tix во время выполнения, чтобы исполняемый файл мог сам записывать файлы Tix на диск.

5.7.9. Параметры RTS для хакеров, отладчиков и чрезмерно заинтересованных

Эти параметры RTS могут быть использованы (a) для избежания ошибки GHC, (b) для просмотра «того, что происходит на самом деле» или (c) по желанию. Не рекомендуется для повседневного использования!

-B

Прозвучит звонок в начале каждого сбора мусора.

Как ни странно, люди действительно используют этот параметр! Наш друг из Дархема (Англия), Пол Кэллахан, пишет: «Некоторые люди здесь используют его для различных целей — честно! — например, для подтверждения, что код/машина что-то делает, для обнаружения бесконечных циклов, для оценки стоимости недавно добавленного кода. Некоторые люди даже могут определить на какой стадии [программа] находится по характеру звуковых сигналов. Но основное применение — это раздражение коллег по офису…»

-D ⟨x⟩

Флаг отладки RTS; доступен только если программа была скомпилирована с параметром -debug. Различные значения ⟨x⟩ предоставляются для включения сообщений об отладке и дополнительных проверок корректности выполнения в различных подсистемах RTS, например, +RTS -Ds -RTS включает сообщения об отладке от планировщика. Используйте +RTS -? для определения поддерживаемых флагов отладки.

Полный список поддерживаемых флагов:

-Ds DEBUG: scheduler
-Di DEBUG: interpreter
-Dw DEBUG: weak
-DG DEBUG: gccafs
-Dg DEBUG: gc
-Db DEBUG: block
-DS DEBUG: sanity
-DZ DEBUG: zero freed memory on GC
-Dt DEBUG: stable
-Dp DEBUG: prof
-Da DEBUG: apply
-Dl DEBUG: linker
-DL DEBUG: linker (verbose); implies :rts-flag:`-Dl`
-Dm DEBUG: stm
-Dn DEBUG: non-moving garbage collector
-Dz DEBUG: stack squeezing
-Dc DEBUG: program coverage
-Dr DEBUG: sparks
-DC DEBUG: compact
-Dk DEBUG: continuation
-Do DEBUG: iomanager

Сообщения об отладке будут отправлены в двоичный журнал событий, вместо stdout, если добавлен параметр -l ⟨flags⟩. Это может быть полезно для снижения накладных расходов при отслеживании отладки.

Чтобы понять, что они делают, наименее плохой способ — это поискать в директории rts/ в коде ghc макросы, такие как DEBUG(scheduler или DEBUG_scheduler.

-r ⟨file⟩

Выводит статистические данные «тики-тики» в конце выполнения программы (доступно только если программа была скомпилирована с -debug). Операция с именем файла ⟨file⟩ работает точно так же, как и для параметра RTS -S [⟨file⟩], выше.

Дополнительную информацию об профилировании «тики-тики» см. в Использование профилирования «тики-тики» (для разработчиков).

-xc

(Доступно только при компиляции программы для профилирования.) Когда в программе возникает исключение, этот параметр вызывает вывод стека вызовов в stderr.

Это может быть особенно полезно при отладке: если ваша программа жалуется на ошибку head [] и вы не знаете, какой фрагмент кода её вызывает, компиляция с параметром -prof -fprof-auto (см. -prof) и запуск с параметром +RTS -xc -RTS покажут точный стек вызовов в момент возникновения ошибки.

Вывод содержит один отчет для каждого исключения, возникшего в программе (программа может генерировать и обрабатывать несколько исключений во время своего выполнения), где каждый отчет выглядит примерно так:

*** Exception raised (reporting due to +RTS -xc), stack trace:
  GHC.List.CAF
  --> evaluated by: Main.polynomial.table_search,
  called from Main.polynomial.theta_index,
  called from Main.polynomial,
  called from Main.zonal_pressure,
  called from Main.make_pressure.p,
  called from Main.make_pressure,
  called from Main.compute_initial_state.p,
  called from Main.compute_initial_state,
  called from Main.CAF
  ...

Стек вызовов может часто начинаться с чего-то неинформативного, например, GHC.List.CAF; это артефакт оптимизатора GHC, который выносит исключения на верхний уровень, где система профилирования назначает их к центру затрат «CAF». Однако, +RTS -xc не просто выводит текущий стек, а смотрит глубже и выводит стек на момент вычисления CAF, и может вывести дополнительные стеки, пока не найдет стек, не относящийся к CAF. В приведенном выше примере следующий стек (после --> evaluated by) содержит много информации о том, что делала программа, когда вычисляла head [].

Помимо реализации, имена функций в стеке, вероятно, дадут достаточно подсказок для отслеживания ошибки.

Также см. функцию traceStack в модуле Debug.Trace для другого способа просмотра стеков вызовов.

-Z

Отключить сжатие кадров обновления при переключении контекста. (Нет особой причины отключать его, кроме как обеспечить точность определённых данных, собираемых в отношении количества входов в thunk.)

5.7.10. Получение информации о RTS

--info

Можно попросить RTS предоставить информацию о себе. Для этого используйте флаг --info, например:

$ ./a.out +RTS --info
[("GHC RTS", "YES")
,("GHC version", "6.7")
,("RTS way", "rts_p")
,("Host platform", "x86_64-unknown-linux")
,("Host architecture", "x86_64")
,("Host OS", "linux")
,("Host vendor", "unknown")
,("Build platform", "x86_64-unknown-linux")
,("Build architecture", "x86_64")
,("Build OS", "linux")
,("Build vendor", "unknown")
,("Target platform", "x86_64-unknown-linux")
,("Target architecture", "x86_64")
,("Target OS", "linux")
,("Target vendor", "unknown")
,("Word size", "64")
,("Compiler unregisterised", "NO")
,("Tables next to code", "YES")
,("Flag -with-rtsopts", "")
,("I/O manager default", "select")
]

Информация отформатирована таким образом, что её можно прочитать как тип [(String, String)]. В настоящее время присутствуют следующие поля:

GHC RTS

Связана ли эта программа с RTS GHC? (всегда «ДА»).

GHC version

Версия GHC, использованная для компиляции этой программы.

RTS way

Вариант («способ») выполнения. Наиболее распространённые значения — rts_v (обычный), rts_thr (потоковая реализация, т.е. скомпилировано с использованием параметра -threaded) и rts_p (реализация для профилирования, т.е. скомпилировано с использованием параметра -prof). Другие варианты включают debug (скомпилировано с использованием -debug) и dyn (RTS подключается динамически, т.е. это общая библиотека, а не статически связанная в исполняемый файл). Эти варианты могут комбинироваться, например, у вас может быть rts_thr_debug_p.

Target platformTarget architectureTarget OSTarget vendor

Платформа, для которой скомпилирована программа.

Build platformBuild architectureBuild OSBuild vendor

Платформа, на которой программа была скомпилирована. (То есть, целевая платформа самого GHC.) Обычно это идентично целевой платформе. (Это может отличаться при кросс-компиляции.)

Host platformHost architectureHost OSHost vendor

Платформа, на которой был скомпилирован сам GHC. Опять же, это обычно идентично платформам сборки и цели.

Word size

Либо "32" или "64", отражая разрядность целевой платформы.

Compiler unregistered

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

Tables next to code

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

Flag -with-rtsopts

Значение флага GHC -with-rtsopts=⟨opts⟩ во время компиляции/связывания.

I/O manager default

Имя подсистемы I/O менеджера, которая будет использоваться по умолчанию для этой программы. Это можно переопределить с помощью флага RTS --io-manager=(name).

© 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/runtime_control.html

Spec-Zone.ru

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