summaryrefslogtreecommitdiff
path: root/testsuite/tests/perf/should_run/MethSharing.hs
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/tests/perf/should_run/MethSharing.hs')
-rw-r--r--testsuite/tests/perf/should_run/MethSharing.hs97
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