Skip to content

Commit 861f350

Browse files
Alex McKennavmchale
authored andcommitted
Add concurrent normalization
Co-authored-by: Vanessa McHale <[email protected]>
1 parent 2ef08d6 commit 861f350

File tree

30 files changed

+965
-573
lines changed

30 files changed

+965
-573
lines changed

.ci/bindist/linux/debian/focal/buildinfo.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
"src": {"type": "hackage", "version": "0.7.0.12"},
2727
"cabal_debian_options": ["--disable-tests"]
2828
},
29+
{
30+
"name": "atomic-primops",
31+
"src": {"type": "hackage", "version": "0.8.4"},
32+
"cabal_debian_options": ["--disable-tests"]
33+
},
34+
{
35+
"name": "lockfree-queue",
36+
"src": {"type": "hackage", "version": "0.2.3.1"},
37+
"cabal_debian_options": ["--disable-tests"]
38+
},
2939
{
3040
"name": "ghc-tcplugins-extra",
3141
"src": {"type": "hackage"}

benchmark/benchmark-normalization.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Clash.Netlist.Types (TopEntityT(topId))
1515

1616
import Criterion.Main
1717

18+
import qualified Control.Concurrent.MVar as MVar
1819
import qualified Control.Concurrent.Supply as Supply
1920
import Control.DeepSeq (NFData(..), rwhnf)
2021
import Data.List (isPrefixOf, partition)
@@ -42,7 +43,7 @@ main = do
4243
benchFile :: [FilePath] -> FilePath -> Benchmark
4344
benchFile idirs src =
4445
env (setupEnv idirs src) $
45-
\ ~(clashEnv, clashDesign, supplyN) -> do
46+
\ ~(clashEnv, clashDesign, supplyN, lock) -> do
4647
bench ("normalization of " ++ src)
4748
(nfIO
4849
(normalizeEntity
@@ -51,18 +52,20 @@ benchFile idirs src =
5152
(ghcTypeToHWType (opt_intWidth (envOpts clashEnv)))
5253
ghcEvaluator
5354
evaluator
55+
lock
5456
(fmap topId (designEntities clashDesign))
5557
supplyN
5658
(topId (head (designEntities clashDesign)))))
5759

5860
setupEnv
5961
:: [FilePath]
6062
-> FilePath
61-
-> IO (ClashEnv, ClashDesign, Supply.Supply)
63+
-> IO (ClashEnv, ClashDesign, Supply.Supply, MVar.MVar ())
6264
setupEnv idirs src = do
6365
(clashEnv, clashDesign) <- runInputStage idirs src
6466
supplyN <- Supply.newSupply
65-
return (clashEnv, clashDesign ,supplyN)
67+
lock <- MVar.newMVar ()
68+
return (clashEnv, clashDesign ,supplyN, lock)
6669

6770
instance NFData Supply.Supply where
6871
rnf = rwhnf

benchmark/common/BenchmarkCommon.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Clash.GHC.Evaluator
1515
import Clash.GHC.GenerateBindings
1616
import Clash.GHC.NetlistTypes
1717

18+
import qualified Control.Concurrent.MVar as MVar
1819
import qualified Control.Concurrent.Supply as Supply
1920

2021
defaultTests :: [FilePath]
@@ -57,6 +58,7 @@ runNormalisationStage
5758
-> IO (ClashEnv, ClashDesign, Id)
5859
runNormalisationStage idirs src = do
5960
supplyN <- Supply.newSupply
61+
lock <- MVar.newMVar ()
6062
(env, design) <- runInputStage idirs src
6163
let topEntityNames = fmap topId (designEntities design)
6264
let topEntity = head topEntityNames
@@ -65,5 +67,6 @@ runNormalisationStage idirs src = do
6567
(ghcTypeToHWType (opt_intWidth (opts idirs)))
6668
ghcEvaluator
6769
evaluator
70+
lock
6871
topEntityNames supplyN topEntity
6972
return (env, design{designBindings=transformedBindings},topEntity)

benchmark/profiling/run/profile-normalization-run.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Clash.GHC.PartialEval
77
import Clash.GHC.Evaluator
88
import Clash.GHC.NetlistTypes (ghcTypeToHWType)
99

10+
import qualified Control.Concurrent.MVar as MVar
1011
import qualified Control.Concurrent.Supply as Supply
1112
import Control.DeepSeq (deepseq)
1213
import Data.Binary (decode)
@@ -32,6 +33,7 @@ main = do
3233
benchFile :: [FilePath] -> FilePath -> IO ()
3334
benchFile idirs src = do
3435
supplyN <- Supply.newSupply
36+
lock <- MVar.newMVar ()
3537
(bindingsMap,tcm,tupTcm,primMap,reprs,topEntityNames,topEntity) <- setupEnv src
3638
putStrLn $ "Doing normalization of " ++ src
3739

@@ -47,6 +49,7 @@ benchFile idirs src = do
4749
(ghcTypeToHWType (opt_intWidth (envOpts clashEnv)))
4850
ghcEvaluator
4951
evaluator
52+
lock
5053
topEntityNames supplyN topEntity
5154
res `deepseq` putStrLn ".. done\n"
5255

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CHANGED: Add concurrent normalization flag [#2074](https://github.com/clash-lang/clash-compiler/pull/2074)

clash-ghc/clash-ghc.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ executable clash
7777
executable clashi
7878
Main-Is: src-ghc/Interactive.hs
7979
Build-Depends: base, clash-ghc
80-
GHC-Options: -Wall -Wcompat -rtsopts -with-rtsopts=-A128m
80+
GHC-Options: -Wall -Wcompat -threaded -rtsopts -with-rtsopts=-A128m
8181
if flag(dynamic)
8282
GHC-Options: -dynamic
8383
extra-libraries: pthread

clash-ghc/src-ghc/Clash/GHC/ClashFlags.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ flagsClash r = [
8989
, defFlag "fclash-inline-workfree-limit" $ IntSuffix (liftEwM . setInlineWFLimit r)
9090
, defFlag "fclash-edalize" $ NoArg (liftEwM (setEdalize r))
9191
, defFlag "fclash-no-render-enums" $ NoArg (liftEwM (setNoRenderEnums r))
92+
, defFlag "fclash-concurrent-normalization" $ NoArg (liftEwM (setConcurrentNormalization r))
9293
]
9394

9495
-- | Print deprecated flag warning
@@ -313,6 +314,9 @@ setAggressiveXOptBB r = modifyIORef r (\c -> c { opt_aggressiveXOptBB = True })
313314
setEdalize :: IORef ClashOpts -> IO ()
314315
setEdalize r = modifyIORef r (\c -> c { opt_edalize = True })
315316

317+
setConcurrentNormalization :: IORef ClashOpts -> IO ()
318+
setConcurrentNormalization r = modifyIORef r (\c -> c { opt_concurrentNormalization = True })
319+
316320
setRewriteHistoryFile :: IORef ClashOpts -> String -> IO ()
317321
setRewriteHistoryFile r arg = do
318322
let fileNm = case drop (length "-fclash-debug-history=") arg of

clash-lib/clash-lib.cabal

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ Library
130130
aeson-pretty >= 0.8 && < 0.9,
131131
ansi-terminal >= 0.8.0.0 && < 0.12,
132132
array,
133-
async >= 2.2.0 && < 2.3,
134133
attoparsec >= 0.10.4.0 && < 0.15,
135134
base >= 4.11 && < 5,
136135
base16-bytestring >= 0.1.1 && < 1.1,
@@ -155,6 +154,10 @@ Library
155154
hint >= 0.7 && < 0.10,
156155
interpolate >= 0.2.0 && < 1.0,
157156
lens >= 4.10 && < 5.1.0,
157+
lifted-async >=0.10 && <0.11,
158+
lifted-base >=0.2 && <0.3,
159+
lockfree-queue >=0.2 && <0.3,
160+
monad-control >=1.0 && <1.1,
158161
mtl >= 2.1.2 && < 2.3,
159162
ordered-containers >= 0.2 && < 0.3,
160163
prettyprinter >= 1.2.0.1 && < 1.8,
@@ -166,6 +169,7 @@ Library
166169
text >= 1.2.2 && < 2.1,
167170
time >= 1.4.0.1 && < 1.14,
168171
transformers >= 0.5.2.0 && < 0.7,
172+
transformers-base,
169173
trifecta >= 1.7.1.1 && < 2.2,
170174
vector >= 0.11 && < 1.0,
171175
vector-binary-instances >= 0.2.3.5 && < 0.3,

clash-lib/src/Clash/Core/PartialEval/Monad.hs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{-|
2-
Copyright : (C) 2020-2021, QBayLogic B.V.
2+
Copyright : (C) 2020-2022, QBayLogic B.V.
33
License : BSD2 (see the file LICENSE)
44
Maintainer : QBayLogic B.V. <[email protected]>
55
@@ -84,7 +84,7 @@ import Clash.Core.Util (mkUniqSystemId, mkUniqSystemTyVar)
8484
import Clash.Core.Var (Id, TyVar, Var)
8585
import Clash.Core.VarEnv
8686
import Clash.Driver.Types (Binding(..))
87-
import Clash.Rewrite.WorkFree (isWorkFree)
87+
import Clash.Rewrite.WorkFree (isWorkFreePure)
8888

8989
{-
9090
NOTE [RWS monad]
@@ -311,7 +311,11 @@ workFreeValue :: Value -> Eval Bool
311311
workFreeValue = \case
312312
VNeutral _ -> pure False
313313
VThunk x _ -> do
314-
bindings <- fmap (fmap asTerm) . genvBindings <$> getGlobalEnv
315-
isWorkFree workFreeCache bindings x
314+
env <- getGlobalEnv
315+
let bindings = fmap (fmap asTerm) (genvBindings env)
316+
let (cache, wf) = isWorkFreePure (genvWorkCache env) bindings x
317+
318+
modifyGlobalEnv (\genv -> genv { genvWorkCache = cache })
319+
pure wf
316320

317321
_ -> pure True

clash-lib/src/Clash/Core/PartialEval/NormalForm.hs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{-|
2-
Copyright : (C) 2020-2021, QBayLogic B.V.,
3-
2022 , Google Inc.
2+
Copyright : (C) 2020-2022, QBayLogic B.V.
43
License : BSD2 (see the file LICENSE)
54
Maintainer : QBayLogic B.V. <[email protected]>
65
@@ -29,11 +28,9 @@ module Clash.Core.PartialEval.NormalForm
2928
, Normal(..)
3029
, LocalEnv(..)
3130
, GlobalEnv(..)
32-
, workFreeCache
3331
) where
3432

3533
import Control.Concurrent.Supply (Supply)
36-
import Control.Lens (Lens', lens)
3734
import Data.IntMap.Strict (IntMap)
3835
import Data.Map.Strict (Map)
3936

@@ -201,6 +198,3 @@ data GlobalEnv = GlobalEnv
201198
-- ^ Cache for the results of isWorkFree. This is required to use
202199
-- Clash.Rewrite.WorkFree.isWorkFree.
203200
}
204-
205-
workFreeCache :: Lens' GlobalEnv (VarEnv Bool)
206-
workFreeCache = lens genvWorkCache (\env x -> env { genvWorkCache = x })

clash-lib/src/Clash/Core/VarEnv.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ module Clash.Core.VarEnv
3838
-- ** Conversions
3939
-- *** Lists
4040
, eltsVarEnv
41+
, toListVarEnv
42+
, listToVarEnv
4143
-- * Sets of variables
4244
, VarSet
4345
-- ** Construction
4446
, emptyVarSet
4547
, unitVarSet
4648
-- ** Modification
49+
, extendVarSet
4750
, delVarSetByKey
4851
, unionVarSet
4952
, differenceVarSet
@@ -260,6 +263,15 @@ eltsVarEnv
260263
-> [a]
261264
eltsVarEnv = eltsUniqMap
262265

266+
toListVarEnv :: VarEnv a -> [(Unique, a)]
267+
toListVarEnv = toListUniqMap
268+
269+
listToVarEnv
270+
:: Uniquable a
271+
=> [(a, b)]
272+
-> VarEnv b
273+
listToVarEnv = listToUniqMap
274+
263275
-- | Does the variable exist in the environment
264276
elemVarEnv
265277
:: Var a

clash-lib/src/Clash/Debug.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
module Clash.Debug
44
( debugIsOn
55
, traceIf
6+
, traceWhen
67
, module Debug.Trace
78
) where
89

@@ -19,4 +20,9 @@ debugIsOn = False
1920
traceIf :: Bool -> String -> a -> a
2021
traceIf True msg = trace msg
2122
traceIf False _ = id
23+
24+
traceWhen :: Monad m => Bool -> String -> m ()
25+
traceWhen True = traceM
26+
traceWhen False = const (pure ())
27+
2228
{-# INLINE traceIf #-}

clash-lib/src/Clash/Driver.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
module Clash.Driver where
2323

2424
import Control.Concurrent (MVar, modifyMVar, modifyMVar_, newMVar, withMVar)
25-
import Control.Concurrent.Async (mapConcurrently_)
25+
import Control.Concurrent.Async.Lifted (mapConcurrently_)
2626
import qualified Control.Concurrent.Supply as Supply
2727
import Control.DeepSeq
2828
import Control.Exception (throw)
@@ -443,7 +443,7 @@ generateHDL env design hdlState typeTrans peEval eval mainTopEntity startTime =
443443
-- 2. Normalize topEntity
444444
supplyN <- Supply.newSupply
445445
transformedBindings <- normalizeEntity env bindingsMap typeTrans peEval
446-
eval topEntityNames supplyN topEntity
446+
eval ioLockV topEntityNames supplyN topEntity
447447

448448
normTime <- transformedBindings `deepseq` Clock.getCurrentTime
449449
let prepNormDiff = reportTimeDiff normTime prevTime
@@ -1063,21 +1063,23 @@ normalizeEntity
10631063
-- ^ Hardcoded evaluator for partial evaluation
10641064
-> WHNF.Evaluator
10651065
-- ^ Hardcoded evaluator for WHNF (old evaluator)
1066+
-> MVar ()
1067+
-- ^ Synchronization for stdout
10661068
-> [Id]
10671069
-- ^ TopEntities
10681070
-> Supply.Supply
10691071
-- ^ Unique supply
10701072
-> Id
10711073
-- ^ root of the hierarchy
10721074
-> IO BindingMap
1073-
normalizeEntity env bindingsMap typeTrans peEval eval topEntities supply tm = transformedBindings
1075+
normalizeEntity env bindingsMap typeTrans peEval eval lock topEntities supply tm = transformedBindings
10741076
where
10751077
doNorm = do norm <- normalize [tm]
10761078
let normChecked = checkNonRecursive norm
10771079
cleaned <- cleanupGraph tm normChecked
10781080
return cleaned
10791081
transformedBindings = runNormalization env supply bindingsMap
1080-
typeTrans peEval eval emptyVarEnv
1082+
typeTrans peEval eval emptyVarEnv lock
10811083
topEntities doNorm
10821084

10831085
-- | topologically sort the top entities

0 commit comments

Comments
 (0)