Cheng Shao pushed to branch wip/ghci-spark at Glasgow Haskell Compiler / GHC

Commits:

3 changed files:

Changes:

  • libraries/ghc-boot/GHC/Utils/Spark.hs
    1
    +{-# LANGUAGE MagicHash #-}
    
    2
    +
    
    3
    +module GHC.Utils.Spark
    
    4
    +  ( sparkST,
    
    5
    +    sparkIO,
    
    6
    +  )
    
    7
    +where
    
    8
    +
    
    9
    +import Control.Monad
    
    10
    +import GHC.Exts
    
    11
    +import GHC.IO
    
    12
    +import GHC.ST
    
    13
    +import Prelude
    
    14
    +
    
    15
    +-- | Same as 'sparkIO' but in the 'ST' monad, useful if no other side
    
    16
    +-- effects are involved.
    
    17
    +sparkST :: ST s a -> ST s a
    
    18
    +sparkST = ST . spark# <=< unsafeInterleaveST
    
    19
    +
    
    20
    +-- | Spawns an 'IO' computation as a spark and returns a thunk that
    
    21
    +-- evaluates to the computation's result. The computation is guarded
    
    22
    +-- by 'noDuplicate' to prevent being executed by multiple threads at
    
    23
    +-- once.
    
    24
    +sparkIO :: IO a -> IO a
    
    25
    +sparkIO = IO . spark# <=< unsafeInterleaveIO

  • libraries/ghc-boot/ghc-boot.cabal.in
    ... ... @@ -55,6 +55,7 @@ Library
    55 55
                 GHC.Data.SizedSeq
    
    56 56
                 GHC.Utils.Encoding
    
    57 57
                 GHC.Utils.Encoding.UTF8
    
    58
    +            GHC.Utils.Spark
    
    58 59
                 GHC.LanguageExtensions
    
    59 60
                 GHC.Unit.Database
    
    60 61
                 GHC.Serialized
    

  • libraries/ghci/GHCi/Message.hs
    ... ... @@ -44,13 +44,13 @@ import qualified GHC.Exts.Heap as Heap
    44 44
     #endif
    
    45 45
     import GHC.ForeignSrcLang
    
    46 46
     import GHC.Fingerprint
    
    47
    -import GHC.Conc (pseq, par)
    
    48 47
     import Control.Concurrent
    
    49 48
     import Control.DeepSeq
    
    50 49
     import Control.Exception
    
    51 50
     #if MIN_VERSION_base(4,20,0)
    
    52 51
     import Control.Exception.Context
    
    53 52
     #endif
    
    53
    +import Control.Monad.ST
    
    54 54
     import Data.Binary
    
    55 55
     import Data.Binary.Get
    
    56 56
     import Data.Binary.Put
    
    ... ... @@ -66,6 +66,7 @@ import Data.Map (Map)
    66 66
     import Foreign
    
    67 67
     import GHC.Generics
    
    68 68
     import GHC.Stack.CCS
    
    69
    +import GHC.Utils.Spark
    
    69 70
     import qualified GHC.Boot.TH.Syntax        as TH
    
    70 71
     import qualified GHC.Boot.TH.Monad         as TH
    
    71 72
     import System.Exit
    
    ... ... @@ -572,7 +573,7 @@ getMessage = do
    572 573
           9  -> Msg <$> RemoveLibrarySearchPath <$> get
    
    573 574
           10 -> Msg <$> return ResolveObjs
    
    574 575
           11 -> Msg <$> FindSystemLibrary <$> get
    
    575
    -      12 -> Msg <$> (CreateBCOs . concatMap (runGet get)) <$> (get :: Get [LB.ByteString])
    
    576
    +      12 -> Msg <$> (CreateBCOs . fmap (runGet get)) <$> (get :: Get [LB.ByteString])
    
    576 577
                         -- See Note [Parallelize CreateBCOs serialization]
    
    577 578
           13 -> Msg <$> FreeHValueRefs <$> get
    
    578 579
           14 -> Msg <$> MallocData <$> get
    
    ... ... @@ -653,29 +654,17 @@ putMessage m = case m of
    653 654
     Note [Parallelize CreateBCOs serialization]
    
    654 655
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    655 656
     Serializing ResolvedBCO is expensive, so we do it in parallel.
    
    656
    -We split the list [ResolvedBCO] into chunks of length <= 100,
    
    657
    -and serialize every chunk in parallel, getting a [LB.ByteString]
    
    658
    -where every bytestring corresponds to a single chunk (multiple ResolvedBCOs).
    
    657
    +For each element in the list [ResolvedBCO], we spawn a spark which
    
    658
    +serializes it, getting a [LB.ByteString] where every fully evaluated
    
    659
    +lazy ByteString corresponds to a single ResolvedBCO.
    
    659 660
     
    
    660 661
     Previously, we stored [LB.ByteString] in the Message object, but that
    
    661 662
     incurs unneccessary serialization with the internal interpreter (#23919).
    
    662 663
     -}
    
    663 664
     
    
    664 665
     serializeBCOs :: [ResolvedBCO] -> [LB.ByteString]
    
    665
    -serializeBCOs rbcos = parMap doChunk (chunkList 100 rbcos)
    
    666
    - where
    
    667
    -  -- make sure we force the whole lazy ByteString
    
    668
    -  doChunk c = pseq (LB.length bs) bs
    
    669
    -    where bs = runPut (put c)
    
    670
    -
    
    671
    -  -- We don't have the parallel package, so roll our own simple parMap
    
    672
    -  parMap _ [] = []
    
    673
    -  parMap f (x:xs) = fx `par` (fxs `pseq` (fx : fxs))
    
    674
    -    where fx = f x; fxs = parMap f xs
    
    675
    -
    
    676
    -  chunkList :: Int -> [a] -> [[a]]
    
    677
    -  chunkList _ [] = []
    
    678
    -  chunkList n xs = as : chunkList n bs where (as,bs) = splitAt n xs
    
    666
    +serializeBCOs rbcos =
    
    667
    +  runST $ traverse (sparkST . pure . force . runPut . put) rbcos
    
    679 668
     
    
    680 669
     -- -----------------------------------------------------------------------------
    
    681 670
     -- Reading/writing messages