On 2017-12-07 12:49 AM, Jonas Scholl wrote:
Looking at the produced core of both versions reveals that in the profiled build a closure of type Regex is floated to top level. The non-profiled build doesn’t do this, thus it recompiles the regex for every iteration. This is most likely the source of the slowdown of the non-profiled build.
Thanks, Jonas. This does indeed seem to be the problem. I changed the code to use a compiled regex (with
makeRegex
andmatch
instead of=~
) but in the non-profiling case the run-time doesn’t improve unless I float the compiled regex myself:parseFilename :: String -> Either String (String, String) parseFilename fn = case (pattern `match` fn :: [[String]]) of [[_, full, _, time]] -> Right $ (full, time) _ -> Left fn pattern :: Regex pattern = makeRegex "^\\./duplicity-(full|inc|new)
(-signatures)?\\.\ \([0-9][0-9][0-9][0-9][0-9][0- 9][0-9][0-9]T[0-9][0-9][0-9][ 0-9][0-9][0-9]Z)\\." Then it runs 2-3x faster than the profiled code.
The question remains, however: why doesn’t the ghc optimizer spot this fairly obvious loop-invariant in the non-profiled build when it does manage to spot it in the profiled one? In other words, when I make
pattern
a local definition ofparseFilename
, why isn’t it treated as a CAF that’s evaluated only once (‘floated to the top level’)? Enabling profiling shouldn’t change the meaning of a program.I remember back in the day having to be careful with regexes in Python to make sure they were always precompiled outside of loops and functions, but one of the nice things about Haskell is that one can usually let the compiler take care of this. (Nowadays Python gets around this by caching compiled regexes, but I prefer Haskell’s statically-optimized approach.)
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell- cafe
Only members subscribed via the mailman list are allowed to post.