packages feed

type-of-html-1.5.1.0: bench/Alloc.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds      #-}
{-# LANGUAGE CPP            #-}

-- | Note that the allocation numbers are only reproducible on linux using the nix shell.

module Main where

import Html
import qualified Html.Attribute as A
import qualified Small          as S
import qualified Medium         as M
import qualified Big            as B

import Weigh
import Data.Proxy
import Data.Int

import GHC
import GHC.Paths (libdir)
import GHC.TypeNats
import DynFlags
import Control.Monad

allocs :: Int64 -> Weight -> Maybe String
allocs n w
  | n' > n = Just $ "More" ++ answer
  | n' < n = Just $ "Less" ++ answer
  | otherwise = Nothing
  where n' = weightAllocatedBytes w
        answer = " allocated bytes than expected: " ++ show (abs $ n' - n)

allocsError :: (Show a, Integral a) => a -> a -> a -> Weight -> Maybe String
allocsError i m n w
  | n' > (m'+1) = Just $ "More" ++ answer
  | n' < (m'-1) = Just $ "Less" ++ answer
  | otherwise = Nothing
  where n' = round (fromIntegral (weightAllocatedBytes w) / (10^i) :: Rational)
        m' = n + m
        answer = " allocated bytes than expected: " ++ pretty (abs $ m' - n')
        pretty x = show x ++ " e" ++ show i

f :: Document b => String -> (a -> b) -> a -> Int64 -> Weigh ()
f s g x n = validateFunc s (renderByteString . g) x (allocs n)

main :: IO ()
main = mainWith $ do

  let ghc = allocFold                                    ::  GhcVersions  [802,  804,  806,   808]

  f "()"                   id ()                                   $ ghc   128     0     0      0
  f "Int"                  id (123456789 :: Int)                   $ ghc   192     0     0      0
  f "Word"                 id (123456789 :: Word)                  $ ghc   192     0     0      0
  f "Char"                 id 'a'                                  $ ghc   192     0     0      0
  f "Integer"              id (123456789 :: Integer)               $ ghc   248     0     0      0
  f "Proxy"                id (Proxy :: Proxy "a")                 $ ghc   208     0     0      0
  f "oneElement Proxy"     S.oneElement (Proxy :: Proxy "b")       $ ghc   208     0     0      0
  f "oneElement ()"        S.oneElement ()                         $ ghc   208     0     0      0
  f "oneAttribute ()"      A.class_ ()                             $ ghc   208     0     0      0
  f "oneAttribute Proxy"   A.class_ (Proxy :: Proxy "c")           $ ghc   208     0     0      0
  f "listElement"          S.listElement ()                        $ ghc   608     0     0      0
  f "Double"               id (123456789 :: Double)                $ ghc   360     0     0      0
  f "oneElement"           S.oneElement ""                         $ ghc   368     0     0      0
  f "nestedElement"        S.nestedElement ""                      $ ghc   368     0     0      0
  f "listOfAttributes"     (\x -> [A.class_ x, A.class_ x]) ()     $ ghc   712     0     0      0
  f "Float"                id (123456789 :: Float)                 $ ghc   400     0     0      0
  f "oneAttribute"         A.class_ ""                             $ ghc   520     0     0      0
  f "parallelElement"      S.parallelElement ""                    $ ghc   520     0     0   (-16)
  f "parallelAttribute"    (\x -> A.class_ x # A.id_ x) ""         $ ghc   736     0     0      0
  f "elementWithAttribute" (\x -> div_A (A.class_ x) x) ""         $ ghc   696     0     0      0
  f "listOfListOf"         (\x -> div_ [i_ [span_ x]]) ()          $ ghc  1200     0    64      0
  f "helloWorld"           M.helloWorld ()                         $ ghc   920   168     0      0
  f "page"                 M.page ()                               $ ghc  1400     0   720      0
  f "table"                M.table (2,2)                           $ ghc  2640     0     8   (-96)
  f "AttrShort"            M.attrShort ()                          $ ghc  2688     0  2104      0
  f "pageA"                M.pageA ()                              $ ghc  4552  (-96) (-96) (-288)
  f "AttrLong"             M.attrLong ()                           $ ghc  2688     0  2104      0
  f "Big table"            M.table (15,15)                         $ ghc 54040     0     8 (-3736)
  f "Big page"             B.page ()                               $ ghc 27888 (-120)    0 (-1344)

type family GhcVersions xs where
  GhcVersions '[] = Int64
  GhcVersions (x ': xs) = GHC x -> GhcVersions xs

newtype GHC (k :: Nat) = GHC Int64 deriving Num

class AllocFold a where
  allocFold :: a

instance AllocFold (GHC k -> Int64) where
  allocFold (GHC i) = i

instance AllocFold (GHC m -> a) => AllocFold (GHC l -> GHC m -> a) where
  allocFold (GHC i1) i2 = allocFold (GHC i1 + i2)

instance {-# OVERLAPPING #-} AllocFold (GHC __GLASGOW_HASKELL__ -> a) => AllocFold (GHC __GLASGOW_HASKELL__ -> GHC m -> a) where
  allocFold i1 _ = allocFold i1

compile :: String -> String -> IO ()
compile out m =
  void . defaultErrorHandler defaultFatalMessager defaultFlushOut . runGhc (Just libdir) $ do
    dflags <- getSessionDynFlags
    void $ setSessionDynFlags (dflags {optLevel = 2, importPaths = ["src", "bench"], hiDir = Just out, objectDir = Just out, outputFile = Just (out ++ "/out")})
    target <- guessTarget m Nothing
    setTargets [target]
    load LoadAllTargets