|  | 
|  | 1 | +{-# LANGUAGE LinearTypes #-} | 
|  | 2 | +{-# LANGUAGE AllowAmbiguousTypes #-} | 
|  | 3 | +{-# LANGUAGE BangPatterns #-} | 
|  | 4 | +{-# LANGUAGE DataKinds #-} | 
|  | 5 | +{-# LANGUAGE FlexibleContexts #-} | 
|  | 6 | +{-# LANGUAGE ImpredicativeTypes #-} | 
|  | 7 | +{-# LANGUAGE KindSignatures #-} | 
|  | 8 | +{-# LANGUAGE LinearTypes #-} | 
|  | 9 | +{-# LANGUAGE RankNTypes #-} | 
|  | 10 | +{-# LANGUAGE ScopedTypeVariables #-} | 
|  | 11 | +{-# LANGUAGE TypeApplications #-} | 
|  | 12 | +{-# OPTIONS_GHC -Wno-name-shadowing -Wno-x-partial #-} | 
|  | 13 | + | 
|  | 14 | +module Bench.Utils where | 
|  | 15 | + | 
|  | 16 | +import Control.DeepSeq | 
|  | 17 | +import Test.Tasty (TestTree, testGroup) | 
|  | 18 | +import Test.Tasty.HUnit (testCaseInfo, assertEqual) | 
|  | 19 | +import Test.Tasty.Bench | 
|  | 20 | +import Control.Exception (evaluate) | 
|  | 21 | +import Data.Functor ((<&>)) | 
|  | 22 | +import GHC.Compact (compact, getCompact) | 
|  | 23 | + | 
|  | 24 | +safetySameAsFirstImpl :: forall m a r. (Show r, Eq r) => [(a %m -> r, String, Bool)] -> [(IO a, String)] -> IO TestTree | 
|  | 25 | +safetySameAsFirstImpl impls datasets = do | 
|  | 26 | +  let ((refImpl, refImplName, _):otherImpls) = impls | 
|  | 27 | +  testGroup "safety" <$> (sequence $ | 
|  | 28 | +    datasets <&> \(loadSampleData, sizeName) -> do | 
|  | 29 | +      sampleData <- loadSampleData | 
|  | 30 | +      return $ testGroup sizeName $ otherImpls <&> \(impl, implName, _) -> | 
|  | 31 | +          testCaseInfo (refImplName ++ " and " ++ implName ++ " give the same result") $ do | 
|  | 32 | +            let expected = refImpl sampleData | 
|  | 33 | +                actual = impl sampleData | 
|  | 34 | +            assertEqual "same result" expected actual | 
|  | 35 | +            return "") | 
|  | 36 | + | 
|  | 37 | +benchImpls :: forall m a r. (NFData r) => [(a %m -> r, String, Bool)] -> [(IO a, String)] -> IO Benchmark | 
|  | 38 | +benchImpls impls datasets = do | 
|  | 39 | +  bgroup "benchmark" <$> (sequence $ | 
|  | 40 | +    datasets <&> \(loadSampleData, sizeName) -> do | 
|  | 41 | +      sampleData <- loadSampleData | 
|  | 42 | +      return $ testGroup sizeName $ concat $ impls <&> \(impl, implName, isLazy) -> if isLazy | 
|  | 43 | +          then | 
|  | 44 | +            [ bench (implName ++ ".force") $ (flip whnfAppIO) sampleData $ \sampleData -> evaluate $ force $ impl sampleData, | 
|  | 45 | +              bench (implName ++ ".copyIntoReg") $ (flip whnfAppIO) sampleData $ \sampleData -> do | 
|  | 46 | +                    resInRegion <- compact $ impl sampleData | 
|  | 47 | +                    evaluate $ getCompact $ resInRegion | 
|  | 48 | +            ] | 
|  | 49 | +          else | 
|  | 50 | +            [ bench implName $ (flip whnfAppIO) sampleData $ \sampleData -> evaluate $ impl sampleData ]) | 
|  | 51 | + | 
|  | 52 | +launchImpl :: forall m a r. (NFData r) => String -> [(a %m -> r, String, Bool)] -> [(IO a, String)] -> IO () | 
|  | 53 | +launchImpl requestedImplDataSetspec impls datasets = go impls (go' datasets) where | 
|  | 54 | +  (requestedSize, dotRequestedImplSpec) = span (/= '.') requestedImplDataSetspec | 
|  | 55 | +  (requestedImplRadical, requestedImplVariant) = span (/= '.') (tail dotRequestedImplSpec) | 
|  | 56 | +  go [] _ = error ("requested implementation '" ++ requestedImplRadical ++ "' not found") | 
|  | 57 | +  go ((impl, implName, isLazy):_) loadSampleData | implName == requestedImplRadical = do | 
|  | 58 | +    sampleData <- loadSampleData | 
|  | 59 | +    if isLazy | 
|  | 60 | +      then case requestedImplVariant of | 
|  | 61 | +        ".force" -> evaluate $ rwhnf $ force $ impl sampleData | 
|  | 62 | +        ".copyIntoReg" -> do | 
|  | 63 | +          resInRegion <- compact $ impl sampleData | 
|  | 64 | +          evaluate $ rwhnf $ getCompact $ resInRegion | 
|  | 65 | +        _ -> error ("variant '" ++ requestedImplVariant ++ "' not found (required for lazy impl)") | 
|  | 66 | +    else | 
|  | 67 | +      evaluate $ rwhnf $ impl sampleData | 
|  | 68 | +    putStrLn "Done!" | 
|  | 69 | +  go (_:xs) loadSampleData = go xs loadSampleData | 
|  | 70 | + | 
|  | 71 | +  go' [] = error ("requested size '" ++ requestedSize ++ "' not found") | 
|  | 72 | +  go' ((loadSampleData, sizeName):_) | sizeName == requestedSize = loadSampleData | 
|  | 73 | +  go' (_:xs) = go' xs | 
|  | 74 | + | 
|  | 75 | +{-# LANGUAGE AllowAmbiguousTypes #-} | 
|  | 76 | +{-# LANGUAGE BangPatterns #-} | 
|  | 77 | +{-# LANGUAGE BlockArguments #-} | 
|  | 78 | +{-# LANGUAGE DataKinds #-} | 
|  | 79 | +{-# LANGUAGE FlexibleContexts #-} | 
|  | 80 | +{-# LANGUAGE ImpredicativeTypes #-} | 
|  | 81 | +{-# LANGUAGE KindSignatures #-} | 
|  | 82 | +{-# LANGUAGE LinearTypes #-} | 
|  | 83 | +{-# LANGUAGE RankNTypes #-} | 
|  | 84 | +{-# LANGUAGE ScopedTypeVariables #-} | 
|  | 85 | +{-# LANGUAGE TypeApplications #-} | 
|  | 86 | +{-# OPTIONS_GHC -Wno-x-partial #-} | 
|  | 87 | + | 
|  | 88 | +module Main (main) where | 
|  | 89 | + | 
|  | 90 | +import System.Environment | 
|  | 91 | +import Test.Tasty.Bench | 
|  | 92 | +import qualified Bench.Map as Map | 
|  | 93 | +import qualified Bench.TreeTraversal as TreeTraversal | 
|  | 94 | +import qualified Bench.DList as DList | 
|  | 95 | +import qualified Bench.Queue as Queue | 
|  | 96 | +import qualified Bench.Parser as Parser | 
|  | 97 | +import qualified Bench.Utils as Utils | 
|  | 98 | + | 
|  | 99 | +-- run with | 
|  | 100 | +-- cabal bench -w $(pwd)/ghc@580d39a221/bin/ghc --allow-newer linear-dest:bench:bench --benchmark-options='+RTS -T -N1 -RTS' | 
|  | 101 | +-- run in isolation with | 
|  | 102 | +-- cabal run -w $(pwd)/ghc@580d39a221/bin/ghc -v0 linear-dest:bench:bench -- -l | grep -P 'All\.[^\.]+\.benchmark\.' | while read -r name; do cabal run -w $(pwd)/ghc@580d39a221/bin/ghc -v0 linear-dest:bench:bench -- -p '$0 == "'"$name"'"' +RTS -T -N1 -RTS; done | 
|  | 103 | + | 
|  | 104 | +launchImpl :: String -> IO () | 
|  | 105 | +launchImpl s = | 
|  | 106 | +  let (_all, dotModuleName) = span (/= '.') s | 
|  | 107 | +      (moduleName, dotBenchmark) = span (/= '.') (tail dotModuleName) | 
|  | 108 | +      (_benchmark, dotImplSizeSpec) = span (/= '.') (tail dotBenchmark) | 
|  | 109 | +      implSizeSpec = tail dotImplSizeSpec | 
|  | 110 | +   in case (_all ++ "." ++ moduleName ++ "." ++ _benchmark) of | 
|  | 111 | +        "All.Map.benchmark" -> Utils.launchImpl implSizeSpec Map.impls Map.dataSets | 
|  | 112 | +        "All.TreeTraversal.benchmark" -> Utils.launchImpl implSizeSpec TreeTraversal.impls TreeTraversal.dataSets | 
|  | 113 | +        "All.DList.benchmark" -> Utils.launchImpl implSizeSpec DList.impls DList.dataSets | 
|  | 114 | +        "All.Queue.benchmark" -> Utils.launchImpl implSizeSpec Queue.impls Queue.dataSets | 
|  | 115 | +        "All.Parser.benchmark" -> Utils.launchImpl implSizeSpec Parser.impls Parser.dataSets | 
|  | 116 | +        _ -> launchAllBenchs | 
|  | 117 | + | 
|  | 118 | +launchAllBenchs :: IO () | 
|  | 119 | +launchAllBenchs = do | 
|  | 120 | +  mapBenchgroup <- bgroup "Map" <$> sequence [ Utils.benchImpls Map.impls Map.dataSets, Utils.safetySameAsFirstImpl Map.impls Map.dataSets ] | 
|  | 121 | +  treetraversalBenchgroup <- bgroup "TreeTraversal" <$> sequence [ Utils.benchImpls TreeTraversal.impls TreeTraversal.dataSets, Utils.safetySameAsFirstImpl TreeTraversal.impls TreeTraversal.dataSets, TreeTraversal.extraSafety ] | 
|  | 122 | +  dlistBenchgroup <- bgroup "DList" <$> sequence [ Utils.benchImpls DList.impls DList.dataSets, Utils.safetySameAsFirstImpl DList.impls DList.dataSets ] | 
|  | 123 | +  queueBenchgroup <- bgroup "Queue" <$> sequence [ Utils.benchImpls Queue.impls Queue.dataSets, Utils.safetySameAsFirstImpl Queue.impls Queue.dataSets ] | 
|  | 124 | +  parserBenchgroup <- bgroup "Parser" <$> sequence [ Utils.benchImpls Parser.impls Parser.dataSets, Utils.safetySameAsFirstImpl Parser.impls Parser.dataSets, Parser.extraSafety ] | 
|  | 125 | +  defaultMain | 
|  | 126 | +    [ mapBenchgroup, | 
|  | 127 | +      treetraversalBenchgroup, | 
|  | 128 | +      dlistBenchgroup, | 
|  | 129 | +      queueBenchgroup, | 
|  | 130 | +      parserBenchgroup | 
|  | 131 | +    ] | 
|  | 132 | + | 
|  | 133 | +main :: IO () | 
|  | 134 | +main = do | 
|  | 135 | +  args <- getArgs | 
|  | 136 | +  case args of | 
|  | 137 | +    s : _ -> launchImpl s | 
|  | 138 | +    _ -> launchAllBenchs | 
0 commit comments