Dramatic de-optimization with "-O", "-O1", "-O2" options
Look for this simple program: `: import Control.Monad import Data.Maybe
-- import qualified Data.HashMap.Strict as M -- import qualified Data.Map.Lazy as M import qualified Data.Map.Strict as M
-- import Control.DeepSeq -- import Control.Exception
main :: IO () main = do putStrLn "Start"
n <- read <$> getLine
q <- read <$> getLine
dict' <- M.fromList <$> replicateM n ((\(k:v:_) -> (k,v)) <$> words <$> getLine)
-- dict <- evaluate $ force dict'
let dict = dict'
count <- length <$> catMaybes <$> replicateM q (flip M.lookup dict <$> getLine)
print count
`
When compiled without "-O2" it runs about 0.07 sec on my computer. But when compiled with "-O2" it runs about 77 sec (1100 times slowly!).
Look: compile and run without "-O2":
% rm -rf ./mime_type mime_type.{o,hi} && ghc mime_type.hs -o mime_type && cat my_data.txt | time ./mime_type
[1 of 1] Compiling Main ( mime_type.hs, mime_type.o )
Linking mime_type ...
Start
4738
./mime_type 0,06s user 0,01s system 97% cpu 0,069 total
And with "-O2":
% rm -rf ./mime_type mime_type.{o,hi} && ghc -O2 mime_type.hs -o mime_type && cat my_data.txt | time ./mime_type
[1 of 1] Compiling Main ( mime_type.hs, mime_type.o )
Linking mime_type ...
Start
4738
./mime_type 76,73s user 0,10s system 99% cpu 1:17,12 total
But when force dict
variable (dict <- evaluate $ force dict'
), it runs fast in both cases (with and without "-O2").
Also this bug is reproductable with "-O", "-O1" options.
Also this bug is reproductable with .Strict and .Lazy versions; and with Data.HashMap, .Strict and .Lazy
Also this bug is reproductable with GHC 7.10.2 and GHC 8.0.1-rc2 (The Glorious Glasgow Haskell Compilation System, version 8.0.0.20160204).
Data file my_data.txt is attached. It has simple structure:
- N, number of key-value pairs
- K, number of keys for searching
- N key-value pairs
- K kes
You can generate it with this Ruby script: {{{ #!/usr/bin/env ruby lst = ('a'..'z').to_a
N = 10000 K = 10000
File.open('my_data.txt', 'w') do |f|
f.puts(N)
f.puts(K)
N.times do
f.puts("#{lst.sample(3).join} #{lst.sample(5).join}")
# f.puts("(\"#{lst.sample(3).join}\",\"#{lst.sample(5).join}\")")
end
K.times do
f.puts("#{lst.sample(3).join}")
end
end }}}