Probe.hs (3144B)
1 {-# LANGUAGE BangPatterns #-} 2 {-# OPTIONS_GHC -fno-full-laziness -fno-cse #-} 3 -- Only the harness disables sharing optimizations, not the production runtime. 4 module Main where 5 import Runtime.Tree 6 import Runtime.Value 7 import qualified Data.ByteString as BS 8 import Control.Exception (evaluate) 9 import Control.Monad (foldM, unless) 10 import GHC.Clock (getMonotonicTimeNSec) 11 import System.Environment (getArgs) 12 import System.Exit (die) 13 import Text.Printf (printf) 14 15 now :: IO Double 16 now = (/1e9) . fromIntegral <$> getMonotonicTimeNSec 17 18 data Suspended = Suspended T 19 {-# OPAQUE suspend #-} 20 suspend :: T -> T -> Suspended 21 suspend f x = Suspended (apply f x) 22 23 force :: T -> () 24 force Leaf = () 25 force (Stem x) = force x 26 force (Fork x y) = force x `seq` force y 27 28 check :: IO () 29 check = do 30 let a = Stem (Stem Leaf); b = Fork Leaf (Stem Leaf) 31 identity = Fork (Stem (Stem Leaf)) (Stem Leaf) 32 cases = [ (apply Leaf a, Stem a), (apply (Stem a) b, Fork a b) 33 , (apply (Fork Leaf a) (error "discard forced"), a) 34 , (apply identity b, b) 35 , (apply (Fork (Fork a b) Leaf) Leaf, a) 36 , (apply (Fork (Fork a b) Leaf) (Stem Leaf), apply b Leaf) 37 , (apply (Fork (Fork a b) identity) (Fork a b), apply (apply identity a) b)] 38 mapM_ (\(actual, expected) -> unless (actual == expected) (die "reduction mismatch")) cases 39 _ <- evaluate (suspend (error "construction forced function") Leaf) 40 unless (toBytes (Fork (ofNumber 256) Leaf) == Left "Byte value out of range: 256") 41 (die "invalid byte accepted") 42 putStrLn "checks passed" 43 44 iteration :: String -> Int -> Int -> IO (Double, Double, Double) 45 iteration kind n roundNo = do 46 let bytes = BS.pack [fromIntegral (97 + (j+roundNo) `mod` 26) | j <- [0..n-1]] 47 _ <- evaluate (BS.length bytes) 48 start <- now 49 Suspended term <- if kind == "codec" then do 50 let input = ofBytes bytes 51 _ <- evaluate (force input) 52 evaluate (suspend (Fork (Stem (Stem Leaf)) (Stem Leaf)) input) 53 else foldM (\(Suspended previous) _ -> evaluate $ 54 if kind == "deep" then suspend (Fork Leaf previous) Leaf 55 else suspend (Fork (Stem (Stem Leaf)) (Stem Leaf)) previous) 56 (Suspended Leaf) [1..n] 57 built <- now 58 result <- evaluate term 59 reduced <- now 60 valid <- evaluate $ if kind == "codec" then toBytes result == Right bytes 61 else case result of Leaf -> True; _ -> False 62 unless valid (die "incorrect complete result") 63 observed <- now 64 pure (built-start, reduced-built, observed-reduced) 65 66 main :: IO () 67 main = do 68 args <- getArgs 69 case args of 70 ["check"] -> check 71 [kind, size, count] | kind `elem` ["codec", "deep", "distribution"] -> do 72 let n = read size; rounds = read count 73 unless (n > 0 && rounds > 0) (die "positive sizes required") 74 (!b,!r,!o) <- foldM (\(!b,!r,!o) i -> do 75 (b',r',o') <- iteration kind n i 76 pure (b+b',r+r',o+o')) (0,0,0) [0..rounds-1] 77 printf "{\"kind\":\"%s\",\"n\":%d,\"rounds\":%d,\"build_s\":%.9f,\"reduce_s\":%.9f,\"observe_s\":%.9f}\n" kind n rounds b r o 78 _ -> die "usage: probe check | codec|deep|distribution SIZE ROUNDS"