Opened 4 years ago

Last modified 3 years ago

#10401 new bug

state hack-related regression

Reported by: rwbarton Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.10.1
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Runtime performance bug Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Consider the following program exp.hs:

import Control.Monad
import Debug.Trace

expensive :: String -> String
expensive x = trace "$$$" x
{-# NOINLINE expensive #-}

main :: IO ()
main = do
  str <- fmap expensive getLine
  replicateM_ 3 $ print str

When run as echo hi | ./exp, it might print either

$$$
"hi"
"hi"
"hi"

or

$$$
"hi"
$$$
"hi"
$$$
"hi"

depending on the compiler version and optimization settings.

In 7.8.4, building with -O2 produces the second (bad) output, while building with -O2 -fno-state-hack produces the first output, not surprisingly.

However in 7.10.1 and in HEAD both -O2 and -O2 -fno-state-hack produce the second output.

It seems this difference in behavior between 7.8.4 and 7.10.1 may be due to the following difference in the unfolding for IO's fmap. In 7.8.4

ba867929df0910f70431843781ad014d
  $fFunctorIO2 :: (a -> b)
                  -> GHC.Types.IO a
                  -> GHC.Prim.State# GHC.Prim.RealWorld
                  -> (# GHC.Prim.State# GHC.Prim.RealWorld, b #)
    {- Arity: 3, HasNoCafRefs,
       Strictness: <L,1*C1(U)><C(S),1*C1(U(U,U))><L,U>,
       Unfolding: (\ @ a
                     @ b
                     f :: a -> b
                     x :: GHC.Types.IO a
                     s :: GHC.Prim.State# GHC.Prim.RealWorld ->
                   case x `cast` (GHC.Types.NTCo:IO[0] <a>_R)
                          s of ds { (#,#) ipv ipv1 ->
                   (# ipv, f ipv1 #) }) -}

while in 7.10.1

d645bee15151bb50f2bad5912d533b38
  $fFunctorIO2 ::
    (a -> b) -> IO a -> State# RealWorld -> (# State# RealWorld, b #)
  {- Arity: 3, HasNoCafRefs,
     Strictness: <L,1*C1(U)><C(S),1*C1(U(U,U))><L,U>,
     Unfolding: InlineRule (3, True, False)
                (\ @ a @ b f :: a -> b x :: IO a s :: State# RealWorld[OneShot] ->
--                                                                     ^^^^^^^
                 case x `cast` (NTCo:IO[0] <a>_R) s of ds { (#,#) ipv ipv1 ->
                 (# ipv, f ipv1 #) }) -}

I didn't completely confirm this, though, nor determine how that difference arose in the first place (I assume the libraries were built with -O2 for both versions?)

Change History (3)

comment:1 Changed 4 years ago by nomeata

The difference you marked is a result of changeset:c001bde73e38904ed161b0b61b240f99a3b6f48d/ghc. But I believe it is not the cause of the problem, as the state hack would, if I understand it correctly, assume State# RealWorld to be one-shot independent of whether that annotation is present in the unfolding or not.

comment:2 Changed 4 years ago by rwbarton

But the ticket is mostly about the behavior of 7.10.1 with -O2 -fno-state-hack. Does that change things? (Probably should have been clearer about this.)

In 7.8 we have -fno-state-hack as an escape hatch for when the state hack heuristic goes wrong. But we can't expect people to rebuild all their dependencies including base with -fno-state-hack, and disabling optimizations completely is not very satisfactory either.

comment:3 Changed 3 years ago by simonpj

See #1168, the master ticket.

Note: See TracTickets for help on using tickets.