-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoutput.go
More file actions
152 lines (131 loc) · 3.98 KB
/
output.go
File metadata and controls
152 lines (131 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package main
import (
"fmt"
"os"
"strconv"
"unicode/utf8"
"github.com/dustin/go-humanize"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"golang.org/x/sys/unix"
"golang.org/x/term"
)
// render size in kilobytes to a string, optionally human-readable
func kiloBytesToString(value int, humanReadable bool) string {
if humanReadable {
return humanize.IBytes(uint64(value * 1024))
}
return fmt.Sprintf("%d", value)
}
// try to infer terminal width
func terminalWidth() int {
// Try stdout
width, _, err := term.GetSize(int(os.Stdout.Fd()))
if err == nil && width > 0 {
return width
}
// Try stderr
width, _, err = term.GetSize(int(os.Stderr.Fd()))
if err == nil && width > 0 {
return width
}
// Try stdin
width, _, err = term.GetSize(int(os.Stdin.Fd()))
if err == nil && width > 0 {
return width
}
// Try /dev/tty
if tty, err := os.Open("/dev/tty"); err == nil {
defer tty.Close()
if ws, err := unix.IoctlGetWinsize(int(tty.Fd()), unix.TIOCGWINSZ); err == nil && ws.Col > 0 {
return int(ws.Col)
}
}
// Try $COLUMNS environment variable
if cols := os.Getenv("COLUMNS"); cols != "" {
if c, err := strconv.Atoi(cols); err == nil && c > 0 {
return c
}
}
// Default
return 80
}
// calculate width of columns other than command line
func otherColumnsWidth(rollups []SmemRollup, pidOwnersMap map[int]PidOwner, humanReadable bool) int {
spacingWidth := 11
pidWidth := 3
userWidth := 4
ussWidth := 3
pssWidth := 3
rssWidth := 3
for _, rollup := range rollups {
l := len(fmt.Sprintf("%d", rollup.PID()))
if l > pidWidth {
pidWidth = l
}
user := pidOwnersMap[rollup.PID()].username
if user == "" {
user = strconv.Itoa(pidOwnersMap[rollup.PID()].uid)
}
l = len(user)
if l > userWidth {
userWidth = l
}
uss := rollup.USS()
l = len(kiloBytesToString(uss, humanReadable))
if l > ussWidth {
ussWidth = l
}
pss := rollup.PSS()
l = len(kiloBytesToString(pss, humanReadable))
if l > pssWidth {
pssWidth = l
}
rss := rollup.RSS()
l = len(kiloBytesToString(rss, humanReadable))
if l > rssWidth {
rssWidth = l
}
}
return spacingWidth + pidWidth + userWidth + ussWidth + pssWidth + rssWidth
}
// render output table to stdout
func render(rollups []SmemRollup, pidOwnersMap map[int]PidOwner, cmdlineMap map[int]string, isWideOutput bool, humanReadable bool) {
cmdWidth := terminalWidth() - otherColumnsWidth(rollups, pidOwnersMap, humanReadable)
if cmdWidth < 7 {
cmdWidth = 7
isWideOutput = true
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.SuppressTrailingSpaces()
t.SetColumnConfigs([]table.ColumnConfig{
{Number: 1, Align: text.AlignRight, AlignFooter: text.AlignRight, AlignHeader: text.AlignRight},
{Number: 2, Align: text.AlignLeft, AlignFooter: text.AlignLeft, AlignHeader: text.AlignLeft},
{Number: 3, Align: text.AlignRight, AlignFooter: text.AlignRight, AlignHeader: text.AlignRight},
{Number: 4, Align: text.AlignRight, AlignFooter: text.AlignRight, AlignHeader: text.AlignRight},
{Number: 5, Align: text.AlignRight, AlignFooter: text.AlignRight, AlignHeader: text.AlignRight},
{Number: 6, Align: text.AlignLeft, AlignFooter: text.AlignLeft, AlignHeader: text.AlignLeft},
})
t.Style().Options.DrawBorder = false
t.Style().Options.SeparateHeader = false
t.Style().Options.SeparateColumns = false
t.Style().Options.SeparateRows = false
t.AppendHeader(table.Row{"PID", "User", "USS", "PSS", "RSS", "Command"})
for _, rollup := range rollups {
pid := rollup.PID()
uss := kiloBytesToString((rollup.USS()), humanReadable)
pss := kiloBytesToString((rollup.PSS()), humanReadable)
rss := kiloBytesToString(rollup.RSS(), humanReadable)
user := pidOwnersMap[pid].username
if user == "" {
user = strconv.Itoa(pidOwnersMap[pid].uid)
}
command := cmdlineMap[pid]
if !isWideOutput && utf8.RuneCountInString(command) > cmdWidth {
command = string([]rune(cmdlineMap[pid])[0:cmdWidth])
}
t.AppendRow(table.Row{pid, user, uss, pss, rss, command})
}
t.Render()
}