10
10
system with the following structure:
11
11
12
12
bench-results
13
- ├── <git-reference> - one folder per version
14
- │ ├── <experiment>.benchmark-gcStats - RTS -s output
15
- │ ├── <experiment>.csv - stats for the experiment
16
- │ ├── <experiment>.svg - Graph of bytes over elapsed time
17
- │ ├── <experiment>.diff.svg - idem, including the previous version
18
- │ ├── <experiment>.log - ghcide-bench output
19
- │ ├── ghc.path - path to ghc used to build the binary
20
- │ ├── ghcide - binary for this version
21
- │ └── results.csv - results of all the experiments for the version
13
+ ├── <git-reference>
14
+ │ ├── ghc.path - path to ghc used to build the binary
15
+ │ ├── ghcide - binary for this version
16
+ ├─ <example>
17
+ │ ├── results.csv - aggregated results for all the versions
18
+ │ └── <git-reference>
19
+ │ ├── <experiment>.benchmark-gcStats - RTS -s output
20
+ │ ├── <experiment>.csv - stats for the experiment
21
+ │ ├── <experiment>.svg - Graph of bytes over elapsed time
22
+ │ ├── <experiment>.diff.svg - idem, including the previous version
23
+ │ ├── <experiment>.log - ghcide-bench output
24
+ │ └── results.csv - results of all the experiments for the example
22
25
├── results.csv - aggregated results of all the experiments and versions
23
- ├ ── <experiment>.svg - graph of bytes over elapsed time, for all the included versions
26
+ └ ── <experiment>.svg - graph of bytes over elapsed time, for all the included versions
24
27
25
28
For diff graphs, the "previous version" is the preceding entry in the list of versions
26
29
in the config file. A possible improvement is to obtain this info via `git rev-list`.
35
38
> cabal bench --benchmark-options "bench-results/HEAD/results.csv bench-results/HEAD/edit.diff.svg"
36
39
37
40
-}
41
+ {-# LANGUAGE ApplicativeDo #-}
38
42
{-# LANGUAGE DeriveAnyClass #-}
39
43
{-# LANGUAGE DerivingStrategies#-}
40
44
{-# LANGUAGE TypeFamilies #-}
@@ -49,7 +53,7 @@ import qualified Data.Text as T
49
53
import Data.Yaml ((.!=) , (.:?) , FromJSON (.. ), ToJSON (.. ), Value (.. ), decodeFileThrow )
50
54
import Development.Shake
51
55
import Development.Shake.Classes (Binary , Hashable , NFData )
52
- import Experiments.Types (exampleToOptions , Example (.. ))
56
+ import Experiments.Types (getExampleName , exampleToOptions , Example (.. ))
53
57
import GHC.Exts (IsList (.. ))
54
58
import GHC.Generics (Generic )
55
59
import qualified Graphics.Rendering.Chart.Backend.Diagrams as E
@@ -60,6 +64,7 @@ import System.Directory
60
64
import System.FilePath
61
65
import qualified Text.ParserCombinators.ReadP as P
62
66
import Text.Read (Read (.. ), get , readMaybe , readP_to_Prec )
67
+ import GHC.Stack (HasCallStack )
63
68
64
69
config :: FilePath
65
70
config = " bench/config.yaml"
@@ -68,24 +73,20 @@ config = "bench/config.yaml"
68
73
readConfigIO :: FilePath -> IO Config
69
74
readConfigIO = decodeFileThrow
70
75
76
+ newtype GetExample = GetExample String deriving newtype (Binary , Eq , Hashable , NFData , Show )
77
+ newtype GetExamples = GetExamples () deriving newtype (Binary , Eq , Hashable , NFData , Show )
71
78
newtype GetSamples = GetSamples () deriving newtype (Binary , Eq , Hashable , NFData , Show )
72
-
73
79
newtype GetExperiments = GetExperiments () deriving newtype (Binary , Eq , Hashable , NFData , Show )
74
-
75
80
newtype GetVersions = GetVersions () deriving newtype (Binary , Eq , Hashable , NFData , Show )
76
-
77
81
newtype GetParent = GetParent Text deriving newtype (Binary , Eq , Hashable , NFData , Show )
78
-
79
82
newtype GetCommitId = GetCommitId String deriving newtype (Binary , Eq , Hashable , NFData , Show )
80
83
84
+ type instance RuleResult GetExample = Maybe Example
85
+ type instance RuleResult GetExamples = [Example ]
81
86
type instance RuleResult GetSamples = Natural
82
-
83
87
type instance RuleResult GetExperiments = [Unescaped String ]
84
-
85
88
type instance RuleResult GetVersions = [GitCommit ]
86
-
87
89
type instance RuleResult GetParent = Text
88
-
89
90
type instance RuleResult GetCommitId = String
90
91
91
92
main :: IO ()
@@ -97,12 +98,16 @@ main = shakeArgs shakeOptions {shakeChange = ChangeModtimeAndDigest} $ do
97
98
_ <- addOracle $ \ GetSamples {} -> samples <$> readConfig config
98
99
_ <- addOracle $ \ GetExperiments {} -> experiments <$> readConfig config
99
100
_ <- addOracle $ \ GetVersions {} -> versions <$> readConfig config
101
+ _ <- addOracle $ \ GetExamples {} -> examples <$> readConfig config
100
102
_ <- addOracle $ \ (GetParent name) -> findPrev name . versions <$> readConfig config
103
+ _ <- addOracle $ \ (GetExample name) -> find (\ e -> getExampleName e == name) . examples <$> readConfig config
101
104
102
105
let readVersions = askOracle $ GetVersions ()
103
106
readExperiments = askOracle $ GetExperiments ()
107
+ readExamples = askOracle $ GetExamples ()
104
108
readSamples = askOracle $ GetSamples ()
105
109
getParent = askOracle . GetParent
110
+ getExample = askOracle . GetExample
106
111
107
112
configStatic <- liftIO $ readConfigIO config
108
113
ghcideBenchPath <- ghcideBench <$> liftIO (readConfigIO config)
@@ -112,16 +117,16 @@ main = shakeArgs shakeOptions {shakeChange = ChangeModtimeAndDigest} $ do
112
117
phony " all" $ do
113
118
Config {.. } <- readConfig config
114
119
115
- forM_ versions $ \ ver ->
116
- need [build </> T. unpack (humanName ver) </> " results.csv" ]
117
-
118
120
need $
121
+ [build </> getExampleName e </> " results.csv" | e <- examples ] ++
119
122
[build </> " results.csv" ]
120
- ++ [ build </> escaped (escapeExperiment e) <.> " svg"
123
+ ++ [ build </> getExampleName ex </> escaped (escapeExperiment e) <.> " svg"
121
124
| e <- experiments
125
+ , ex <- examples
122
126
]
123
- ++ [ build </> T. unpack (humanName ver) </> escaped (escapeExperiment e) <.> mode <.> " svg"
127
+ ++ [ build </> getExampleName ex </> T. unpack (humanName ver) </> escaped (escapeExperiment e) <.> mode <.> " svg"
124
128
| e <- experiments,
129
+ ex <- examples,
125
130
ver <- versions,
126
131
mode <- [" " , " diff" ]
127
132
]
@@ -136,7 +141,7 @@ main = shakeArgs shakeOptions {shakeChange = ChangeModtimeAndDigest} $ do
136
141
Stdout commitid <- command [] " git" [" rev-list" , " -n" , " 1" , gitThing]
137
142
writeFileChanged out $ init commitid
138
143
139
- priority 10 $ [build -/- " HEAD/ghcide"
144
+ priority 10 $ [ build -/- " HEAD/ghcide"
140
145
, build -/- " HEAD/ghc.path"
141
146
]
142
147
&%> \ [out, ghcpath] -> do
@@ -159,8 +164,7 @@ main = shakeArgs shakeOptions {shakeChange = ChangeModtimeAndDigest} $ do
159
164
cmd_ [Cwd " bench-temp" ] $ buildGhcide buildSystem (" .." </> takeDirectory out)
160
165
writeFile' ghcpath ghcLoc
161
166
162
- priority 8000 $
163
- build -/- " */results.csv" %> \ out -> do
167
+ build -/- " */*/results.csv" %> \ out -> do
164
168
experiments <- readExperiments
165
169
166
170
let allResultFiles = [takeDirectory out </> escaped (escapeExperiment e) <.> " csv" | e <- experiments]
@@ -173,16 +177,17 @@ main = shakeArgs shakeOptions {shakeChange = ChangeModtimeAndDigest} $ do
173
177
ghcideBenchResource <- newResource " ghcide-bench" 1
174
178
175
179
priority 0 $
176
- [ build -/- " */*.csv" ,
177
- build -/- " */*.benchmark-gcStats" ,
178
- build -/- " */*.log"
180
+ [ build -/- " */*/* .csv" ,
181
+ build -/- " */*/* .benchmark-gcStats" ,
182
+ build -/- " */*/* .log"
179
183
]
180
184
&%> \ [outcsv, _outGc, outLog] -> do
181
- let [_, _, exp ] = splitDirectories outcsv
185
+ let [_, exampleName, ver, exp ] = splitDirectories outcsv
186
+ example <- fromMaybe (error $ " Unknown example " <> exampleName) <$> getExample exampleName
182
187
samples <- readSamples
183
188
liftIO $ createDirectoryIfMissing True $ dropFileName outcsv
184
- let ghcide = dropFileName outcsv </> " ghcide"
185
- ghcpath = dropFileName outcsv </> " ghc.path"
189
+ let ghcide = build </> ver </> " ghcide"
190
+ ghcpath = build </> ver </> " ghc.path"
186
191
need [ghcide, ghcpath]
187
192
ghcPath <- readFile' ghcpath
188
193
withResource ghcideBenchResource 1 $ do
@@ -203,53 +208,66 @@ main = shakeArgs shakeOptions {shakeChange = ChangeModtimeAndDigest} $ do
203
208
" --select" ,
204
209
unescaped (unescapeExperiment (Escaped $ dropExtension exp ))
205
210
] ++
206
- exampleToOptions ( example configStatic) ++
211
+ exampleToOptions example ++
207
212
[ " --stack" | Stack == buildSystem]
208
213
cmd_ Shell $ " mv *.benchmark-gcStats " <> dropFileName outcsv
209
214
210
215
build -/- " results.csv" %> \ out -> do
211
- versions <- readVersions
212
- let allResultFiles =
213
- [build </> T. unpack (humanName v) </> " results.csv" | v <- versions]
216
+ examples <- map getExampleName <$> readExamples
217
+ let allResultFiles = [build </> e </> " results.csv" | e <- examples]
218
+
219
+ allResults <- traverse readFileLines allResultFiles
220
+
221
+ let header = head $ head allResults
222
+ results = map tail allResults
223
+ header' = " example, " <> header
224
+ results' = zipWith (\ e -> map (\ l -> e <> " , " <> l)) examples results
225
+
226
+ writeFileChanged out $ unlines $ header' : concat results'
214
227
215
- need [build </> T. unpack (humanName v) </> " ghcide" | v <- versions]
228
+ build -/- " */results.csv" %> \ out -> do
229
+ versions <- map (T. unpack . humanName) <$> readVersions
230
+ let example = takeFileName $ takeDirectory out
231
+ allResultFiles =
232
+ [build </> example </> v </> " results.csv" | v <- versions]
216
233
217
234
allResults <- traverse readFileLines allResultFiles
218
235
219
236
let header = head $ head allResults
220
237
results = map tail allResults
221
238
header' = " version, " <> header
222
- results' = zipWith (\ v -> map (\ l -> T. unpack (humanName v) <> " , " <> l)) versions results
239
+ results' = zipWith (\ v -> map (\ l -> v <> " , " <> l)) versions results
223
240
224
241
writeFileChanged out $ unlines $ header' : concat results'
225
242
226
243
priority 2 $
227
- build -/- " */*.diff.svg" %> \ out -> do
228
- let [b, ver, exp_] = splitDirectories out
244
+ build -/- " */*/* .diff.svg" %> \ out -> do
245
+ let [b, example, ver, exp_] = splitDirectories out
229
246
exp = Escaped $ dropExtension $ dropExtension exp_
230
247
prev <- getParent $ T. pack ver
231
248
232
- runLog <- loadRunLog b exp ver
233
- runLogPrev <- loadRunLog b exp $ T. unpack prev
249
+ runLog <- loadRunLog b example exp ver
250
+ runLogPrev <- loadRunLog b example exp $ T. unpack prev
234
251
235
252
let diagram = Diagram Live [runLog, runLogPrev] title
236
253
title = show (unescapeExperiment exp ) <> " - live bytes over time compared"
237
254
plotDiagram True diagram out
238
255
239
256
priority 1 $
240
- build -/- " */*.svg" %> \ out -> do
241
- let [b, ver, exp ] = splitDirectories out
242
- runLog <- loadRunLog b (Escaped $ dropExtension exp ) ver
257
+ build -/- " */*/* .svg" %> \ out -> do
258
+ let [b, example, ver, exp ] = splitDirectories out
259
+ runLog <- loadRunLog b example (Escaped $ dropExtension exp ) ver
243
260
let diagram = Diagram Live [runLog] title
244
261
title = ver <> " live bytes over time"
245
262
plotDiagram True diagram out
246
263
247
- build -/- " *.svg" %> \ out -> do
264
+ build -/- " */* .svg" %> \ out -> do
248
265
let exp = Escaped $ dropExtension $ takeFileName out
266
+ example = takeFileName $ takeDirectory out
249
267
versions <- readVersions
250
268
251
269
runLogs <- forM (filter include versions) $ \ v -> do
252
- loadRunLog build exp $ T. unpack $ humanName v
270
+ loadRunLog build example exp $ T. unpack $ humanName v
253
271
254
272
let diagram = Diagram Live runLogs title
255
273
title = show (unescapeExperiment exp ) <> " - live bytes over time"
@@ -282,7 +300,7 @@ findGhc Stack = do
282
300
283
301
data Config = Config
284
302
{ experiments :: [Unescaped String ],
285
- example :: Example ,
303
+ examples :: [ Example ] ,
286
304
samples :: Natural ,
287
305
versions :: [GitCommit ],
288
306
-- | Path to the ghcide-bench binary for the experiments
@@ -401,14 +419,15 @@ data Diagram = Diagram
401
419
-- | A file path containing the output of -S for a given run
402
420
data RunLog = RunLog
403
421
{ runVersion :: ! String ,
422
+ _runExample :: ! String ,
404
423
_runExperiment :: ! String ,
405
424
runFrames :: ! [Frame ],
406
425
runSuccess :: ! Bool
407
426
}
408
427
409
- loadRunLog :: FilePath -> Escaped FilePath -> FilePath -> Action RunLog
410
- loadRunLog buildF exp ver = do
411
- let log_fp = buildF </> ver </> escaped exp <.> " benchmark-gcStats"
428
+ loadRunLog :: HasCallStack => FilePath -> String -> Escaped FilePath -> FilePath -> Action RunLog
429
+ loadRunLog buildF example exp ver = do
430
+ let log_fp = buildF </> example </> ver </> escaped exp <.> " benchmark-gcStats"
412
431
csv_fp = replaceExtension log_fp " csv"
413
432
log <- readFileLines log_fp
414
433
csv <- readFileLines csv_fp
@@ -422,7 +441,7 @@ loadRunLog buildF exp ver = do
422
441
success = case map (T. split (== ' ,' ) . T. pack) csv of
423
442
[_header, _name: s: _] | Just s <- readMaybe (T. unpack s) -> s
424
443
_ -> error $ " Cannot parse: " <> csv_fp
425
- return $ RunLog ver (dropExtension $ escaped exp ) frames success
444
+ return $ RunLog ver example (dropExtension $ escaped exp ) frames success
426
445
427
446
plotDiagram :: Bool -> Diagram -> FilePath -> Action ()
428
447
plotDiagram includeFailed t@ Diagram {traceMetric, runLogs} out = do
0 commit comments