Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reflect pid or proc count in name #10

Merged
merged 3 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

`mem-info` uses [PVP Versioning][1].

## Unreleased -- 2024-01-31
## Unreleased -- 2024-02-06

- Remove the check for __root__ when no pids are specified

- previously, an error occurred if no pids were specified without sudo
- after this, all processes of the current user are shown

- Add an option -y (--output-style) that allows the output to be formatted as
CSV with all values in KiB

## 0.2.0.0 -- 2024-01-28

- Simplify the output when the -d (--discriminate-by-pid) flag is used
Expand Down
2 changes: 1 addition & 1 deletion src/System/MemInfo/Choices.hs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ styleHelp =
Text.unlines
[ "Determines how the output report is presented;"
, "'normal' is the default and is the same as if this option was omitted;"
, "'csv' outputs the usage and header rows in csv format, with all values in KiB and 'overall' row."
, "'csv' outputs the usage and header rows in csv format, with all values in KiB and no 'total' row."
, "With 'csv', the --total (-t) flag is ignored"
]

Expand Down
33 changes: 23 additions & 10 deletions src/System/MemInfo/Print.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

{- |
Module : System.MemInfo.Print
Expand All @@ -18,6 +20,7 @@ module System.MemInfo.Print (
styleOutput,
) where

import Data.Proxy (Proxy (..))
import qualified Data.Text as Text
import Fmt (
build,
Expand Down Expand Up @@ -110,25 +113,28 @@ fmtMem' =
in go


hdrPrivate, hdrShared, hdrRamUsed, hdrSwapUsed, hdrProgram :: Text
hdrPrivate, hdrShared, hdrRamUsed, hdrSwapUsed, hdrProgram, hdrCount, hdrPid :: Text
hdrPrivate = "Private"
hdrShared = "Shared"
hdrRamUsed = "RAM Used"
hdrSwapUsed = "Swap Used"
hdrProgram = "Program"
hdrCount = "(# processes)"
hdrPid = "[pid]"


-- | Generates the text of the printed header of the memory report
fmtAsHeader :: Bool -> Text
fmtAsHeader showSwap =
fmtAsHeader :: Bool -> Bool -> Text
fmtAsHeader hasPid showSwap =
let
padb = padBothF columnWidth ' '
padr = padRightF columnWidth ' '
padl = padLeftF columnWidth ' '
private = padb hdrPrivate
shared = padb hdrShared
all' = padl hdrRamUsed
name' = padr hdrProgram
nameExt = if hasPid then hdrPid else hdrCount
name' = padr $ hdrProgram <> " " <> nameExt
swap' = padl hdrSwapUsed
ram = private |+ " + " +| shared |+ " = " +| all'
numbers = if showSwap then ram +| swap' else ram
Expand All @@ -137,13 +143,14 @@ fmtAsHeader showSwap =


-- | Generates the text of the printed header of the memory report
fmtAsHeaderCsv :: Bool -> Text
fmtAsHeaderCsv showSwap =
fmtAsHeaderCsv :: Bool -> Bool -> Text
fmtAsHeaderCsv hasPid showSwap =
let
private = build hdrPrivate
shared = build hdrShared
all' = build hdrRamUsed
name' = build hdrProgram
nameExt = if hasPid then hdrPid else hdrCount
name' = build $ hdrProgram <> " " <> nameExt
swap' = build hdrSwapUsed
ram = private |+ "," +| shared |+ "," +| all' |+ ","
numbers = if showSwap then ram +| swap' |+ "," else ram
Expand All @@ -165,14 +172,20 @@ class AsCmdName a where
cmdWithCount :: a -> Int -> Text


-- Indicate if pid or process count should shown in the hdr
hdrHasPid :: Proxy a -> Bool


instance AsCmdName Text where
asCmdName = id
cmdWithCount cmd count = "" +| asCmdName cmd |+ " (" +| count |+ ")"
hdrHasPid _ = False


instance AsCmdName (ProcessID, Text) where
asCmdName (pid, name) = "" +| name |+ " [" +| toInteger pid |+ "]"
cmdWithCount cmd _count = "" +| asCmdName cmd |+ ""
hdrHasPid _ = True


overallTotals :: [MemUsage] -> (Int, Int)
Expand All @@ -188,12 +201,12 @@ data Printers a = Printers
}


printStyle :: (AsCmdName a) => Style -> Bool -> Printers a
printStyle :: forall a. (AsCmdName a) => Style -> Bool -> Printers a
printStyle style showSwap =
let usageFmt Normal = fmtMemUsage
usageFmt Csv = fmtMemUsageCsv
headerFmt Normal = fmtAsHeader
headerFmt Csv = fmtAsHeaderCsv
headerFmt Normal = fmtAsHeader (hdrHasPid @a Proxy)
headerFmt Csv = fmtAsHeaderCsv (hdrHasPid @a Proxy)
overallFmt Normal x = Just $ fmtOverall showSwap x
overallFmt Csv _ = Nothing
in Printers
Expand Down
98 changes: 84 additions & 14 deletions test/MemInfo/PrintSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ module MemInfo.PrintSpec (spec) where

import Data.Text (Text)
import qualified Data.Text as Text
import System.MemInfo.Print (fmtAsHeader, fmtMemUsage, fmtOverall)
import System.MemInfo.Choices (Style (Csv, Normal))
import System.MemInfo.Print (fmtAsHeader, fmtMemUsage, fmtOverall, styleOutput)
import System.MemInfo.Proc (MemUsage (..))
import System.Posix.Types (ProcessID)
import Test.Hspec
Expand All @@ -22,34 +23,103 @@ spec = describe "module System.MemInfo.Print" $ do
fmtAsHeaderSpec
fmtOverallSpec
fmtMemUsageSpec
styleOutputSpec


styleOutputSpec :: Spec
styleOutputSpec = describe "styleOutput" $ do
describe "when accurate and swap shown" $ do
let count = 6
usage = sampleUsage' count
styleOutput' s = styleOutput True s True
describe "when style is csv" $ do
let style = Csv
describe "when discriminating by pid" $ do
let want =
[ "Private,Shared,RAM Used,Swap Used,Program [pid]"
, "1,1,2,4,by-id-and-name-cmd [100]"
]
it "should generate the expected output" $ do
styleOutput' style [(biName, usage)] `shouldBe` want

describe "not discriminating by pid" $ do
let want =
[ "Private,Shared,RAM Used,Swap Used,Program (# processes)"
, "1,1,2,4,by-name-cmd (6)"
]
it "should generate the expected output" $ do
styleOutput' style [(monoName, usage)] `shouldBe` want

describe "when accurate and no swap shown" $ do
let count = 6
usage = sampleUsage' count
styleOutput' s = styleOutput False s True
describe "when style is normal" $ do
let style = Normal
wantedSummary =
Text.unlines
[ "------------------------------------"
, " 2.0 KiB"
, "===================================="
]
describe "when discriminating by pid" $ do
let want =
[ " Private + Shared = RAM Used\tProgram [pid]"
, " 1.0 KiB + 1.0 KiB = 2.0 KiB\tby-id-and-name-cmd [100]"
, wantedSummary
]
it "should generate the expected output" $ do
styleOutput' style [(biName, usage)] `shouldBe` want

describe "not discriminating by pid" $ do
let want =
[ " Private + Shared = RAM Used\tProgram (# processes)"
, " 1.0 KiB + 1.0 KiB = 2.0 KiB\tby-name-cmd (6)"
, wantedSummary
]
it "should generate the expected output" $ do
styleOutput' style [(monoName, usage)] `shouldBe` want


fmtAsHeaderSpec :: Spec
fmtAsHeaderSpec = describe "fmtAsHeader" $ do
describe "when swap is not required" $ do
it "does not show it" $
fmtAsHeader False `shouldBe` headerNoSwap
describe "when discriminating by pid" $ do
let byPid = True
describe "when swap is not required" $ do
it "does not show it" $ do
fmtAsHeader byPid False `shouldBe` headerNoSwap

describe "when swap is required" $ do
it "does show it" $
fmtAsHeader True `shouldBe` headerSwap
describe "when swap is required" $ do
it "does show it" $ do
fmtAsHeader byPid True `shouldBe` headerSwap

describe "when not discriminating by pid" $ do
let byPid = False
withProcCount = Text.replace "[pid]" "(# processes)"
describe "when swap is not required" $ do
it "does not show it" $ do
fmtAsHeader byPid False `shouldBe` withProcCount headerNoSwap

describe "when swap is required" $ do
it "does show it" $ do
fmtAsHeader byPid True `shouldBe` withProcCount headerSwap


headerNoSwap :: Text
headerNoSwap = " Private + Shared = RAM Used\tProgram "
headerNoSwap = " Private + Shared = RAM Used\tProgram [pid]"


headerSwap :: Text
headerSwap = " Private + Shared = RAM Used Swap Used\tProgram "
headerSwap = " Private + Shared = RAM Used Swap Used\tProgram [pid]"


fmtOverallSpec :: Spec
fmtOverallSpec = describe "fmtOverall" $ do
describe "when swap is not required" $ do
it "does not show it" $
it "does not show it" $ do
fmtOverall False (1, 1) `shouldBe` sampleNoSwapOverall
describe "when swap is required" $ do
it "does show it" $
it "does show it" $ do
fmtOverall True (1, 1) `shouldBe` sampleSwapOverall


Expand All @@ -76,17 +146,17 @@ fmtMemUsageSpec = describe "fmtMemUsage" $ do
describe "when displaying by-pid" $ do
let usage = sampleUsage' 1
describe "and swap is not required" $ do
it "does not show it" $
it "does not show it" $ do
fmtMemUsage False biName usage `shouldBe` sampleTotalNoSwap

describe "when swap is required" $ do
it "shows it" $
it "shows it" $ do
fmtMemUsage True biName usage `shouldBe` sampleTotalSwap

describe "when displaying by-name" $ do
let usage = sampleUsage' 3
describe "and swap is not required" $ do
it "does not show it" $
it "does not show it" $ do
fmtMemUsage False monoName usage `shouldBe` sampleTotalNoSwapMono


Expand Down
Loading