0 | module Profile.Runner
2 | import Data.Refined.Integer
5 | import Profile.Statistics
10 | %foreign "scheme,chez:(lambda () (collect (collect-maximum-generation)))"
11 | "javascript:lambda:(w) => {}"
12 | prim__collect : PrimIO ()
14 | unitFor : Integer -> String
23 | nonSec : (sig,exp : Integer) -> String -> String
30 | pre := show $
sig `div` factor
31 | post := padLeft pad '0' . show $
sig `mod` factor
32 | in "\{pre}.\{post} \{s}"
34 | printPos : Integer -> String
35 | printPos n = case lte 1000 n of
36 | Nothing0 => padLeft 8 ' ' "\{show n} as"
38 | let (n',exp) := significant n 4 @{weak [0,1000,n]}
39 | exp' := cast {to = Integer} exp
40 | in case unitFor (exp' `div` 3) of
41 | "s" => case exp `minus` 18 of
43 | e => "\{show n'}e\{show e} s"
44 | u => nonSec n' exp' u
46 | printAtto : AttoSecondsPerRun -> String
47 | printAtto (MkScalar v) = if v < 0 then "-" ++ printPos v else printPos v
51 | runs = go 600 [< 1] 1 1.0
54 | go : Nat -> SnocList Pos -> Pos -> Double -> List Pos
55 | go 0 sx p x = sx <>> Nil
58 | n2@(S _) = cast nx | 0 => go k sx p nx
60 | in go k (if p2.val > p.val then sx :< p2 else sx) p2 nx
64 | run : Pos -> Benchmarkable err -> IO (Either err Measured)
65 | run p (MkBenchmarkable alloc clean go cpuonly) = do
67 | fromPrim prim__collect
68 | start <- clockTime Monotonic
69 | startCPU <- clockTime Process
71 | stopCPU <- clockTime Process
72 | stop <- clockTime Monotonic
75 | let tot := timeDelta start stop
76 | cpu := timeDelta startCPU stopCPU
77 | runs := the Runs $
MkScalar $
cast p.val
84 | , avrgTime = tot `div` runs
86 | , avrgCPU = cpu `div` runs
90 | Left err => pure (Left err)
91 | Right v => pure (Right meas)
94 | threshold : AttoSeconds
95 | threshold = fromMilliSeconds 30
98 | threshold10 : AttoSeconds
99 | threshold10 = fromMilliSeconds 300
105 | runBenchmark : (timeLimit : AttoSeconds)
106 | -> Benchmarkable err
107 | -> IO (Either err $
List Measured)
108 | runBenchmark timeLimit b = do
109 | startTime <- clockTime Monotonic
110 | fromPrim $
go Lin runs startTime 0 0
116 | -> (startTime : Clock Monotonic)
117 | -> (overThreshold : AttoSeconds)
119 | -> PrimIO (Either err $
List Measured)
120 | go sr [] st ot nr w = MkIORes (Right $
sr <>> Nil) w
121 | go sr (p :: ps) st ot nr w =
122 | let MkIORes (Right r) w2 := toPrim (run p b) w
123 | | MkIORes (Left err) w2 => MkIORes (Left err) w2
124 | diffThreshold := max 0 $
r.totalTime `minus` threshold
125 | overThreshold := ot `plus` diffThreshold
126 | tot := fromClock $
timeDifference r.stopTime st
128 | tot >= timeLimit &&
129 | overThreshold >= threshold10 &&
132 | in if done then MkIORes (Right (sr <>> [r])) w2
133 | else go (sr :< r) ps st overThreshold (S nr) w2
135 | detailStats : Nat -> String -> Stats -> String
136 | detailStats k name stats = """
137 | # \{show k}: \{name}
138 | time per run : \{printAtto stats.slope}
139 | mean : \{printAtto stats.mean}
140 | r2 : \{show stats.r2}
145 | tableStats : Nat -> String -> Stats -> String
146 | tableStats k name stats =
147 | let nm := padRight 50 ' ' name
148 | tpr := padLeft 10 ' ' $
printAtto stats.slope
149 | mean := padLeft 10 ' ' $
printAtto stats.mean
150 | r2 := pack $
take 5 $
unpack $
show stats.r2
151 | in "\{nm} \{tpr} \{mean} \{r2}"
153 | showStats : Format -> Nat -> String -> Stats -> String
154 | showStats Table = tableStats
155 | showStats Details = detailStats
161 | -> Benchmarkable err
162 | -> IO (Either err ())
163 | runAndPrint format k name b = do
164 | Right (h :: t) <- runBenchmark (fromSeconds 1) b
165 | | Right [] => pure (Right ())
166 | | Left err => pure (Left err)
168 | putStrLn (showStats format k name $
regr (h :: fromList t))
174 | -> (Nat -> String -> Benchmarkable err -> IO (Either err ()))
175 | -> IO (Either err ())
176 | for select b f = ignore <$> fromPrim (go 1 "" b)
179 | many : Nat -> String -> List (Benchmark err) -> PrimIO (Either err Nat)
181 | go : Nat -> String -> Benchmark err -> PrimIO (Either err Nat)
182 | go k s (Single name bench) w =
183 | let s' := addPrefix s name
186 | let MkIORes (Right _) w2 := toPrim (f k s' bench) w
187 | | MkIORes (Left err) w2 => MkIORes (Left err) w2
188 | in MkIORes (Right $
S k) w2
189 | else MkIORes (Right k) w
190 | go k s (Group name benchs) w = many k (addPrefix s name) benchs w
192 | many k s [] w = MkIORes (Right k) w
193 | many k s (b :: bs) w =
194 | let MkIORes (Right k2) w2 = go k s b w
195 | | MkIORes (Left err) w2 => MkIORes (Left err) w2
205 | runDefault select format showErr b = do
206 | Left err <- for select b (runAndPrint format)
207 | | Right () => pure ()
208 | putStrLn (showErr err)