packages feed

perf-analysis (empty) → 0.0.1.0

raw patch · 6 files changed

+466/−0 lines, 6 filesdep +basedep +containersdep +deepseqsetup-changed

Dependencies added: base, containers, deepseq, formatting, optparse-generic, perf, perf-analysis, protolude, scientific, tdigest, text, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Tony Day (c) 2016++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Tony Day nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ examples/examples.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# 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 #-}++module Main where++import Data.Scientific+import Formatting+import Options.Generic+import Perf+import Perf.Analysis+import Protolude hiding ((%))+import qualified Data.Map as Map+import qualified Data.Text as Text+import qualified Data.Vector as V+import qualified Data.Vector.Storable as S+import qualified Data.Vector.Unboxed as U++data Opts = Opts+  { runs :: Maybe Int -- <?> "number of runs"+  , sumTo :: Maybe Int -- <?> "sum to this number"+  , sumsTo :: Maybe [Int] -- <?> "sum to these numbers"+  } deriving (Generic, Show)++instance ParseField [Int]++instance ParseRecord Opts++-- | useful as a benchmark versus the `ticks` functions being imported+ticksInFile :: (NFData b) => Int -> (a -> b) -> a -> IO ([Cycle], b)+ticksInFile n0 f a = go f a n0 []+  where+    go f a n ts+      | n <= 0 = pure (ts, f a)+      | otherwise = do+          (t,_) <- tick f a+          go f a (n - 1) (t:ts)++-- | interposition of a lambda+fLambda :: Int -> Int+fLambda = \x -> foldl' (+) 0 [1 .. x]++-- | monomorphic version+fMono :: Int -> Int+fMono x = foldl' (+) 0 [1 .. x]++-- | polymorphic function version+fPoly :: (Integral b) => b -> b+fPoly x = foldl' (+) 0 [1 .. x]++main :: IO ()+main = do+  o :: Opts <- getRecord "perf examples"+  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_+  ticks' <- replicateM 10 tick_+  manyticks <- replicateM 1000000 tick_+  let avticks = average manyticks+  let qticks = deciles 5 manyticks+  let tick999 = percentile 0.999 manyticks+  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)+      ]++  -- | tick tests+  (t, resultPrime) <- tick fMono a+  print resultPrime+  (t2,_) <- tick fMono a+  (t3,_) <- tick fMono a+  (t',_) <- tick' fMono a+  (tio,_) <- tickIO (pure $ fMono a)+  -- mystery: if tickNoinline is used at all, all tick computations slow down+  -- by a factor of 2 (or by a function call)+  -- (tn,_) <- tickNoinline fMono a+  t10 <- sequence $ replicate 10 (tick fMono a)+  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+  (rpurePoly, _) <- ticks n fPoly a+  (rpureLambda, _) <- ticks n fLambda a+  (rio, _) <- ticksIO n (pure $ fMono a)+  (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++  -- | 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]+      asl = [1 .. a]+  let suml :: [Int] -> Int+      suml = foldl' (+) 0+  (rlist, _) <- ticks n suml asl+  let sumv :: V.Vector Int -> Int+      sumv = V.foldl (+) 0+  let asv :: V.Vector Int =+        V.generate a identity+  (rboxed, _) <- ticks n sumv asv+  let sums :: S.Vector Int -> Int+      sums = S.foldl (+) 0+  let ass :: S.Vector Int =+        S.generate a identity+  (rstorable, _) <- ticks n sums ass+  let sumu :: U.Vector Int -> Int+      sumu = U.foldl (+) 0+  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)+  (rwhnf, _) <- tick (fmap fMono) (Just a)+  (rnfs, _) <- ticks n (fmap fMono) (Just a)+  (rwhnfs, _) <- ticksWHNF n (fmap fMono) (Just a)+  (rnfio, _) <- tickIO (pure $ fmap fMono (Just a))+  (rwhnfio, _) <- tickWHNFIO (pure $ fmap fMono (Just a))+  (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+    ]++  -- 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"++  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)+
+ perf-analysis.cabal view
@@ -0,0 +1,68 @@+-- This file has been generated from package.yaml by hpack version 0.28.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 97459822690cecba4e6db836b86eedf2d10cc0a7f8ff32e4c525614241b4af82++name:           perf-analysis+version:        0.0.1.0+synopsis:       analysis example using perf+description:     Analytical tools to use with perf. +category:       performance+homepage:       https://github.com/tonyday567/perf#readme+bug-reports:    https://github.com/tonyday567/perf/issues+author:         Tony Day+maintainer:     tonyday567@gmail.com+copyright:      Tony Day+license:        BSD3+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10+extra-source-files:+    stack.yaml++source-repository head+  type: git+  location: https://github.com/tonyday567/perf+  subdir: perf-analysis++library+  exposed-modules:+      Perf.Analysis+  other-modules:+      Paths_perf_analysis+  hs-source-dirs:+      src+  build-depends:+      base >=4.7 && <4.12+    , deepseq+    , formatting+    , perf+    , protolude+    , scientific+    , tdigest+    , text+    , vector+  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+    , containers+    , deepseq+    , formatting+    , optparse-generic+    , perf+    , perf-analysis+    , protolude+    , scientific+    , tdigest+    , text+    , vector+  default-language: Haskell2010
+ src/Perf/Analysis.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# 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++import Data.Scientific+import Data.TDigest+import Formatting+import Perf+import Protolude hiding ((%))+import qualified Data.Text as Text++-- | compute deciles+--+-- >>> deciles 5 [1..1000]+-- [1.0,200.5,400.5,600.5,800.5,1000.0]+--+-- > c5 <- decile 5 <$> ticks n f a+--+deciles :: (Functor f, Foldable f, Integral a) => a -> f a -> [Double]+deciles n xs =+  (\x -> fromMaybe 0 $+    quantile x (tdigest (fromIntegral <$> xs) :: TDigest 25)) <$>+  ((/ fromIntegral n) . fromIntegral <$> [0 .. n])++-- | compute a percentile+--+-- >>> percentile 0.1 [1..1000]+-- 100.5+--+-- > c <- percentile 0.4 . fst <$> ticks n f a+--+percentile :: (Functor f, Foldable f, Integral a) => Double -> f a -> Double+percentile p xs = fromMaybe 0 $ quantile p (tdigest (fromIntegral <$> xs) :: TDigest 25)++-- | fixed precision for a Scientific+prec :: Int -> Format r (Scientific -> r)+prec n = scifmt Exponent (Just n)++-- | convert an integral to a Scientific+--+-- >>> sformat (left 8 ' ' %. prec 1) (int2Sci 1000)+-- "   1.0e3"+--+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)++-- | 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)++-- | 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 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)++-- | place markdown backtics around text+code :: [Text] -> Text+code cs = "\n```\n" <> Text.intercalate "\n" cs <> "\n```\n"
+ stack.yaml view
@@ -0,0 +1,11 @@+resolver: nightly-2018-04-05++packages:+  - .+  - ../perf++extra-deps:+  - rdtsc-1.3.0.1+  - tdigest-0.2++allow-newer: true