Experiment with parallel grammar checks

Introduced the function

	parallelCheck :: [Check a] -> Check [a]

that runs independent checks in parallel, potentially allowing faster grammar
compilation on multi-core computers, if you run gf with +RTS -N.

However, on my dual core laptop, this seems to slow down compilation somewhat
even though CPU utilization goes up as high as 170% at times.
(This is with GF compiled with GHC 7.0.4.)
This commit is contained in:
hallgren
2012-06-26 17:01:15 +00:00
parent 82a5c574b6
commit 241bef8a51
3 changed files with 27 additions and 9 deletions

View File

@@ -108,7 +108,9 @@ executable gf
process, process,
pretty, pretty,
mtl, mtl,
haskeline haskeline,
parallel
ghc-options: -threaded
if flag(server) if flag(server)
build-depends: httpd-shed, network, silently, utf8-string, json, cgi build-depends: httpd-shed, network, silently, utf8-string, json, cgi
cpp-options: -DSERVER_MODE cpp-options: -DSERVER_MODE

View File

@@ -56,11 +56,9 @@ checkModule opts mos mo@(m,mi) = do
infoss <- checkErr $ topoSortJments2 mo infoss <- checkErr $ topoSortJments2 mo
foldM updateCheckInfos mo infoss foldM updateCheckInfos mo infoss
where where
updateCheckInfos mo0 = commitCheck . foldM updateCheckInfo mo0 updateCheckInfos mo = fmap (foldl update mo) . parallelCheck . map check
where check (i,info) = fmap ((,) i) (checkInfo opts mos mo i info)
updateCheckInfo mo@(m,mi) (i,info) = do update mo@(m,mi) (i,info) = (m,mi{jments=updateTree (i,info) (jments mi)})
info <- accumulateError (checkInfo opts mos mo i) info
return (m,mi{jments=updateTree (i,info) (jments mi)})
-- check if restricted inheritance modules are still coherent -- check if restricted inheritance modules are still coherent
-- i.e. that the defs of remaining names don't depend on omitted names -- i.e. that the defs of remaining names don't depend on omitted names

View File

@@ -16,7 +16,7 @@ module GF.Infra.CheckM
(Check, CheckResult, Message, runCheck, (Check, CheckResult, Message, runCheck,
checkError, checkCond, checkWarn, checkWarnings, checkAccumError, checkError, checkCond, checkWarn, checkWarnings, checkAccumError,
checkErr, checkIn, checkMap, checkMapRecover, checkErr, checkIn, checkMap, checkMapRecover,
accumulateError, commitCheck parallelCheck, accumulateError, commitCheck,
) where ) where
import GF.Data.Operations import GF.Data.Operations
@@ -26,6 +26,8 @@ import GF.Grammar.Printer
import qualified Data.Map as Map import qualified Data.Map as Map
import Text.PrettyPrint import Text.PrettyPrint
import Control.Parallel.Strategies(parList,rseq,using)
import Control.Monad(liftM)
type Message = Doc type Message = Doc
type Error = Message type Error = Message
@@ -38,6 +40,8 @@ data CheckResult a = Fail Error | Success a
newtype Check a newtype Check a
= Check {unCheck :: {-Context ->-} Accumulate NonFatal (CheckResult a)} = Check {unCheck :: {-Context ->-} Accumulate NonFatal (CheckResult a)}
instance Functor Check where fmap = liftM
instance Monad Check where instance Monad Check where
return x = Check $ \{-ctxt-} ws -> (ws,Success x) return x = Check $ \{-ctxt-} ws -> (ws,Success x)
f >>= g = Check $ \{-ctxt-} ws -> f >>= g = Check $ \{-ctxt-} ws ->
@@ -98,14 +102,28 @@ runCheck c =
bad (es,ws) = Bad (render $ list ws $$ list es) bad (es,ws) = Bad (render $ list ws $$ list es)
list = vcat . reverse list = vcat . reverse
parallelCheck :: [Check a] -> Check [a]
parallelCheck cs =
Check $ \ {-ctxt-} (es0,ws0) ->
let os = [unCheck c {-[]-} ([],[])|c<-cs] `using` parList rseq
(msgs1,crs) = unzip os
(ess,wss) = unzip msgs1
rs = [r | Success r<-crs]
fs = [f | Fail f<-crs]
msgs = (concat ess++es0,concat wss++ws0)
in if null fs
then (msgs,Success rs)
else (msgs,Fail (vcat $ reverse fs))
checkMap :: (Ord a) => (a -> b -> Check b) -> Map.Map a b -> Check (Map.Map a b) checkMap :: (Ord a) => (a -> b -> Check b) -> Map.Map a b -> Check (Map.Map a b)
checkMap f map = do xs <- mapM (\(k,v) -> do v <- f k v checkMap f map = do xs <- mapM (\(k,v) -> do v <- f k v
return (k,v)) (Map.toList map) return (k,v)) (Map.toList map)
return (Map.fromAscList xs) return (Map.fromAscList xs)
checkMapRecover :: (Ord a) => (a -> b -> Check b) -> Map.Map a b -> Check (Map.Map a b) checkMapRecover :: (Ord a) => (a -> b -> Check b) -> Map.Map a b -> Check (Map.Map a b)
checkMapRecover f mp = commitCheck (checkMap f' mp) checkMapRecover f = fmap Map.fromList . parallelCheck . map f' . Map.toList
where f' key info = accumulateError (f key) info where f' (k,v) = fmap ((,)k) (f k v)
{- {-
checkMapRecover f mp = do checkMapRecover f mp = do
let xs = map (\ (k,v) -> (k,runCheck (f k v))) (Map.toList mp) let xs = map (\ (k,v) -> (k,runCheck (f k v))) (Map.toList mp)