diff options
Diffstat (limited to 'testsuite/tests/perf/should_run/MethSharing.hs')
-rw-r--r-- | testsuite/tests/perf/should_run/MethSharing.hs | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/testsuite/tests/perf/should_run/MethSharing.hs b/testsuite/tests/perf/should_run/MethSharing.hs new file mode 100644 index 0000000000..fb69bd4509 --- /dev/null +++ b/testsuite/tests/perf/should_run/MethSharing.hs @@ -0,0 +1,97 @@ +module Main where + +-- This test works efficiently because the full laziness +-- pass now floats out applications +-- \x -> f y (x+1) +-- It'll float out the (f y) if that's a redex + +loop :: Double -> [Int] -> Double +{-# NOINLINE loop #-} +loop x [] = x +loop x (n:ns) = x `seq` loop (x ^ n) ns + +main = print $ loop 1 (replicate 10000000 5) + +---------------------------------------------------- +{- Roman's message of May 2010 + +I tried running nofib with -fno-method-sharing (we discussed this at some point). These are the results: + +-------------------------------------------------------------------------------- + Program Size Allocs Runtime Elapsed +-------------------------------------------------------------------------------- + + Min -0.3% -25.0% -12.5% -9.9% + Max +0.2% +159.1% +90.0% +84.7% + Geometric Mean -0.0% +2.2% +6.8% +5.1% + +This is the worst program: + + simple +0.2% +159.1% +65.3% +63.9% + +I looked at it a bit and came up with this small example: + +---- +loop :: Double -> [Int] -> Double +{-# NOINLINE loop #-} +loop x [] = x +loop x (n:ns) = x `seq` loop (x ^ n) ns + +main = print $ loop 1 (replicate 10000000 5) +---- + +This is over 2x slower with -fno-method-sharing. The culprit is, of +course, (^). Here is the difference: + +Without -fno-method-sharing: + +---- +^_rVB :: GHC.Types.Double -> GHC.Types.Int -> GHC.Types.Double ^_rVB = + GHC.Real.^ + @ GHC.Types.Double + @ GHC.Types.Int + GHC.Float.$fNumDouble + GHC.Real.$fIntegralInt + +Main.loop [InlPrag=NOINLINE (sat-args=2), Occ=LoopBreaker] + :: GHC.Types.Double -> [GHC.Types.Int] -> GHC.Types.Double Main.loop = + \ (x1_aat :: GHC.Types.Double) (ds_drG :: [GHC.Types.Int]) -> + case ds_drG of _ { + [] -> x1_aat; + : n_aav ns_aaw -> + case x1_aat of x2_aau { GHC.Types.D# ipv_srQ -> + Main.loop (^_rVB x2_aau n_aav) ns_aaw + } + } +---- + +With: + +---- +Main.loop [InlPrag=NOINLINE (sat-args=2), Occ=LoopBreaker] + :: GHC.Types.Double -> [GHC.Types.Int] -> GHC.Types.Double Main.loop = + \ (x1_aat :: GHC.Types.Double) (ds_drD :: [GHC.Types.Int]) -> + case ds_drD of _ { + [] -> x1_aat; + : n_aav ns_aaw -> + case x1_aat of x2_aau { GHC.Types.D# ipv_srN -> + Main.loop + (GHC.Real.^ + @ GHC.Types.Double + @ GHC.Types.Int + GHC.Float.$fNumDouble + GHC.Real.$fIntegralInt + x2_aau + n_aav) + ns_aaw + } + } +---- + +This is a bit disappointing. I would have expected GHC to float out +the application of (^) to the two dictionaries during full laziness +(note that (^) has arity 2 so the application is oversaturated). Why +doesn't that happen? SetLevels (if this is the right place to look) +has this: + +-}
\ No newline at end of file |