Варианты RTS GHC для сбора мусора - PullRequest
38 голосов
/ 03 июля 2010

У меня есть программа на Haskell, которая обрабатывает текстовый файл и создает Map (с несколькими миллионами элементов). Все это может длиться 2-3 минуты. Я обнаружил, что настройка параметров -H и -A сильно влияет на время выполнения.

Имеется документация об этой функциональности RTS, но мне трудно ее прочитать, поскольку я не знаю алгоритмов и терминов из теории GC. Я ищу менее техническое объяснение, предпочтительно специфичное для Haskell / GHC. Есть ли какие-либо ссылки на выбор разумных значений для этих параметров?

EDIT: Это код, он строит три для заданного списка слов.

buildTrie :: [B.ByteString] -> MyDFA 
buildTrie l = fst3 $ foldl' step (emptyDFA, B.empty, 1) $ sort $ map B.reverse l where
    step :: (MyDFA , B.ByteString, Int) -> B.ByteString -> (MyDFA , B.ByteString, Int)
    step (dfa, lastWord, newIndex) newWord = (insertNewStates, newWord, newIndex + B.length newSuffix) where            
        (pref, lastSuffix, newSuffix) = splitPrefix lastWord newWord
        branchPoint = transStar dfa pref

        --new state labels for the newSuffix path
        newStates = [newIndex .. newIndex + B.length newSuffix - 1]
        --insert newStates
        insertNewStates = (foldl' (flip insertTransition) dfa $ zip3 (branchPoint:init newStates) (B.unpack newSuffix) newStates)

Ответы [ 2 ]

68 голосов
/ 03 июля 2010

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

Компромисс работает следующим образом: программа распределяет память до тех пор, пока она не достигнет некоторого предела (определяется параметрами автоматической настройки ГХ или явно через параметры RTS). Когда предел достигнут, ГХ отслеживает все данные, которые программа использует в настоящее время, и восстанавливает всю память, используемую данными, которые больше не требуются. Чем дольше вы можете отложить этот процесс, тем больше данных станет недоступным («мертвым») за это время, поэтому GC избегает отслеживания этих данных. Единственный способ задержать сборку мусора - это выделить больше памяти для размещения; следовательно, больше памяти равняется меньшему количеству GC, равному меньшему количеству служебных данных GC. Грубо говоря, опция -H GHC позволяет установить нижнюю границу объема памяти, используемого GC, что позволяет снизить накладные расходы GC.

GHC использует GC поколения, который является оптимизацией базовой схемы, в которой куча делится на два или более поколений. Объекты выделяются в «молодое» поколение, а те, которые живут достаточно долго, превращаются в «старое» поколение (в установке 2-го поколения). Молодое поколение собирается гораздо чаще, чем старое, идея состоит в том, что «большинство объектов умирают молодыми», поэтому коллекции молодого поколения дешевы (они не отслеживают много данных), но они требуют много памяти. Грубо говоря, опция -A устанавливает размер молодого поколения, то есть объем памяти, который будет выделен до сбора молодого поколения.

Значением по умолчанию для -A является 512 КБ: хорошая идея, чтобы молодое поколение оставалось меньше кеша L2, а производительность обычно падает, если вы превышаете размер кеша L2. Но работа в обратном направлении - это компромисс между пространством и временем GC: использование очень большого размера молодого поколения может перевесить преимущества кэша за счет уменьшения объема работы, которую должен выполнять GC. Это не всегда происходит, это зависит от динамики приложения, что затрудняет автоматическую настройку GC. Опция -H также увеличивает размер молодого поколения, что также может отрицательно сказаться на использовании кэша.

Суть: поиграйтесь с опциями и посмотрите, что работает. Если у вас достаточно свободной памяти, вы, возможно, сможете увеличить производительность, используя -A или -H, но не обязательно.

8 голосов
/ 04 июля 2010

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

Затем проверьте, соответствуют ли профили памяти, которые вы видите, вашим ожиданиям (вам не нужно знать овсе параметры профилирования для получения полезных графиков).Сочетание строгого foldl' с нестрогим кортежем в качестве аккумулятора было бы первым, на что я бы обратил внимание: если компоненты кортежа не являются принудительными, эта рекурсия создает не оцененные выражения.

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

...