Чрезмерное количество системных вызовов при использовании `threadDelay`

У меня есть несколько процессов Haskell, запущенных на производстве, с системой с 12 ядрами. Все процессы скомпилированы с помощью -threaded и работают с 12 возможностями. Одна библиотека, которую они все используют, - это resource-pool, которая поддерживает пул соединений с базой данных.

Интересно, что, хотя все процессы практически бездействуют, они потребляют около 2% процессорного времени. Осмотр одного из этих процессов с помощью strace -p $(pgrep processname) -f показывает, что процесс выполняет необоснованное количество системных вызовов, даже если он не должен ничего делать. Чтобы взглянуть на вещи:

  • Запуск strace в процессе с -N2 в течение 5 секунд создает файл журнала 66K.
  • Запуск с (необоснованным) -N64 дает журнал < <мегабайт > .

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

Копаем глубже, мы обнаруживаем, что resource-pool запускает поток руны, который срабатывает каждую секунду, чтобы проверить, может ли он очистить некоторые ресурсы. Мы можем моделировать то же поведение с этой тривиальной программой.

module Main where

import Control.Concurrent
import Control.Monad (forever)

main :: IO ()
main = forever $ do
  threadDelay (10 ^ 6)

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

Поэтому, когда я подавляю эти циклы GC, передавая -I0 в RTS, выполняющий команду strace в процессе, выдает только около 70K больших файлов журнала. Поскольку процесс также запускает сервер scotty, GC запускается, когда запросы поступают, поэтому они, похоже, происходят, когда они мне действительно нужны.

Поскольку мы собираемся увеличить количество процессов Haskell на этой машине на большую сумму в течение следующего года, мне было интересно, как сохранить их свободное время на разумном уровне. Очевидно, передача -I0 кажется довольно плохой идеей (?). Другая идея заключалась бы в том, чтобы просто уменьшить количество возможностей с 12 до, возможно, что-то вроде 4. Есть ли другой способ настроить RTS, чтобы я мог поддерживать процессы от записи до многих циклов ЦП на холостом ходу?

Ответы