    {-# LANGUAGE PatternGuards, RecordWildCards #-}

    module Development.Shake.Internal.Profile(writeProfile) where

    import General.Template
    import Data.Tuple.Extra
    import Data.Function
    import Data.List.Extra
    import Data.Maybe
    import System.FilePath
    import System.IO.Extra
    import Numeric.Extra
    import General.Extra
    import Development.Shake.Internal.Errors
    import Development.Shake.Internal.Core.Types
    import Development.Shake.Internal.Core.Database
    import Development.Shake.Internal.Value
    import qualified Data.HashSet as Set
    import Development.Shake.Internal.Paths
    import Development.Shake.Classes
    import System.Time.Extra
    import qualified Data.HashMap.Strict as Map
    import qualified Data.ByteString.Lazy.Char8 as LBS
    import qualified Data.ByteString.Char8 as BS
    import General.Intern(Id)

    -- | Given a map of representing a dependency order (with a show for error messages), find an ordering for the items such
    --   that no item points to an item before itself.
    --   Raise an error if you end up with a cycle.
    dependencyOrder :: (Eq a, Hashable a) => (a -> String) -> Map.HashMap a [a] -> [a]
    -- Algorithm:
    --    Divide everyone up into those who have no dependencies [Id]
    --    And those who depend on a particular Id, Dep :-> Maybe [(Key,[Dep])]
    --    Where d :-> Just (k, ds), k depends on firstly d, then remaining on ds
    --    For each with no dependencies, add to list, then take its dep hole and
    --    promote them either to Nothing (if ds == []) or into a new slot.
    --    k :-> Nothing means the key has already been freed
    dependencyOrder :: forall a.
    (Eq a, Hashable a) =>
    (a -> String) -> HashMap a [a] -> [a]
    dependencyOrder a -> String
    shw HashMap a [a]
    status = [a] -> HashMap a (Maybe [(a, [a])]) -> [a]
    f (((a, [a]) -> a) -> [(a, [a])] -> [a]
    forall a b. (a -> b) -> [a] -> [b]
    map (a, [a]) -> a
    forall a b. (a, b) -> a
    fst [(a, [a])]
    noDeps) (HashMap a (Maybe [(a, [a])]) -> [a])
    -> HashMap a (Maybe [(a, [a])]) -> [a]
    forall a b. (a -> b) -> a -> b
    $ ([(a, [a])] -> Maybe [(a, [a])])
    -> HashMap a [(a, [a])] -> HashMap a (Maybe [(a, [a])])
    forall v1 v2 k. (v1 -> v2) -> HashMap k v1 -> HashMap k v2
    Map.map [(a, [a])] -> Maybe [(a, [a])]
    forall a. a -> Maybe a
    Just (HashMap a [(a, [a])] -> HashMap a (Maybe [(a, [a])]))
    -> HashMap a [(a, [a])] -> HashMap a (Maybe [(a, [a])])
    forall a b. (a -> b) -> a -> b
    $ ([(a, [a])] -> [(a, [a])] -> [(a, [a])])
    -> [(a, [(a, [a])])] -> HashMap a [(a, [a])]
    forall k v.
    (Eq k, Hashable k) =>
    (v -> v -> v) -> [(k, v)] -> HashMap k v
    Map.fromListWith [(a, [a])] -> [(a, [a])] -> [(a, [a])]
    forall a. [a] -> [a] -> [a]
    (++) [(a
    d, [(a
    k,[a]
    ds)]) | (a
    k,a
    d:[a]
    ds) <- [(a, [a])]
    hasDeps]
        where
            ([(a, [a])]
    noDeps, [(a, [a])]
    hasDeps) = ((a, [a]) -> Bool) -> [(a, [a])] -> ([(a, [a])], [(a, [a])])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition ([a] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null ([a] -> Bool) -> ((a, [a]) -> [a]) -> (a, [a]) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (a, [a]) -> [a]
    forall a b. (a, b) -> b
    snd) ([(a, [a])] -> ([(a, [a])], [(a, [a])]))
    -> [(a, [a])] -> ([(a, [a])], [(a, [a])])
    forall a b. (a -> b) -> a -> b
    $ HashMap a [a] -> [(a, [a])]
    forall k v. HashMap k v -> [(k, v)]
    Map.toList HashMap a [a]
    status

            f :: [a] -> HashMap a (Maybe [(a, [a])]) -> [a]
    f [] HashMap a (Maybe [(a, [a])])
    mp | [String] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [String]
    bad = []
                    | Bool
    otherwise = SomeException -> [a]
    forall a. SomeException -> a
    throwImpure (SomeException -> [a]) -> SomeException -> [a]
    forall a b. (a -> b) -> a -> b
    $ Partial => String -> SomeException
    String -> SomeException
    errorInternal (String -> SomeException) -> String -> SomeException
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unlines ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
                        String
    "Internal invariant broken, database seems to be cyclic" String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :
                        (String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String
    "    " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++) [String]
    bad [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++
                        [String
    "... plus " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall a. Show a => a -> String
    show ([String] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [String]
    badOverflow) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " more ..." | Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ [String] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [String]
    badOverflow]
                where ([String]
    bad,[String]
    badOverflow) = Int -> [String] -> ([String], [String])
    forall a. Int -> [a] -> ([a], [a])
    splitAt Int
    10 [a -> String
    shw a
    i | (a
    i, Just [(a, [a])]
    _) <- HashMap a (Maybe [(a, [a])]) -> [(a, Maybe [(a, [a])])]
    forall k v. HashMap k v -> [(k, v)]
    Map.toList HashMap a (Maybe [(a, [a])])
    mp]

            f (a
    x:[a]
    xs) HashMap a (Maybe [(a, [a])])
    mp = a
    x a -> [a] -> [a]
    forall a. a -> [a] -> [a]
    : [a] -> HashMap a (Maybe [(a, [a])]) -> [a]
    f ([a]
    now[a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    ++[a]
    xs) HashMap a (Maybe [(a, [a])])
    later
                where Just [(a, [a])]
    free = Maybe [(a, [a])]
    -> a -> HashMap a (Maybe [(a, [a])]) -> Maybe [(a, [a])]
    forall k v. (Eq k, Hashable k) => v -> k -> HashMap k v -> v
    Map.lookupDefault ([(a, [a])] -> Maybe [(a, [a])]
    forall a. a -> Maybe a
    Just []) a
    x HashMap a (Maybe [(a, [a])])
    mp
                      ([a]
    now,HashMap a (Maybe [(a, [a])])
    later) = (([a], HashMap a (Maybe [(a, [a])]))
     -> (a, [a]) -> ([a], HashMap a (Maybe [(a, [a])])))
    -> ([a], HashMap a (Maybe [(a, [a])]))
    -> [(a, [a])]
    -> ([a], HashMap a (Maybe [(a, [a])]))
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' ([a], HashMap a (Maybe [(a, [a])]))
    -> (a, [a]) -> ([a], HashMap a (Maybe [(a, [a])]))
    forall {k} {a}.
    Hashable k =>
    ([a], HashMap k (Maybe [(a, [k])]))
    -> (a, [k]) -> ([a], HashMap k (Maybe [(a, [k])]))
    g ([], a
    -> Maybe [(a, [a])]
    -> HashMap a (Maybe [(a, [a])])
    -> HashMap a (Maybe [(a, [a])])
    forall k v.
    (Eq k, Hashable k) =>
    k -> v -> HashMap k v -> HashMap k v
    Map.insert a
    x Maybe [(a, [a])]
    forall a. Maybe a
    Nothing HashMap a (Maybe [(a, [a])])
    mp) [(a, [a])]
    free

            g :: ([a], HashMap k (Maybe [(a, [k])]))
    -> (a, [k]) -> ([a], HashMap k (Maybe [(a, [k])]))
    g ([a]
    free, HashMap k (Maybe [(a, [k])])
    mp) (a
    k, []) = (a
    ka -> [a] -> [a]
    forall a. a -> [a] -> [a]
    :[a]
    free, HashMap k (Maybe [(a, [k])])
    mp)
            g ([a]
    free, HashMap k (Maybe [(a, [k])])
    mp) (a
    k, k
    d:[k]
    ds) = case Maybe [(a, [k])]
    -> k -> HashMap k (Maybe [(a, [k])]) -> Maybe [(a, [k])]
    forall k v. (Eq k, Hashable k) => v -> k -> HashMap k v -> v
    Map.lookupDefault ([(a, [k])] -> Maybe [(a, [k])]
    forall a. a -> Maybe a
    Just []) k
    d HashMap k (Maybe [(a, [k])])
    mp of
                Maybe [(a, [k])]
    Nothing -> ([a], HashMap k (Maybe [(a, [k])]))
    -> (a, [k]) -> ([a], HashMap k (Maybe [(a, [k])]))
    g ([a]
    free, HashMap k (Maybe [(a, [k])])
    mp) (a
    k, [k]
    ds)
                Just [(a, [k])]
    todo -> ([a]
    free, k
    -> Maybe [(a, [k])]
    -> HashMap k (Maybe [(a, [k])])
    -> HashMap k (Maybe [(a, [k])])
    forall k v.
    (Eq k, Hashable k) =>
    k -> v -> HashMap k v -> HashMap k v
    Map.insert k
    d ([(a, [k])] -> Maybe [(a, [k])]
    forall a. a -> Maybe a
    Just ([(a, [k])] -> Maybe [(a, [k])]) -> [(a, [k])] -> Maybe [(a, [k])]
    forall a b. (a -> b) -> a -> b
    $ (a
    k,[k]
    ds) (a, [k]) -> [(a, [k])] -> [(a, [k])]
    forall a. a -> [a] -> [a]
    : [(a, [k])]
    todo) HashMap k (Maybe [(a, [k])])
    mp)

    -- | Eliminate all errors from the database, pretending they don't exist
    resultsOnly :: Map.HashMap Id (Key, Status) -> Map.HashMap Id (Key, Result (Either BS.ByteString Value))
    resultsOnly :: HashMap Id (Key, Status)
    -> HashMap Id (Key, Result (Either ByteString Value))
    resultsOnly HashMap Id (Key, Status)
    mp = ((Key, Status) -> (Key, Result (Either ByteString Value)))
    -> HashMap Id (Key, Status)
    -> HashMap Id (Key, Result (Either ByteString Value))
    forall v1 v2 k. (v1 -> v2) -> HashMap k v1 -> HashMap k v2
    Map.map (\(Key
    k, Status
    v) -> (Key
    k, let Just Result (Either ByteString Value)
    r = Status -> Maybe (Result (Either ByteString Value))
    getResult Status
    v in Result (Either ByteString Value)
    r{depends = map (Depends . filter (isJust . flip Map.lookup keep) . fromDepends) $ depends r})) HashMap Id (Key, Status)
    keep
        where keep :: HashMap Id (Key, Status)
    keep = ((Key, Status) -> Bool)
    -> HashMap Id (Key, Status) -> HashMap Id (Key, Status)
    forall v k. (v -> Bool) -> HashMap k v -> HashMap k v
    Map.filter (Maybe (Result (Either ByteString Value)) -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe (Result (Either ByteString Value)) -> Bool)
    -> ((Key, Status) -> Maybe (Result (Either ByteString Value)))
    -> (Key, Status)
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Status -> Maybe (Result (Either ByteString Value))
    getResult (Status -> Maybe (Result (Either ByteString Value)))
    -> ((Key, Status) -> Status)
    -> (Key, Status)
    -> Maybe (Result (Either ByteString Value))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Key, Status) -> Status
    forall a b. (a, b) -> b
    snd) HashMap Id (Key, Status)
    mp

    removeStep :: Map.HashMap Id (Key, Result a) -> Map.HashMap Id (Key, Result a)
    removeStep :: forall a. HashMap Id (Key, Result a) -> HashMap Id (Key, Result a)
    removeStep = ((Key, Result a) -> Bool)
    -> HashMap Id (Key, Result a) -> HashMap Id (Key, Result a)
    forall v k. (v -> Bool) -> HashMap k v -> HashMap k v
    Map.filter (\(Key
    k,Result a
    _) -> Key
    k Key -> Key -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Key
    stepKey)

    toReport :: Database -> IO [ProfileEntry]
    toReport :: Database -> IO [ProfileEntry]
    toReport Database
    db = do
        status <- HashMap Id (Key, Result (Either ByteString Value))
    -> HashMap Id (Key, Result (Either ByteString Value))
    forall a. HashMap Id (Key, Result a) -> HashMap Id (Key, Result a)
    removeStep (HashMap Id (Key, Result (Either ByteString Value))
     -> HashMap Id (Key, Result (Either ByteString Value)))
    -> (HashMap Id (Key, Status)
        -> HashMap Id (Key, Result (Either ByteString Value)))
    -> HashMap Id (Key, Status)
    -> HashMap Id (Key, Result (Either ByteString Value))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HashMap Id (Key, Status)
    -> HashMap Id (Key, Result (Either ByteString Value))
    resultsOnly (HashMap Id (Key, Status)
     -> HashMap Id (Key, Result (Either ByteString Value)))
    -> IO (HashMap Id (Key, Status))
    -> IO (HashMap Id (Key, Result (Either ByteString Value)))
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Database -> IO (HashMap Id (Key, Status))
    forall k v. DatabasePoly k v -> IO (HashMap Id (k, v))
    getKeyValuesFromId Database
    db
        let order = let shw :: Id -> String
    shw Id
    i = String
    -> ((Key, Result (Either ByteString Value)) -> String)
    -> Maybe (Key, Result (Either ByteString Value))
    -> String
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe String
    "<unknown>" (Key -> String
    forall a. Show a => a -> String
    show (Key -> String)
    -> ((Key, Result (Either ByteString Value)) -> Key)
    -> (Key, Result (Either ByteString Value))
    -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Key, Result (Either ByteString Value)) -> Key
    forall a b. (a, b) -> a
    fst) (Maybe (Key, Result (Either ByteString Value)) -> String)
    -> Maybe (Key, Result (Either ByteString Value)) -> String
    forall a b. (a -> b) -> a -> b
    $ Id
    -> HashMap Id (Key, Result (Either ByteString Value))
    -> Maybe (Key, Result (Either ByteString Value))
    forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
    Map.lookup Id
    i HashMap Id (Key, Result (Either ByteString Value))
    status
                    in (Id -> String) -> HashMap Id [Id] -> [Id]
    forall a.
    (Eq a, Hashable a) =>
    (a -> String) -> HashMap a [a] -> [a]
    dependencyOrder Id -> String
    shw (HashMap Id [Id] -> [Id]) -> HashMap Id [Id] -> [Id]
    forall a b. (a -> b) -> a -> b
    $ ((Key, Result (Either ByteString Value)) -> [Id])
    -> HashMap Id (Key, Result (Either ByteString Value))
    -> HashMap Id [Id]
    forall v1 v2 k. (v1 -> v2) -> HashMap k v1 -> HashMap k v2
    Map.map ((Depends -> [Id]) -> [Depends] -> [Id]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap Depends -> [Id]
    fromDepends ([Depends] -> [Id])
    -> ((Key, Result (Either ByteString Value)) -> [Depends])
    -> (Key, Result (Either ByteString Value))
    -> [Id]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Result (Either ByteString Value) -> [Depends]
    forall a. Result a -> [Depends]
    depends (Result (Either ByteString Value) -> [Depends])
    -> ((Key, Result (Either ByteString Value))
        -> Result (Either ByteString Value))
    -> (Key, Result (Either ByteString Value))
    -> [Depends]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Key, Result (Either ByteString Value))
    -> Result (Either ByteString Value)
    forall a b. (a, b) -> b
    snd) HashMap Id (Key, Result (Either ByteString Value))
    status
            ids = [(Id, Int)] -> HashMap Id Int
    forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
    Map.fromList ([(Id, Int)] -> HashMap Id Int) -> [(Id, Int)] -> HashMap Id Int
    forall a b. (a -> b) -> a -> b
    $ [Id] -> [Int] -> [(Id, Int)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Id]
    order [Int
    0..]

            steps = let xs :: [Step]
    xs = HashSet Step -> [Step]
    forall a. HashSet a -> [a]
    Set.toList (HashSet Step -> [Step]) -> HashSet Step -> [Step]
    forall a b. (a -> b) -> a -> b
    $ [Step] -> HashSet Step
    forall a. (Eq a, Hashable a) => [a] -> HashSet a
    Set.fromList ([Step] -> HashSet Step) -> [Step] -> HashSet Step
    forall a b. (a -> b) -> a -> b
    $ [[Step]] -> [Step]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat [[Step
    changed, Step
    built] | (Key
    _,Result{Float
    [Depends]
    [Trace]
    Either ByteString Value
    Step
    depends :: forall a. Result a -> [Depends]
    changed :: Step
    built :: Step
    result :: Either ByteString Value
    depends :: [Depends]
    execution :: Float
    traces :: [Trace]
    traces :: forall a. Result a -> [Trace]
    execution :: forall a. Result a -> Float
    changed :: forall a. Result a -> Step
    built :: forall a. Result a -> Step
    result :: forall a. Result a -> a
    ..}) <- HashMap Id (Key, Result (Either ByteString Value))
    -> [(Key, Result (Either ByteString Value))]
    forall k v. HashMap k v -> [v]
    Map.elems HashMap Id (Key, Result (Either ByteString Value))
    status]
                    in [(Step, Int)] -> HashMap Step Int
    forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
    Map.fromList ([(Step, Int)] -> HashMap Step Int)
    -> [(Step, Int)] -> HashMap Step Int
    forall a b. (a -> b) -> a -> b
    $ [Step] -> [Int] -> [(Step, Int)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip ((Step -> Step -> Ordering) -> [Step] -> [Step]
    forall a. (a -> a -> Ordering) -> [a] -> [a]
    sortBy ((Step -> Step -> Ordering) -> Step -> Step -> Ordering
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Step -> Step -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare) [Step]
    xs) [Int
    0..]

            f (a
    k, Result{a
    Float
    [Depends]
    [Trace]
    Step
    depends :: forall a. Result a -> [Depends]
    traces :: forall a. Result a -> [Trace]
    execution :: forall a. Result a -> Float
    changed :: forall a. Result a -> Step
    built :: forall a. Result a -> Step
    result :: forall a. Result a -> a
    result :: a
    built :: Step
    changed :: Step
    depends :: [Depends]
    execution :: Float
    traces :: [Trace]
    ..}) = ProfileEntry
                {prfName :: String
    prfName = a -> String
    forall a. Show a => a -> String
    show a
    k
                ,prfBuilt :: Int
    prfBuilt = Step -> Int
    fromStep Step
    built
                ,prfChanged :: Int
    prfChanged = Step -> Int
    fromStep Step
    changed
                ,prfDepends :: [[Int]]
    prfDepends = ([Int] -> Bool) -> [[Int]] -> [[Int]]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Bool -> Bool
    not (Bool -> Bool) -> ([Int] -> Bool) -> [Int] -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Int] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null) ([[Int]] -> [[Int]]) -> [[Int]] -> [[Int]]
    forall a b. (a -> b) -> a -> b
    $ (Depends -> [Int]) -> [Depends] -> [[Int]]
    forall a b. (a -> b) -> [a] -> [b]
    map ((Id -> Maybe Int) -> [Id] -> [Int]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe (Id -> HashMap Id Int -> Maybe Int
    forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
    `Map.lookup` HashMap Id Int
    ids) ([Id] -> [Int]) -> (Depends -> [Id]) -> Depends -> [Int]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Depends -> [Id]
    fromDepends) [Depends]
    depends
                ,prfExecution :: Double
    prfExecution = Float -> Double
    floatToDouble Float
    execution
                ,prfTraces :: [ProfileTrace]
    prfTraces = (Trace -> ProfileTrace) -> [Trace] -> [ProfileTrace]
    forall a b. (a -> b) -> [a] -> [b]
    map Trace -> ProfileTrace
    fromTrace ([Trace] -> [ProfileTrace]) -> [Trace] -> [ProfileTrace]
    forall a b. (a -> b) -> a -> b
    $ (Trace -> Float) -> [Trace] -> [Trace]
    forall b a. Ord b => (a -> b) -> [a] -> [a]
    sortOn Trace -> Float
    traceStart [Trace]
    traces
                }
                where fromStep :: Step -> Int
    fromStep Step
    i = Maybe Int -> Int
    forall a. Partial => Maybe a -> a
    fromJust (Maybe Int -> Int) -> Maybe Int -> Int
    forall a b. (a -> b) -> a -> b
    $ Step -> HashMap Step Int -> Maybe Int
    forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
    Map.lookup Step
    i HashMap Step Int
    steps
                      fromTrace :: Trace -> ProfileTrace
    fromTrace (Trace ByteString
    a Float
    b Float
    c) = String -> Double -> Double -> ProfileTrace
    ProfileTrace (ByteString -> String
    BS.unpack ByteString
    a) (Float -> Double
    floatToDouble Float
    b) (Float -> Double
    floatToDouble Float
    c)
        pure [maybe (throwImpure $ errorInternal "toReport") f $ Map.lookup i status | i <- order]

    data ProfileEntry = ProfileEntry
        {ProfileEntry -> String
    prfName :: String, ProfileEntry -> Int
    prfBuilt :: Int, ProfileEntry -> Int
    prfChanged :: Int, ProfileEntry -> [[Int]]
    prfDepends :: [[Int]], ProfileEntry -> Double
    prfExecution :: Double, ProfileEntry -> [ProfileTrace]
    prfTraces :: [ProfileTrace]}
    data ProfileTrace = ProfileTrace
        {ProfileTrace -> String
    prfCommand :: String, ProfileTrace -> Double
    prfStart :: Double, ProfileTrace -> Double
    prfStop :: Double}
    prfTime :: ProfileTrace -> Double
    prfTime ProfileTrace{Double
    String
    prfCommand :: ProfileTrace -> String
    prfStart :: ProfileTrace -> Double
    prfStop :: ProfileTrace -> Double
    prfCommand :: String
    prfStart :: Double
    prfStop :: Double
    ..} = Double
    prfStop Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    prfStart

    -- | Generates an report given some build system profiling data.
    writeProfile :: FilePath -> Database -> IO ()
    writeProfile :: String -> Database -> IO ()
    writeProfile String
    out Database
    db = String -> [ProfileEntry] -> IO ()
    writeProfileInternal String
    out ([ProfileEntry] -> IO ()) -> IO [ProfileEntry] -> IO ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< Database -> IO [ProfileEntry]
    toReport Database
    db

    writeProfileInternal :: FilePath -> [ProfileEntry] -> IO ()
    writeProfileInternal :: String -> [ProfileEntry] -> IO ()
    writeProfileInternal String
    out [ProfileEntry]
    xs
        | String -> String
    takeExtension String
    out String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    ".js" = String -> String -> IO ()
    writeFileBinary String
    out (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String
    "var profile = \n" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [ProfileEntry] -> String
    generateJSON [ProfileEntry]
    xs
        | String -> String
    takeExtension String
    out String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    ".json" = String -> String -> IO ()
    writeFileBinary String
    out (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ [ProfileEntry] -> String
    generateJSON [ProfileEntry]
    xs
        | String -> String
    takeExtension String
    out String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    ".trace" = String -> String -> IO ()
    writeFileBinary String
    out (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ [ProfileEntry] -> String
    generateTrace [ProfileEntry]
    xs
        | String
    out String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    "-" = String -> IO ()
    putStr (String -> IO ()) -> String -> IO ()
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unlines ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ [ProfileEntry] -> [String]
    generateSummary [ProfileEntry]
    xs
        -- NOTE: On my laptop writing 1.5Mb of profile report takes 0.6s.
        --       This is fundamentals of my laptop, not a Haskell profiling issue.
        --       Verified with similar "type foo > bar" commands taking similar time.
        | Bool
    otherwise = String -> ByteString -> IO ()
    LBS.writeFile String
    out (ByteString -> IO ()) -> IO ByteString -> IO ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< [ProfileEntry] -> IO ByteString
    generateHTML [ProfileEntry]
    xs

    generateSummary :: [ProfileEntry] -> [String]
    generateSummary :: [ProfileEntry] -> [String]
    generateSummary [ProfileEntry]
    xs =
        [String
    "* This database has tracked " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> String
    forall a. Show a => a -> String
    show ([Int] -> Int
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum (Int
    0 Int -> [Int] -> [Int]
    forall a. a -> [a] -> [a]
    : (ProfileEntry -> Int) -> [ProfileEntry] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileEntry -> Int
    prfChanged [ProfileEntry]
    xs) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " runs."
        ,let f :: [a] -> String
    f = Int -> String
    forall a. Show a => a -> String
    show (Int -> String) -> ([a] -> Int) -> [a] -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [a] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length in String
    "* There are " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [ProfileEntry] -> String
    forall {a}. [a] -> String
    f [ProfileEntry]
    xs String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " rules (" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [ProfileEntry] -> String
    forall {a}. [a] -> String
    f [ProfileEntry]
    ls String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " rebuilt in the last run)."
        ,let f :: [ProfileEntry] -> String
    f = Int -> String
    forall a. Show a => a -> String
    show (Int -> String)
    -> ([ProfileEntry] -> Int) -> [ProfileEntry] -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Int] -> Int
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum ([Int] -> Int)
    -> ([ProfileEntry] -> [Int]) -> [ProfileEntry] -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ProfileEntry -> Int) -> [ProfileEntry] -> [Int]
    forall a b. (a -> b) -> [a] -> [b]
    map ([ProfileTrace] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length ([ProfileTrace] -> Int)
    -> (ProfileEntry -> [ProfileTrace]) -> ProfileEntry -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ProfileEntry -> [ProfileTrace]
    prfTraces) in String
    "* Building required " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [ProfileEntry] -> String
    f [ProfileEntry]
    xs String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " traced commands (" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [ProfileEntry] -> String
    f [ProfileEntry]
    ls String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " in the last run)."
        ,String
    "* The total (unparallelised) time is " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Double -> String
    showDuration ([Double] -> Double
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum ([Double] -> Double) -> [Double] -> Double
    forall a b. (a -> b) -> a -> b
    $ (ProfileEntry -> Double) -> [ProfileEntry] -> [Double]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileEntry -> Double
    prfExecution [ProfileEntry]
    xs) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
            String
    " of which " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Double -> String
    showDuration ([Double] -> Double
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum ([Double] -> Double) -> [Double] -> Double
    forall a b. (a -> b) -> a -> b
    $ (ProfileTrace -> Double) -> [ProfileTrace] -> [Double]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileTrace -> Double
    prfTime ([ProfileTrace] -> [Double]) -> [ProfileTrace] -> [Double]
    forall a b. (a -> b) -> a -> b
    $ (ProfileEntry -> [ProfileTrace])
    -> [ProfileEntry] -> [ProfileTrace]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap ProfileEntry -> [ProfileTrace]
    prfTraces [ProfileEntry]
    xs) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " is traced commands."
        ,let f :: [(Double, String)] -> String
    f [(Double, String)]
    xs = if [(Double, String)] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [(Double, String)]
    xs then String
    "0s" else (\(Double
    a,String
    b) -> Double -> String
    showDuration Double
    a String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " (" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    b String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ")") ((Double, String) -> String) -> (Double, String) -> String
    forall a b. (a -> b) -> a -> b
    $ ((Double, String) -> (Double, String) -> Ordering)
    -> [(Double, String)] -> (Double, String)
    forall a. (a -> a -> Ordering) -> [a] -> a
    maximumBy' (Double -> Double -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare (Double -> Double -> Ordering)
    -> ((Double, String) -> Double)
    -> (Double, String)
    -> (Double, String)
    -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` (Double, String) -> Double
    forall a b. (a, b) -> a
    fst) [(Double, String)]
    xs in
            String
    "* The longest rule takes " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [(Double, String)] -> String
    f ((ProfileEntry -> (Double, String))
    -> [ProfileEntry] -> [(Double, String)]
    forall a b. (a -> b) -> [a] -> [b]
    map (ProfileEntry -> Double
    prfExecution (ProfileEntry -> Double)
    -> (ProfileEntry -> String) -> ProfileEntry -> (Double, String)
    forall a b c. (a -> b) -> (a -> c) -> a -> (b, c)
    &&& ProfileEntry -> String
    prfName) [ProfileEntry]
    xs) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
            String
    ", and the longest traced command takes " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [(Double, String)] -> String
    f ((ProfileTrace -> (Double, String))
    -> [ProfileTrace] -> [(Double, String)]
    forall a b. (a -> b) -> [a] -> [b]
    map (ProfileTrace -> Double
    prfTime (ProfileTrace -> Double)
    -> (ProfileTrace -> String) -> ProfileTrace -> (Double, String)
    forall a b c. (a -> b) -> (a -> c) -> a -> (b, c)
    &&& ProfileTrace -> String
    prfCommand) ([ProfileTrace] -> [(Double, String)])
    -> [ProfileTrace] -> [(Double, String)]
    forall a b. (a -> b) -> a -> b
    $ (ProfileEntry -> [ProfileTrace])
    -> [ProfileEntry] -> [ProfileTrace]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap ProfileEntry -> [ProfileTrace]
    prfTraces [ProfileEntry]
    xs) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "."
        ,let sumLast :: Double
    sumLast = [Double] -> Double
    forall a. Num a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum ([Double] -> Double) -> [Double] -> Double
    forall a b. (a -> b) -> a -> b
    $ (ProfileTrace -> Double) -> [ProfileTrace] -> [Double]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileTrace -> Double
    prfTime ([ProfileTrace] -> [Double]) -> [ProfileTrace] -> [Double]
    forall a b. (a -> b) -> a -> b
    $ (ProfileEntry -> [ProfileTrace])
    -> [ProfileEntry] -> [ProfileTrace]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap ProfileEntry -> [ProfileTrace]
    prfTraces [ProfileEntry]
    ls
             maxStop :: Double
    maxStop = [Double] -> Double
    forall a. Ord a => [a] -> a
    forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
    maximum ([Double] -> Double) -> [Double] -> Double
    forall a b. (a -> b) -> a -> b
    $ Double
    0 Double -> [Double] -> [Double]
    forall a. a -> [a] -> [a]
    : (ProfileTrace -> Double) -> [ProfileTrace] -> [Double]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileTrace -> Double
    prfStop ((ProfileEntry -> [ProfileTrace])
    -> [ProfileEntry] -> [ProfileTrace]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap ProfileEntry -> [ProfileTrace]
    prfTraces [ProfileEntry]
    ls) in
            String
    "* Last run gave an average parallelism of " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Int -> Double -> String
    forall a. RealFloat a => Int -> a -> String
    showDP Int
    2 (if Double
    maxStop Double -> Double -> Bool
    forall a. Eq a => a -> a -> Bool
    == Double
    0 then Double
    0 else Double
    sumLast Double -> Double -> Double
    forall a. Fractional a => a -> a -> a
    / Double
    maxStop) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++
            String
    " times over " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Double -> String
    showDuration Double
    maxStop String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "."
        ]
        where ls :: [ProfileEntry]
    ls = (ProfileEntry -> Bool) -> [ProfileEntry] -> [ProfileEntry]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) Int
    0 (Int -> Bool) -> (ProfileEntry -> Int) -> ProfileEntry -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ProfileEntry -> Int
    prfBuilt) [ProfileEntry]
    xs

    generateHTML :: [ProfileEntry] -> IO LBS.ByteString
    generateHTML :: [ProfileEntry] -> IO ByteString
    generateHTML [ProfileEntry]
    xs = do
        report <- String -> IO ByteString
    readDataFileHTML String
    "profile.html"
        let f String
    "data/profile-data.js" = ByteString -> f ByteString
    forall a. a -> f a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (ByteString -> f ByteString) -> ByteString -> f ByteString
    forall a b. (a -> b) -> a -> b
    $ String -> ByteString
    LBS.pack (String -> ByteString) -> String -> ByteString
    forall a b. (a -> b) -> a -> b
    $ String
    "var profile =\n" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [ProfileEntry] -> String
    generateJSON [ProfileEntry]
    xs
        runTemplate f report

    generateTrace :: [ProfileEntry] -> String
    generateTrace :: [ProfileEntry] -> String
    generateTrace [ProfileEntry]
    xs = [String] -> String
    jsonListLines ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
        Integer -> [ProfileTrace] -> [String]
    forall {a}. Show a => a -> [ProfileTrace] -> [String]
    showEntries Integer
    0 [ProfileTrace
    y{prfCommand=prfName x} | ProfileEntry
    x <- [ProfileEntry]
    onlyLast, ProfileTrace
    y <- ProfileEntry -> [ProfileTrace]
    prfTraces ProfileEntry
    x] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++
        Integer -> [ProfileTrace] -> [String]
    forall {a}. Show a => a -> [ProfileTrace] -> [String]
    showEntries Integer
    1 ((ProfileEntry -> [ProfileTrace])
    -> [ProfileEntry] -> [ProfileTrace]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap ProfileEntry -> [ProfileTrace]
    prfTraces [ProfileEntry]
    onlyLast)
        where
            onlyLast :: [ProfileEntry]
    onlyLast = (ProfileEntry -> Bool) -> [ProfileEntry] -> [ProfileEntry]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (\ProfileEntry
    x -> ProfileEntry -> Int
    prfBuilt ProfileEntry
    x Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    0) [ProfileEntry]
    xs
            showEntries :: a -> [ProfileTrace] -> [String]
    showEntries a
    pid [ProfileTrace]
    xs = ((Int, ProfileTrace) -> String)
    -> [(Int, ProfileTrace)] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (a -> (Int, ProfileTrace) -> String
    forall {a} {a}.
    (Show a, Show a) =>
    a -> (a, ProfileTrace) -> String
    showEntry a
    pid) ([(Int, ProfileTrace)] -> [String])
    -> [(Int, ProfileTrace)] -> [String]
    forall a b. (a -> b) -> a -> b
    $ ([ProfileTrace], [(Int, ProfileTrace)]) -> [(Int, ProfileTrace)]
    forall a b. (a, b) -> b
    snd (([ProfileTrace], [(Int, ProfileTrace)]) -> [(Int, ProfileTrace)])
    -> ([ProfileTrace], [(Int, ProfileTrace)]) -> [(Int, ProfileTrace)]
    forall a b. (a -> b) -> a -> b
    $ ([ProfileTrace]
     -> ProfileTrace -> ([ProfileTrace], (Int, ProfileTrace)))
    -> [ProfileTrace]
    -> [ProfileTrace]
    -> ([ProfileTrace], [(Int, ProfileTrace)])
    forall (t :: * -> *) s a b.
    Traversable t =>
    (s -> a -> (s, b)) -> s -> t a -> (s, t b)
    mapAccumL [ProfileTrace]
    -> ProfileTrace -> ([ProfileTrace], (Int, ProfileTrace))
    alloc [] ([ProfileTrace] -> ([ProfileTrace], [(Int, ProfileTrace)]))
    -> [ProfileTrace] -> ([ProfileTrace], [(Int, ProfileTrace)])
    forall a b. (a -> b) -> a -> b
    $ (ProfileTrace -> Double) -> [ProfileTrace] -> [ProfileTrace]
    forall b a. Ord b => (a -> b) -> [a] -> [a]
    sortOn ProfileTrace -> Double
    prfStart [ProfileTrace]
    xs

            alloc :: [ProfileTrace] -> ProfileTrace -> ([ProfileTrace], (Int, ProfileTrace))
            -- FIXME: I don't really understand what this code is doing, or the invariants it ensures
            alloc :: [ProfileTrace]
    -> ProfileTrace -> ([ProfileTrace], (Int, ProfileTrace))
    alloc [ProfileTrace]
    as ProfileTrace
    r | ([ProfileTrace]
    a1,ProfileTrace
    _:[ProfileTrace]
    a2) <- (ProfileTrace -> Bool)
    -> [ProfileTrace] -> ([ProfileTrace], [ProfileTrace])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (\ProfileTrace
    a -> ProfileTrace -> Double
    prfStop ProfileTrace
    a Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    <= ProfileTrace -> Double
    prfStart ProfileTrace
    r) [ProfileTrace]
    as = ([ProfileTrace]
    a1[ProfileTrace] -> [ProfileTrace] -> [ProfileTrace]
    forall a. [a] -> [a] -> [a]
    ++ProfileTrace
    rProfileTrace -> [ProfileTrace] -> [ProfileTrace]
    forall a. a -> [a] -> [a]
    :[ProfileTrace]
    a2, ([ProfileTrace] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [ProfileTrace]
    a1,ProfileTrace
    r))
                       | Bool
    otherwise = ([ProfileTrace]
    as[ProfileTrace] -> [ProfileTrace] -> [ProfileTrace]
    forall a. [a] -> [a] -> [a]
    ++[ProfileTrace
    r], ([ProfileTrace] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [ProfileTrace]
    as,ProfileTrace
    r))

            showEntry :: a -> (a, ProfileTrace) -> String
    showEntry a
    pid (a
    tid, ProfileTrace{Double
    String
    prfCommand :: ProfileTrace -> String
    prfStart :: ProfileTrace -> Double
    prfStop :: ProfileTrace -> Double
    prfCommand :: String
    prfStart :: Double
    prfStop :: Double
    ..}) = [(String, String)] -> String
    forall {a}. Show a => [(a, String)] -> String
    jsonObject
                [(String
    "args",String
    "{}"), (String
    "ph",String -> String
    forall a. Show a => a -> String
    show String
    "X"), (String
    "cat",String -> String
    forall a. Show a => a -> String
    show String
    "target")
                ,(String
    "name",String -> String
    forall a. Show a => a -> String
    show String
    prfCommand), (String
    "tid",a -> String
    forall a. Show a => a -> String
    show a
    tid), (String
    "pid",a -> String
    forall a. Show a => a -> String
    show a
    pid)
                ,(String
    "ts",Double -> String
    forall a. Show a => a -> String
    show (Double -> String) -> Double -> String
    forall a b. (a -> b) -> a -> b
    $ Double
    1000000Double -> Double -> Double
    forall a. Num a => a -> a -> a
    *Double
    prfStart), (String
    "dur",Double -> String
    forall a. Show a => a -> String
    show (Double -> String) -> Double -> String
    forall a b. (a -> b) -> a -> b
    $ Double
    1000000Double -> Double -> Double
    forall a. Num a => a -> a -> a
    *(Double
    prfStopDouble -> Double -> Double
    forall a. Num a => a -> a -> a
    -Double
    prfStart))]

    generateJSON :: [ProfileEntry] -> String
    generateJSON :: [ProfileEntry] -> String
    generateJSON = [String] -> String
    jsonListLines ([String] -> String)
    -> ([ProfileEntry] -> [String]) -> [ProfileEntry] -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ProfileEntry -> String) -> [ProfileEntry] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileEntry -> String
    showEntry
        where
            showEntry :: ProfileEntry -> String
    showEntry ProfileEntry{Double
    Int
    String
    [[Int]]
    [ProfileTrace]
    prfName :: ProfileEntry -> String
    prfBuilt :: ProfileEntry -> Int
    prfChanged :: ProfileEntry -> Int
    prfDepends :: ProfileEntry -> [[Int]]
    prfExecution :: ProfileEntry -> Double
    prfTraces :: ProfileEntry -> [ProfileTrace]
    prfName :: String
    prfBuilt :: Int
    prfChanged :: Int
    prfDepends :: [[Int]]
    prfExecution :: Double
    prfTraces :: [ProfileTrace]
    ..} = [String] -> String
    jsonList ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
                [String -> String
    forall a. Show a => a -> String
    show String
    prfName
                ,Double -> String
    forall {p}. RealFloat p => p -> String
    showTime Double
    prfExecution
                ,Int -> String
    forall a. Show a => a -> String
    show Int
    prfBuilt
                ,Int -> String
    forall a. Show a => a -> String
    show Int
    prfChanged] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++
                [[[Int]] -> String
    forall a. Show a => a -> String
    show [[Int]]
    prfDepends | Bool -> Bool
    not ([[Int]] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [[Int]]
    prfDepends) Bool -> Bool -> Bool
    || Bool -> Bool
    not ([ProfileTrace] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [ProfileTrace]
    prfTraces)] [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++
                [[String] -> String
    jsonList ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $ (ProfileTrace -> String) -> [ProfileTrace] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map ProfileTrace -> String
    showTrace [ProfileTrace]
    prfTraces | Bool -> Bool
    not ([ProfileTrace] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [ProfileTrace]
    prfTraces)]
            showTrace :: ProfileTrace -> String
    showTrace ProfileTrace{Double
    String
    prfCommand :: ProfileTrace -> String
    prfStart :: ProfileTrace -> Double
    prfStop :: ProfileTrace -> Double
    prfCommand :: String
    prfStart :: Double
    prfStop :: Double
    ..} = [String] -> String
    jsonList
                [String -> String
    forall a. Show a => a -> String
    show String
    prfCommand, Double -> String
    forall {p}. RealFloat p => p -> String
    showTime Double
    prfStart, Double -> String
    forall {p}. RealFloat p => p -> String
    showTime Double
    prfStop]
            showTime :: p -> String
    showTime p
    x = if Char
    '.' Char -> String -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` String
    y then (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhileEnd (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '.') (String -> String) -> String -> String
    forall a b. (a -> b) -> a -> b
    $ (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhileEnd (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == Char
    '0') String
    y else String
    y
                where y :: String
    y = Int -> p -> String
    forall a. RealFloat a => Int -> a -> String
    showDP Int
    4 p
    x

    jsonListLines :: [String] -> String
    jsonListLines [String]
    xs = String
    "[" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "\n," [String]
    xs String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "\n]"
    jsonList :: [String] -> String
    jsonList [String]
    xs = String
    "[" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "," [String]
    xs String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "]"
    jsonObject :: [(a, String)] -> String
    jsonObject [(a, String)]
    xs = String
    "{" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate String
    "," [a -> String
    forall a. Show a => a -> String
    show a
    a String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ":" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    b | (a
    a,String
    b) <- [(a, String)]
    xs] String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "}"