@@ -48,6 +48,7 @@ module Development.Benchmark.Rules
48
48
(
49
49
buildRules , MkBuildRules (.. ), OutputFolder , ProjectRoot ,
50
50
benchRules , MkBenchRules (.. ), BenchProject (.. ), ProfilingMode (.. ),
51
+ addGetParentOracle ,
51
52
csvRules ,
52
53
svgRules ,
53
54
heapProfileRules ,
@@ -77,11 +78,13 @@ import Data.Aeson (FromJSON (..),
77
78
import Data.Aeson.Lens (AsJSON (_JSON ),
78
79
_Object , _String )
79
80
import Data.ByteString.Lazy (ByteString )
80
- import Data.Char (isDigit )
81
- import Data.List (find , isInfixOf ,
81
+ import Data.Char (isAlpha , isDigit )
82
+ import Data.List (find , intercalate ,
83
+ isInfixOf ,
84
+ isSuffixOf ,
82
85
stripPrefix ,
83
86
transpose )
84
- import Data.List.Extra (lower )
87
+ import Data.List.Extra (lower , splitOn )
85
88
import Data.Maybe (fromMaybe )
86
89
import Data.String (fromString )
87
90
import Data.Text (Text )
@@ -144,7 +147,9 @@ allTargetsForExample prof baseFolder ex = do
144
147
configurations <- askOracle $ GetConfigurations ()
145
148
let buildFolder = baseFolder </> profilingPath prof
146
149
return $
147
- [buildFolder </> getExampleName ex </> " results.csv" ]
150
+ [
151
+ buildFolder </> getExampleName ex </> " results.csv"
152
+ , buildFolder </> getExampleName ex </> " resultDiff.csv" ]
148
153
++ [ buildFolder </> getExampleName ex </> escaped (escapeExperiment e) <.> " svg"
149
154
| e <- experiments
150
155
]
@@ -187,6 +192,8 @@ phonyRules prefix executableName prof buildFolder examples = do
187
192
allTargetsForExample prof buildFolder ex
188
193
need $ (buildFolder </> profilingPath prof </> " results.csv" )
189
194
: concat exampleTargets
195
+ need $ (buildFolder </> profilingPath prof </> " resultDiff.csv" )
196
+ : concat exampleTargets
190
197
phony (prefix <> " all-binaries" ) $ need =<< allBinaries buildFolder executableName
191
198
--------------------------------------------------------------------------------
192
199
type OutputFolder = FilePath
@@ -384,69 +391,92 @@ parseMaxResidencyAndAllocations input =
384
391
385
392
386
393
--------------------------------------------------------------------------------
387
-
394
+ -- | oracles to get previous version of a given version
395
+ -- used for diff the results
396
+ addGetParentOracle :: Rules ()
397
+ addGetParentOracle = void $ addOracle $ \ (GetParent name) -> findPrev name <$> askOracle (GetVersions () )
388
398
-- | Rules to aggregate the CSV output of individual experiments
389
399
csvRules :: forall example . RuleResultForExample example => FilePattern -> Rules ()
390
400
csvRules build = do
401
+ let genConfig resultName prefixName prefixOracles out = do
402
+ configurations <- prefixOracles
403
+ let allResultFiles = [takeDirectory out </> c </> resultName | c <- configurations ]
404
+ allResults <- traverse readFileLines allResultFiles
405
+ let header = head $ head allResults
406
+ results = map tail allResults
407
+ header' = prefixName <> " , " <> header
408
+ results' = zipWith (\ v -> map (\ l -> v <> " , " <> l)) configurations results
409
+ writeFileChanged out $ unlines $ header' : interleave results'
391
410
-- build results for every experiment*example
392
- build -/- " */*/*/*/results.csv" %> \ out -> do
411
+ priority 1 $ build -/- " */*/*/*/results.csv" %> \ out -> do
393
412
experiments <- askOracle $ GetExperiments ()
394
-
395
413
let allResultFiles = [takeDirectory out </> escaped (escapeExperiment e) <.> " csv" | e <- experiments]
396
414
allResults <- traverse readFileLines allResultFiles
397
-
398
415
let header = head $ head allResults
399
416
results = map tail allResults
400
417
writeFileChanged out $ unlines $ header : concat results
401
-
418
+ priority 2 $ build -/- " */*/*/*/resultDiff.csv" %> \ out -> do
419
+ let out2@ [b, flav, example, ver, conf, exp_] = splitDirectories out
420
+ prev <- fmap T. unpack $ askOracle $ GetParent $ T. pack ver
421
+ allResultsCur <- readFileLines $ joinPath [b ,flav, example, ver, conf] </> " results.csv"
422
+ allResultsPrev <- readFileLines $ joinPath [b ,flav, example, prev, conf] </> " results.csv"
423
+ let resultsPrev = tail allResultsPrev
424
+ let resultsCur = tail allResultsCur
425
+ let resultDiff = zipWith convertToDiffResults resultsCur resultsPrev
426
+ writeFileChanged out $ unlines $ head allResultsCur : resultDiff
402
427
-- aggregate all configurations for an experiment
403
- build -/- " */*/*/results.csv" %> \ out -> do
404
- configurations <- map confName <$> askOracle (GetConfigurations () )
405
- let allResultFiles = [takeDirectory out </> c </> " results.csv" | c <- configurations ]
406
-
407
- allResults <- traverse readFileLines allResultFiles
408
-
409
- let header = head $ head allResults
410
- results = map tail allResults
411
- header' = " configuration, " <> header
412
- results' = zipWith (\ v -> map (\ l -> v <> " , " <> l)) configurations results
413
-
414
- writeFileChanged out $ unlines $ header' : interleave results'
415
-
428
+ priority 3 $ build -/- " */*/*/results.csv" %> genConfig " results.csv"
429
+ " Configuration" (map confName <$> askOracle (GetConfigurations () ))
430
+ priority 3 $ build -/- " */*/*/resultDiff.csv" %> genConfig " resultDiff.csv"
431
+ " Configuration" (map confName <$> askOracle (GetConfigurations () ))
416
432
-- aggregate all experiments for an example
417
- build -/- " */*/results.csv" %> \ out -> do
418
- versions <- map (T. unpack . humanName) <$> askOracle (GetVersions () )
419
- let allResultFiles = [takeDirectory out </> v </> " results.csv" | v <- versions]
420
-
421
- allResults <- traverse readFileLines allResultFiles
422
-
423
- let header = head $ head allResults
424
- results = map tail allResults
425
- header' = " version, " <> header
426
- results' = zipWith (\ v -> map (\ l -> v <> " , " <> l)) versions results
427
-
428
- writeFileChanged out $ unlines $ header' : interleave results'
429
-
433
+ priority 4 $ build -/- " */*/results.csv" %> genConfig " results.csv"
434
+ " Version" (map (T. unpack . humanName) <$> askOracle (GetVersions () ))
435
+ priority 4 $ build -/- " */*/resultDiff.csv" %> genConfig " resultDiff.csv"
436
+ " Version" (map (T. unpack . humanName) <$> askOracle (GetVersions () ))
430
437
-- aggregate all examples
431
- build -/- " */results.csv" %> \ out -> do
432
- examples <- map (getExampleName @ example ) <$> askOracle (GetExamples () )
433
- let allResultFiles = [takeDirectory out </> e </> " results.csv" | e <- examples]
434
-
435
- allResults <- traverse readFileLines allResultFiles
436
-
437
- let header = head $ head allResults
438
- results = map tail allResults
439
- header' = " example, " <> header
440
- results' = zipWith (\ e -> map (\ l -> e <> " , " <> l)) examples results
438
+ priority 5 $ build -/- " */results.csv" %> genConfig " results.csv"
439
+ " Example" (map getExampleName <$> askOracle (GetExamples () ))
440
+ priority 5 $ build -/- " */resultDiff.csv" %> genConfig " resultDiff.csv"
441
+ " Example" (map getExampleName <$> askOracle (GetExamples () ))
442
+
443
+ convertToDiffResults :: String -> String -> String
444
+ convertToDiffResults line baseLine = intercalate " ," diffResults
445
+ where items = parseLine line
446
+ baseItems = parseLine baseLine
447
+ diffItems = zipWith diffItem items baseItems
448
+ diffResults = map showItemDiffResult diffItems
449
+
450
+ showItemDiffResult :: (Item , Maybe Double ) -> String
451
+ showItemDiffResult (ItemString x, _) = x
452
+ showItemDiffResult (_, Nothing ) = " NA"
453
+ showItemDiffResult (Mem x, Just y) = printf " %.2f" (y * 100 - 100 ) <> " %"
454
+ showItemDiffResult (Time x, Just y) = printf " %.2f" (y * 100 - 100 ) <> " %"
455
+
456
+ diffItem :: Item -> Item -> (Item , Maybe Double )
457
+ diffItem (Mem x) (Mem y) = (Mem x, Just $ fromIntegral x / fromIntegral y)
458
+ diffItem (Time x) (Time y) = (Time x, if y == 0 then Nothing else Just $ x / y)
459
+ diffItem (ItemString x) (ItemString y) = (ItemString x, Nothing )
460
+ diffItem _ _ = (ItemString " no match" , Nothing )
461
+
462
+ data Item = Mem Int | Time Double | ItemString String
463
+ deriving (Show )
441
464
442
- writeFileChanged out $ unlines $ header' : concat results'
465
+ parseLine :: String -> [Item ]
466
+ parseLine = map f . splitOn " ,"
467
+ where
468
+ f x
469
+ | " MB" `isSuffixOf` x = Mem $ read $ reverse $ drop 2 $ reverse x
470
+ | otherwise =
471
+ case readMaybe @ Double x of
472
+ Just time -> Time time
473
+ Nothing -> ItemString x
443
474
444
475
--------------------------------------------------------------------------------
445
476
446
477
-- | Rules to produce charts for the GC stats
447
478
svgRules :: FilePattern -> Rules ()
448
479
svgRules build = do
449
- void $ addOracle $ \ (GetParent name) -> findPrev name <$> askOracle (GetVersions () )
450
480
-- chart GC stats for an experiment on a given revision
451
481
priority 1 $
452
482
build -/- " */*/*/*/*.svg" %> \ out -> do
0 commit comments