packages feed

sectile-0.1.0.0: src/Data/Sectile/System/Linux/Cpu.hs

-- |
-- Module        : Data.Sectile.System.Linux.Cpu
-- Copyright     : Gautier DI FOLCO
-- License       : ISC
--
-- Maintainer    : Gautier DI FOLCO <foss@difolco.dev>
-- Stability     : Stable
-- Portability   : Portable
module Data.Sectile.System.Linux.Cpu (cpu) where

import qualified Data.Aeson as Aeson
import qualified Data.HashMap.Strict as HashMap
import Data.Maybe (mapMaybe)
import Data.Sectile.System.Linux.Internal
import Data.Sectile.Types
import qualified Data.Text as T

-- | Display CPU usage percentage by reading @\/proc\/stat@.
--
-- Shows the aggregate CPU usage as a percentage.
--
-- Example:
--
-- > import Data.Sectile
-- >
-- > cpuSegment :: Segment IO
-- > cpuSegment = cpu "cpu"
-- > -- Renders e.g. "5.6%"
cpu :: Name -> Segment IO
cpu name@(Name nameB) =
  Segment $ do
    result <- tryReadFile "/proc/stat"
    let (txt, bnds) = case result of
          Right content ->
            case parseCpuUsage name content of
              Just (formatted, b) -> (formatted, b)
              Nothing -> (errMsg nameB, HashMap.empty)
          Left _ -> (errMsg nameB, HashMap.empty)
    pure $ do
      _ <- appendBindings bnds
      mkFormatted nameB "cpu" txt []

-- | Parse /proc/stat cpu line to get usage percentage.
parseCpuUsage :: Name -> T.Text -> Maybe (T.Text, HashMap.HashMap T.Text Aeson.Value)
parseCpuUsage name content =
  let lns = T.lines content
   in case filter (T.isPrefixOf "cpu ") lns of
        (cpuLine : _) ->
          let ws = drop 1 $ T.words cpuLine
              nums = mapMaybe readDouble ws
           in case nums of
                (user : nice : system : idle : iowait : irq : softirq : steal : _) ->
                  let total = user + nice + system + idle + iowait + irq + softirq + steal
                      busy = total - idle - iowait
                      pct = busy / total
                      bnds = percentBindings name pct
                   in Just (T.pack (showFFloat1 (pct * 100)) <> "%", bnds)
                _ -> Nothing
        _ -> Nothing