Spec-Zone.ru › Haskell 9

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

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

У 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, принимающих значения ⟨size⟩: если последний символ в ⟨size⟩ — K или k, значение умножается на 1024; если M или m — на 1024*1024; если G или G — на 1024^3. (И за любое переполнение счётчиков отвечаете вы!)

Передача параметра RTS +RTS -? выведет список параметров RTS, доступных в вашей программе (он различается в зависимости от способа компиляции).

Примечание

Поскольку GHC сама скомпилирована с помощью GHC, можно изменять параметры RTS компилятора, используя обычное сочетание +RTS ... -RTS. Например, чтобы установить максимальный размер кучи для компиляции равным 128M, добавьте +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. Например, чтобы установить максимальный размер кучи равным 2G для всех программ, скомпилированных 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⟩

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

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

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

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

--generate-crash-dumps

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

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

Если задано значение yes (по умолчанию), 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-разрядных машинах компоновщику времени выполнения обычно необходимо отображать объектный код в нижних 2 ГБ адресного пространства. Это связано с малой моделью памяти 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, если их требуется загружать компоновщиком времени выполнения.

-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 размером более 1T. -xr ничего не делает, если GHC настроена с --disable-large-address-space или если платформа 32-разрядная.

--optimistic-linking

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

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

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

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

вкл.

Начиная с версии:

8.10.2

Обратный параметр:

–nonmoving-gc

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

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

выкл.

Начиная с версии:

8.10.1

Обратный параметр:

–copying-gc

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

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

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

выкл.

Начиная с версии:

8.10.1

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

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

16

Начиная с версии:

9.10.1

Обратный параметр:

нет

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

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

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

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

выкл.

Начиная с версии:

уже давно

Обратный параметр:

нет

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

-A ⟨size⟩
По умолчанию:

4MB

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

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

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

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

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

-AL ⟨size⟩
По умолчанию:

значение -A

Начиная с версии:

8.2.1

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

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

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

-O ⟨size⟩
По умолчанию:

1m

Задаёт минимальный размер старого поколения.

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

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

4m при значении -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

Этот параметр задаёт объём памяти, зарезервированный для старших поколений (а в случае двухпространственного сборщика — размер области выделения памяти), как множитель объёма живых данных. Например, если при последней сборке в самом старом поколении было 2M живых данных, то по умолчанию сборщик будет ждать, пока объём не достигнет 4M, прежде чем собирать его снова.

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

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

-Fd ⟨factor⟩
По умолчанию:

4

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

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

-G ⟨generations⟩
По умолчанию:

2

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

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

-qg ⟨gen⟩
По умолчанию:

0

Начиная с версии:

6.12.1

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

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

-qb ⟨gen⟩
По умолчанию:

1 при значении -A < 32M, иначе 0

Начиная с версии:

6.12.1

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

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

-qn ⟨x⟩
По умолчанию:

значение -N или количество ядер ЦП — выбирается меньшее значение.

Начиная с версии:

8.2.1

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

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

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

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

0

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

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

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

-I ⟨seconds⟩
По умолчанию:

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

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

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

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

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

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

-Iw ⟨seconds⟩
По умолчанию:

0 секунд

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

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

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

-ki ⟨size⟩
По умолчанию:

1k

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

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

Примечание

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

-kc ⟨size⟩
По умолчанию:

32k

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

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

-kb ⟨size⟩
По умолчанию:

1k

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

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

-K ⟨size⟩
По умолчанию:

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

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

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

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

3%

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

-M ⟨size⟩
По умолчанию:

не ограничен

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

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

Если максимальный размер кучи превышен, система выполнения вызовет исключение в главном потоке. Чтобы дать программе возможность корректно завершиться или восстановиться, GHC не будет повторно выбрасывать исключение в течение льготного периода после его первого возникновения. Длительность этого периода задаётся параметром -Mgrace=⟨size⟩. По его истечении исключение будет выброшено снова, если ограничение на размер кучи всё ещё превышено.

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

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

-Mgrace=⟨size⟩
По умолчанию:

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.
  • Привязывать рабочие потоки возможности к соответствующему узлу.
  • Выделять nursery из локальной памяти узла.
  • Выполнять другие выделения памяти, в том числе при сборке мусора, из локальной памяти узла.
  • При балансировке нагрузки отдавать предпочтение переносу потоков на другую возможность того же узла.

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

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

Если указан явный <mask>, он интерпретируется как битовая маска, указывающая узлы 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 выводит одну строку в том же формате, что и параметр GHC -Rghc-timing; -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 для профилирования).
  • Пиковый объём памяти, выделенной 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, по завершении программы будет выведено примерно следующее (точные данные зависят от типа RTS; например, данные профилирования будут отображаться только в RTS, скомпилированной для профилирования):

    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 использует копирующий сборщик мусора. «Байты, скопированные при GC» показывают, сколько байтов пришлось скопировать во время сборки мусора.
  • Максимальный объём памяти, фактически использованной программой, указан в поле «максимальный объём резидентных данных в байтах». Он проверяется только во время полных сборок мусора, поэтому является лишь приближённой оценкой; число измерений показывает, сколько раз выполнялась проверка.
  • «Максимальный объём потерь в байтах» показывает наибольший объём памяти, когда-либо потерянный из-за того, что GHC выделяет память блоками. Потери — это неиспользованная память в конце блока. Управлять этим нельзя; просто полезно знать, сколько памяти так теряется.
  • «Общий объём используемой памяти» показывает пиковый объём памяти, выделенной RTS у ОС.
  • Далее приводится информация о выполненных сборках мусора. Для каждого поколения указано число сборок мусора, сколько из них выполнялось параллельно, общее время процессора, затраченное на сборку мусора этого поколения, и общее прошедшее реальное время сборки мусора этого поколения.
  • Статистика SPARKS относится к использованию Control.Parallel.par и связанных с ними возможностей в программе. Каждая spark соответствует вызову par; spark «преобразуется», когда выполняется параллельно, и «отбрасывается», если оказывается уже вычисленной и удаляется сборщиком мусора из пула. Все оставшиеся sparks отбрасываются в конце выполнения, поэтому сумма «преобразованных» и «отброшенных» не обязательно равна общему числу.
  • Далее приводится время работы процессора и прошедшее реальное время с разбивкой по действиям среды выполнения. INIT — инициализация среды выполнения. MUT — время мутатора, то есть время фактического выполнения вашего кода. GC — время сборки мусора. RP — время профилирования удерживающих ссылок. PROF — время прочих видов профилирования. EXIT — время завершения работы среды выполнения. Наконец, Total — это общее время.

    %GC показывает, какой процент от Total занимает сборка мусора. «Скорость выделения» — это «байты, выделенные в куче», делённые на время процессора 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 для профилирования доступны только при компиляции программы для профилирования (см. Параметры компилятора для профилирования и Параметры RTS для профилирования кучи). Однако один параметр профилирования доступен для обычных исполняемых файлов без профилирования:

-hT
-h

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

Примечание

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

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

25 символов

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

5.7.7. Трассировка

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

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

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

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

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

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

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

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

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

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

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

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

-ol⟨filename⟩
По умолчанию:

⟨program⟩.eventlog

Начиная с версии:

8.8

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

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

отключено

Начиная с версии:

9.2

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

-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

RTS можно указать считывать файл <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 можно использовать, чтобы (а) обойти ошибку GHC, (б) выяснить, «что же на самом деле происходит», или (в) просто потому, что вам так захотелось. Для повседневного использования не рекомендуются!

-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

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

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

-r ⟨file⟩

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

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

-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? (Всегда “YES”.)

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

Название подсистемы менеджера ввода-вывода, которая будет использоваться этой программой по умолчанию. Его можно переопределить с помощью флага 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.14.1/docs/users_guide/runtime_control.html

Spec-Zone.ru

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