Опции RTS GHC для сборки "мусора"

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

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

Править: Это - код, он создает trie для данного списка слов.

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)

38
задан Dominik Schrempf 7 May 2018 в 16:53
поделиться

2 ответа

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

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

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

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

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

68
ответ дан 27 November 2019 в 03:30
поделиться

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

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

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

8
ответ дан 27 November 2019 в 03:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: