{- Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. -} module Glean.Util.Metric ( Tick(..), Point(..), beginTick, endTick, endTicks, showLatency, showThroughput, tickLatencyNanoSecs, tickMillis, showMemory, showCount, pad ) where import Data.List (find) import Data.Word import System.Clock data Tick = Tick { tickValue :: !Word64 , tickDuration :: !TimeSpec } instance Semigroup Tick where Tick v1 d1 <> Tick v2 d2 = Tick (v1+v2) (d1+d2) instance Monoid Tick where mempty = Tick 0 0 showLatency :: Tick -> String showLatency = pad 5 . f where f (Tick 0 _) = "-" f tick = display $ tickLatencyNanoSecs tick display n | n <= 2000 = show n ++ "ns" | n <= 2000000 = show (n `div` 1000) ++ "us" | n <= 2000000000 = show (n `div` 1000000) ++ "ms" | otherwise = show (n `div` 1000000000) ++ "s" tickLatencyNanoSecs :: Tick -> Integer tickLatencyNanoSecs (Tick value time) = toNanoSecs time `div` fromIntegral value showScaled :: [(Word64, String)] -> Word64 -> String showScaled scale value | Just (k,sfx) <- find ((value >=) . fst) scale = let n = (value * 10) `div` k in concat [show $ n `div` 10, ".", show $ n `mod` 10, sfx] | otherwise = show value showThroughput :: Tick -> String showThroughput = pad 9 . f where f tick | ms == 0 = "-" | otherwise = showScaled deciscale rate ++ "B/s" where ms = tickMillis tick rate = (tickValue tick * 1000) `div` ms deciscale :: [(Word64, String)] deciscale = [(1000*1000*1000, "G"), (1000*1000, "M"), (1000, "K")] tickMillis :: Tick -> Word64 tickMillis (Tick _ time) = fromIntegral $ sec time * 1000 + nsec time `div` 1000000 data Point = Point { pointValue :: !Word64 , pointStart :: !TimeSpec } beginTick :: Word64 -> IO Point beginTick value = Point value <$> getTime Monotonic endTick :: Point -> IO Tick endTick (Point value start) = do now <- getTime Monotonic return $ Tick value (now - start) endTicks :: [Point] -> IO [Tick] endTicks ticks = do now <- getTime Monotonic return [Tick value (now - start) | Point value start <- ticks] showMemory :: Word64 -> String showMemory n = showScaled deciscale n ++ "B" showCount :: Word64 -> String showCount n = showScaled deciscale n pad :: Int -> String -> String pad n s = replicate (n - length s) ' ' <> s