[GHC] #7977: Optimization: Shift dropped list heads by coeffecient to prevent thunk generation
GHC
ghc-devs at haskell.org
Tue Jun 11 16:50:18 CEST 2013
#7977: Optimization: Shift dropped list heads by coeffecient to prevent thunk
generation
-----------------------------+----------------------------------------------
Reporter: schyler | Owner:
Type: feature request | Status: new
Priority: normal | Component: Compiler
Version: 7.4.2 | Keywords:
Os: Unknown/Multiple | Architecture: Unknown/Multiple
Failure: None/Unknown | Blockedby:
Blocking: | Related:
-----------------------------+----------------------------------------------
Consider the following snippet(s) equivalent to ([a..b] !! n), the source
of (!!) and the source of drop:
{{{
normal_list :: Int -> Int
normal_list n = head $ drop n [a..b]
shifted_list :: Int -> Int
shifted_list n = head $ drop (n-n) [(a+n)..b]
}}}
{{{
xs !! n | n < 0 = undefined
[] !! _ = undefined
(x:_) !! 0 = x
(_:xs) !! n = xs !! (n-1)
}}}
{{{
drop n xs | n <= 0 = xs
drop _ [] = []
drop n (_:xs) = drop (n-1) xs
}}}
Notice the (_:xs) matching in these functions as a result of WHNF.
In the first case, normal_list, thunks are generated for x in ({-x-}_:xs)
of the target list and overhead is seen in the pattern matching/guard of n
in drop.
In the second case, shifted_list, this overhead can be completely removed
by adding a coefficient such that the list starts at the programmatically
defined lower bound, a, plus the known fact that the head is dropped n
times.
Hence, given the example above, consider:
{{{
[x * x + 3 | x <- [1..]] !! n
-- versus
[x * x + 3 | x <- [(1+n)..]] !! (n-n)
-- which is optimized into
[x * x + 3 | x <- [(n+1)..]] !! 0
-- which is effectively
head [x * x + 3 | x <- [(n+1)..]]
}}}
The operation is turned from O(n) into O(1).
Consider benchmark proving GHC 7.4.2 does not make this optimization under
-O2:
{{{
import Criterion.Main
normal_list :: Int -> Int
normal_list n = head $ drop n [1..]
shifted_list :: Int -> Int
shifted_list n = head $ drop (n-n) [(1+n)..]
main = defaultMain
[ bench "normal_list 1000" $ whnf normal_list 1000
, bench "shifted_list 1000" $ whnf shifted_list 1000
]
}}}
{{{
C:\Users\Kyle\Desktop>ghc -O2 listco.hs
[1 of 1] Compiling Main ( listco.hs, listco.o )
Linking listco.exe ...
C:\Users\Kyle\Desktop>listco.exe
warming up
estimating clock resolution...
mean is 4.644044 us (160001 iterations)
found 319255 outliers among 159999 samples (199.5%)
159256 (99.5%) low severe
159999 (100.0%) high severe
estimating cost of a clock call...
mean is 310.3118 ns (34 iterations)
benchmarking normal_list 1000
Warning: Couldn't open /dev/urandom
Warning: using system clock for seed instead (quality will be lower)
mean: 7.352463 us, lb 7.058339 us, ub 7.646574 us, ci 0.950
std dev: 1.478087 us, lb 1.478066 us, ub 1.478200 us, ci 0.950
variance introduced by outliers: 94.651%
variance is severely inflated by outliers
benchmarking shifted_list 1000
mean: 46.42819 ns, lb 45.44244 ns, ub 47.21689 ns, ci 0.950
std dev: 4.495757 ns, lb 4.035428 ns, ub 4.832396 ns, ci 0.950
variance introduced by outliers: 77.960%
variance is severely inflated by outliers
}}}
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/7977>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list