perf-analysis 0.0.1.1 → 0.1.0.0
raw patch · 4 files changed
+186/−188 lines, 4 filesdep +readme-lhsdep ~base
Dependencies added: readme-lhs
Dependency ranges changed: base
Files
- examples/examples.hs +123/−107
- perf-analysis.cabal +6/−16
- src/Perf/Analysis.hs +57/−54
- stack.yaml +0/−11
examples/examples.hs view
@@ -13,12 +13,12 @@ module Main where -import Data.Scientific+import Readme.Lhs import Formatting import Options.Generic import Perf import Perf.Analysis-import Protolude hiding ((%))+import Protolude import qualified Data.Map as Map import qualified Data.Text as Text import qualified Data.Vector as V@@ -63,15 +63,6 @@ let !n = fromMaybe 1000 (runs o) let !a = fromMaybe 1000 (sumTo o) let !as = [1, 10, 100, 1000 :: Int]-- writeFile "other/run.md" $- code- [ formatInt "number of runs:" 2 n- , formatInt "accumulate to:" 2 a- , sformat ((right 24 ' ' %. stext)%stext) "function:" "foldl' (+) 0"- ]-- -- | tick_ testing prewarmup <- tick_ _ <- warmup 100 onetick <- tick_@@ -83,20 +74,34 @@ let tick99999 = percentile 0.99999 manyticks let tick99 = percentile 0.99 manyticks let tick40 = percentile 0.4 manyticks- writeFile "other/tick_.md" $- code- [ "pre warmup: " <> show prewarmup <> " cycles"- , "one tick_: " <> show onetick <> " cycles"- , "next 10: " <> show ticks'- , "average over 1m: " <> sformat (fixed 2) avticks <> " cycles"- , "99.999% perc: " <> sformat commas (floor tick99999 :: Integer)- , "99.9% perc: " <> sformat (fixed 2) tick999- , "99th perc: " <> sformat (fixed 2) tick99- , "40th perc: " <> sformat (fixed 2) tick40- , "[min, 20th, .. 80th, max]:"- , mconcat (sformat (" " % prec 4) . fromFloatDigits <$> qticks)- ] + -- perf basics+ (result, cs) <- runPerfT $+ perf "sum" cycles (pure $ foldl' (+) 0 [0 .. a])+ putStrLn (show (result, cs) :: Text)++ -- PerfT example+ -- prior to Perfification+ result <- do+ txt <- readFile "perf-analysis/examples/examples.hs"+ let n = Text.length txt+ let x = foldl' (+) 0 [1..n]+ putStrLn $ "sum of one to number of characters is: " <>+ (show x :: Text)+ pure (n, x)++ -- post-Perfification+ (result', ms) <- runPerfT $ do+ txt <- perf "file read" cycles $ readFile "perf-analysis/examples/examples.hs"+ n <- perf "length" cycles $ pure (Text.length txt)+ x <- perf "sum" cycles $ pure (foldl' (+) 0 [1..n])+ perf "print to screen" cycles $+ putStrLn $ "sum of one to number of characters is: " <>+ (show x :: Text)+ pure (n, x)++ when (result == result') $ print "PerfT has no effect on original computation"+ -- | tick tests (t, resultPrime) <- tick fMono a print resultPrime@@ -111,20 +116,6 @@ t10io <- sequence $ replicate 10 (tickIO $ pure (fMono a)) -- t10n <- sequence $ replicate 10 (tickNoinline fMono a) t10' <- sequence $ replicate 10 (tick fMono a)- writeFile "other/tick.md" $- code- [ "sum to " <> show a- , "first measure: " <> show t <> " cycles"- , "second measure: " <> show t2 <> " cycles"- , "third measure: " <> show t3 <> " cycles"- , "tick': " <> show t' <> " cycles"- , "tickIO: " <> show tio <> " cycles"- -- , "tickNoinline: " <> show tn <> " cycles"- , "tick * 10: " <> show (fst <$> t10)- , "tickIO * 10: " <> show (fst <$> t10io)- -- , "tickNoinline * 10: " <> show (fst <$> t10n)- , "tick * 10: " <> show (fst <$> t10')- ] -- | ticks and ticksIO (rpure, _) <- ticks n fMono a@@ -134,35 +125,14 @@ (rioPoly, _) <- ticksIO n (pure $ fPoly a) (rioLambda, _) <- ticksIO n (pure $ fLambda a) - writeFile "other/ticks.md" $- code [ "acc = " <> show a <> " n = " <> show n- , formatRunHeader- , formatRun "monomorphic" 2 $ rpure- , formatRun "includes lambda" 2 $ rpureLambda- , formatRun "polymorphic" 2 $ rpurePoly- , formatRun "ticksIO mono" 2 $ rio- , formatRun "ticksIO lambda" 2 $ rioLambda- , formatRun "ticksIO poly" 2 $ rioPoly- ]-- gaps <- sequence $ (\a -> formatGap a <$> tickIO (ticks n fPoly a)) <$> as- writeFile "other/ticksCost.md" $ code gaps+ -- | gaps+ gaps <- sequence $ (tickIO . ticks n fPoly) <$> as -- | ns testing css <- fmap (fmap fst) <$> sequence ((replicateM n . tick fMono) <$> as)- let r12 =- "(replicateM n . tick fMono) <$> as: " <>- mconcat (sformat (" " %prec 3) <$>- (fromFloatDigits . percentile 0.4 <$> css)) (ts, _) <- ns (ticks n fMono) as- let r13 =- "ns (ticks n fMono) as: " <>- mconcat (sformat (" " %prec 3) <$>- (fromFloatDigits . percentile 0.4 <$> ts))- writeFile "other/tickns.md" $- code ["sum to's " <> show as, r13, r12] -- | vectors let asl :: [Int]@@ -185,14 +155,6 @@ let asu :: U.Vector Int = U.generate a identity (runboxed, _) <- ticks n sumu asu- writeFile "other/vector.md" $- code- [ "sum to " <> show a- , formatRun "ticks list" 2 $ rlist- , formatRun "ticks boxed" 2 $ rboxed- , formatRun "ticks storable" 2 $ rstorable- , formatRun "ticks unboxed" 2 $ runboxed- ] -- WHNF (rnf, _) <- tick (fmap fMono) (Just a)@@ -204,47 +166,101 @@ (rnfsio, _) <- ticksIO n (pure $ fmap fMono (Just a)) (rwhnfsio, _) <- ticksWHNFIO n (pure $ fmap fMono (Just a)) - writeFile "other/whnf.md" $ code- [ "sum to " <> show a- , formatInt "tick" 2 $ rnf- , formatInt "tickWHNF" 2 $ rwhnf- , formatRun "ticks" 2 rnfs- , formatRun "ticksWHNF" 2 rwhnfs- , formatInt "tickIO" 2 rnfio- , formatInt "tickWHNFIO" 2 rwhnfio- , formatRun "ticksIO" 2 rnfsio- , formatRun "ticksWHNFIO" 2 rwhnfsio- ]+ void $ runOutput+ ("other/readme_.md", GitHubMarkdown)+ ("readme.md", GitHubMarkdown) $ do - -- perf basics- (result, cs) <- runPerfT $- perf "sum" cycles (pure $ foldl' (+) 0 [0 .. a])- putStrLn (show (result, cs) :: Text)+ output "run" $ Native $ (:[]) $ table+ "run details"+ []+ [AlignLeft, AlignRight]+ [0, 0]+ [ ["number of runs", formatI 2 n]+ , ["accumulate to", formatI 2 a]+ , ["function", "foldl' (+) 0"]+ ] - -- PerfT example- -- prior to Perfification- result <- do- txt <- readFile "perf-analysis/examples/examples.hs"- let n = Text.length txt- let x = foldl' (+) 0 [1..n]- putStrLn $ "sum of one to number of characters is: " <>- (show x :: Text)- pure (n, x)+ output "tick_" $ Native $ (:[]) $ table mempty ["stat", "cycles"] mempty mempty+ [ ["pre warmup", show prewarmup]+ , ["one tick_", show onetick]+ , ["next 10", show ticks']+ , ["average over one million", sformat (fixed 2) avticks]+ , ["99.999% perc", sformat commas (floor tick99999 :: Integer)]+ , ["99.9% perc", sformat (fixed 2) tick999]+ , ["99th perc", sformat (fixed 2) tick99]+ , ["40th perc", sformat (fixed 2) tick40]+ , ["[min, 20th, .. 80th, max]",+ Text.intercalate " " (formatF 4 <$> qticks)]+ ] - -- post-Perfification- (result', ms) <- runPerfT $ do- txt <- perf "file read" cycles $ readFile "perf-analysis/examples/examples.hs"- n <- perf "length" cycles $ pure (Text.length txt)- x <- perf "sum" cycles $ pure (foldl' (+) 0 [1..n])- perf "print to screen" cycles $- putStrLn $ "sum of one to number of characters is: " <>- (show x :: Text)- pure (n, x)+ output "tick" $ Native+ [ plain ("sum to " <> show a)+ , table mempty ["stat", "cycles"] mempty mempty+ [ ["first measure", show t]+ , ["second measure", show t2]+ , ["third measure", show t3]+ , ["tick'", show t']+ , ["tickIO", show tio]+ , ["tick * 10", show (fst <$> t10)]+ , ["tickIO * 10", show (fst <$> t10io)]+ , ["tick' * 10", show (fst <$> t10')]+ ]+ ] - when (result == result') $ print "PerfT has no effect on original computation"+ output "ticks" $ Native [formatRuns 3 2+ [ ("monomorphic", rpure)+ , ("includes lambda", rpureLambda)+ , ("polymorphic", rpurePoly)+ , ("ticksIO mono", rio)+ , ("ticksIO lambda", rioLambda)+ , ("ticksIO poly", rioPoly)+ ]] - let fmt = sformat ((right 40 ' ' %. stext) %prec 3 % " " % stext)- writeFile "other/perf.md" $- "\nperf cycle measurements\n---\n" <>- code ((\(t,c) -> fmt t (int2Sci c) "cycles") <$> Map.toList ms) ++ output "gaps" $ Native $ (:[]) $ table mempty+ ["number runs", "outside cycles", "inside cycles", "gap"]+ mempty mempty+ (zipWith (\a (co, (ci, _)) ->+ [ formatI 1 a+ , formatI 3 co+ , formatI 3 (sum ci)+ , formatI 3 (co - sum ci)+ ]) as gaps)++ output "tickns" $ Native+ [ table mempty (["sum to:"] <> (show <$> as)) mempty mempty+ [ ["(replicateM n . tick fMono) <$> as"] <>+ (formatF 3 . percentile 0.5 <$> css)+ , ["ns (ticks n fMono) as"] <>+ (formatF 3 . percentile 0.5 <$> ts)+ ]+ ]++ output "vector" $ Native $ [plain ("sum to " <> show a)] <>+ [formatRuns 3 2 + [ ("ticks list", rlist)+ , ("ticks boxed", rboxed)+ , ("ticks storable", rstorable)+ , ("ticks unboxed", runboxed)+ ]]++ output "whnf" $ Native+ [ plain ("sum to " <> show a)+ , table mempty ["function", "cycles"] mempty mempty+ [ ["tick", formatI 3 rnf]+ , ["tickWHNF", formatI 3 rwhnf]+ , formatRun "ticks" 3 3 rnfs+ , formatRun "ticksWHNF" 3 3 rwhnfs+ , ["tickIO", formatI 3 rnfio]+ , ["tickWHNFIO", formatI 3 rwhnfio]+ , formatRun "ticksIO" 3 3 rnfsio+ , formatRun "ticksWHNFIO" 3 3 rwhnfsio+ ]+ ]++ output "perf" $ Native+ [ plain "perf cycle measurements"+ , table mempty ["effect", "cycles"] mempty mempty+ ((\(t,c) -> [t, formatI 3 c]) <$> Map.toList ms)+ ]
perf-analysis.cabal view
@@ -1,11 +1,5 @@--- This file has been generated from package.yaml by hpack version 0.28.2.------ see: https://github.com/sol/hpack------ hash: 5b2bb96e01227ec3ddd4c29e4bebf5895c909acff05541ea597f16b063ce3eb4- name: perf-analysis-version: 0.0.1.1+version: 0.1.0.0 synopsis: analysis example using perf description: Analytical tools to use with perf. category: performance@@ -17,9 +11,7 @@ license: BSD3 license-file: LICENSE build-type: Simple-cabal-version: >= 1.10-extra-source-files:- stack.yaml+cabal-version: 2.0 source-repository head type: git@@ -29,12 +21,10 @@ library exposed-modules: Perf.Analysis- other-modules:- Paths_perf_analysis hs-source-dirs: src build-depends:- base >=4.7 && <4.12+ base >=4.7 && <5 , deepseq , formatting , perf >=0.4.1.0@@ -43,17 +33,16 @@ , tdigest , text , vector+ , readme-lhs default-language: Haskell2010 executable perf-examples main-is: examples.hs- other-modules:- Paths_perf_analysis hs-source-dirs: examples ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -rtsopts -O2 build-depends:- base >=4.7 && <4.12+ base >=4.7 && <5 , containers , deepseq , formatting@@ -65,4 +54,5 @@ , tdigest , text , vector+ , readme-lhs default-language: Haskell2010
src/Perf/Analysis.hs view
@@ -1,14 +1,7 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE DataKinds #-} {-# OPTIONS_GHC -Wall #-}-{-# OPTIONS_GHC -fno-warn-type-defaults #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE NoImplicitPrelude #-} -- | analytical functionality for perf module Perf.Analysis where@@ -17,8 +10,8 @@ import Data.TDigest import Formatting import Perf-import Protolude hiding ((%))-import qualified Data.Text as Text+import Protolude+import Readme.Lhs hiding (Format) -- | compute deciles --@@ -55,51 +48,61 @@ int2Sci :: (Integral a) => a -> Scientific int2Sci n = scientific (fromIntegral n) 0 --- | format an Integral as a Scientific with a label and precision-formatInt :: (Integral a) => Text -> Int -> a -> Text-formatInt label p x =- sformat- ((right 24 ' ' %. stext) %- (left 8 ' ' %. prec p)) label (int2Sci x)+formatSecs :: (RealFloat a) => Int -> a -> Text+formatSecs p s+ | s < 0 = "-" <> formatSecs p (-s)+ | s >= 1 = formatFixed p s <> " s"+ | s >= 1e-3 = formatFixed p (s*1e3) <> " ms"+ | s >= 1e-6 = formatFixed p (s*1e6) <> " μs"+ | s >= 1e-9 = formatFixed p (s*1e9) <> " ns"+ | otherwise = formatFixed p (s*1e12) <> " ps" --- | format the first 5 results, and then the 40th percentile-formatRun :: (Integral a) => Text -> Int -> [a] -> Text-formatRun label p xs =- sformat- ((right 24 ' ' %. stext) % stext %- (left 9 ' ' %. prec p) %- (left 9 ' ' %. prec p))- label- (Text.intercalate " " $ sformat (left 8 ' ' %. prec p) .- int2Sci <$>- take 3 xs)- (fromFloatDigits $ percentile 0.5 xs)- (fromFloatDigits $ average xs)+-- | format an Integral as a Scientific with a precision+formatI :: (Integral a) => Int -> a -> Text+formatI p x = sformat (prec p) (int2Sci x) --- | header for formatRun-formatRunHeader :: Text-formatRunHeader =- sformat- ((right 24 ' ' %. stext) %- (left 8 ' ' %. stext) %- (left 9 ' ' %. stext) %- (left 9 ' ' %. stext) %- (left 9 ' ' %. stext) %- (left 9 ' ' %. stext))- "run"- "first"- "2nd"- "3rd"- "median"- "av."+-- | format a Float as a Scientific with a precision+formatF :: (RealFloat a) => Int -> a -> Text+formatF p x = sformat (prec p) (fromFloatDigits x) --- | format a tick result with an inside and outside measurement-formatGap :: (Integral a) => Int -> (a, ([a],b)) -> Text-formatGap a (co, (ci, _)) =- sformat- ("n = " %(left 7 ' ' %. prec 3)%" outside: "%(left 7 ' ' %. prec 3)%" inside: "%(left 7 ' ' %. prec 3)%" gap: "%(left 7 ' ' %. prec 3))- (int2Sci a) (int2Sci co) (int2Sci $ sum ci) (int2Sci $ co - sum ci)+-- | format a Float as a Scientific with a precision+formatFixed :: (RealFloat a) => Int -> a -> Text+formatFixed p x = sformat (fixed p) (fromFloatDigits x) --- | place markdown backtics around text-code :: [Text] -> Text-code cs = "\n```\n" <> Text.intercalate "\n" cs <> "\n```\n"+-- | format the first few results, the median and average+formatRun :: (Integral a) => Text -> Int -> Int -> [a] -> [Text]+formatRun label n p xs =+ [ label] <>+ (formatI p <$> take n xs) <>+ [ formatF p $ average xs+ , formatF p $ percentile 0.5 xs+ ]++-- | average and time+formatRunTime :: (Integral a) => Text -> Double -> Int -> [a] -> [Text]+formatRunTime label npc p xs =+ [ label] <>+ [ formatF p $ npc * average xs+ , formatF p $ average xs+ ]++formatRuns :: (Integral a) => Int -> Int -> [(Text, [a])] -> Block+formatRuns n p runs =+ table+ mempty+ (["run"] <>+ take n (["first", "second", "third"] <> ((<>"th") . show <$> [4::Int ..])) <>+ ["average", "median"])+ ([AlignLeft] <> replicate (n+2) AlignRight)+ (replicate (n+3) 0)+ (fmap (\(l,as) -> formatRun l n p as) runs)++formatRunsTime :: (Integral a) => Double -> Int -> [(Text, [a])] -> Block+formatRunsTime npc p runs =+ table+ mempty+ ["run", "cputime", "cycles"]+ [AlignLeft, AlignRight, AlignRight]+ []+ (fmap (\(l,as) -> formatRunTime l npc p as) runs)+
− stack.yaml
@@ -1,11 +0,0 @@-resolver: nightly-2018-05-28--packages:- - .- - ../perf--extra-deps:- - rdtsc-1.3.0.1- - tdigest-0.2--allow-newer: true