Mam funkcję nierekurencyjną do obliczania najdłuższego wspólnego podciągu, który wydaje się dobrze działać (ghc 7.6.1
, skompilowany z flagami -O2 -fllvm
), jeśli zmierzę go z Criterion
w tym samym module. Z drugiej strony, jeśli przekonwertuję funkcję na moduł, wyeksportuję właśnie tę funkcję (zgodnie z zaleceniem here), a następnie zmierzę ponownie za pomocą kryterium, otrzymuję ~ 2x spowolnienie (które znika, gdy przeniosę test kryterium z powrotem do modułu gdzie zdefiniowana jest funkcja). Próbowałem zaznaczyć funkcję z pragma INLINE
, która nie miała wpływu na pomiary wydajności między modułami.Optymalizacje w module krzyżowym w GHC
Wydaje mi się, że GHC może przeprowadzać analizę ścisłości, która działa dobrze, gdy funkcja i główna (z której funkcja jest dostępna) znajdują się w tym samym module, ale nie wtedy, gdy są rozdzielone. Byłbym wdzięczny za wskazówki, jak modularyzować funkcję tak, aby działała dobrze po wywołaniu z innych modułów. Kod, o którym mowa, jest zbyt duży, aby go tu wkleić - możesz go zobaczyć here, jeśli chcesz go wypróbować. Mały przykład tego, co próbuję zrobić, to poniżej (z fragmentów kodu):
-- Function to find longest common subsequence given unboxed vectors a and b
-- It returns indices of LCS in a and b
lcs :: (U.Unbox a, Eq a) => Vector a -> Vector a -> (Vector Int,Vector Int)
lcs a b | (U.length a > U.length b) = lcsh b a True
| otherwise = lcsh a b False
-- This section below measures performance of lcs function - if I move it to
-- a different module, performance degrades ~2x - mean goes from ~1.25us to ~2.4us
-- on my test machine
{--
config :: Config
config = defaultConfig { cfgSamples = ljust 100 }
a = U.fromList ['a'..'j'] :: Vector Char
b = U.fromList ['a'..'k'] :: Vector Char
suite :: [Benchmark]
suite = [
bench "lcs 10" $ whnf (lcs a) b
]
main :: IO()
main = defaultMainWith config (return()) suite
--}
Zamiast tego wypróbuj INLINEABLE. To może działać lepiej. – Carl
@Carl, wypróbowany dla funkcji lcs. Wciąż ten sam. – Sal
Podejrzewam, że problem polega na tym, że GHC może specjalizować zmienną typu 'a' na' Char', ponieważ nigdy nie jest używana z żadnym innym typem, co eliminuje narzut klasy. Możesz spróbować grać z 'pragma '(lub po prostu zmienić ją na' Char' ręcznie) i sprawdzić, czy to ma jakiś wpływ. – hammar