-
Notifications
You must be signed in to change notification settings - Fork 44
/
mem-util.go
146 lines (123 loc) · 3.31 KB
/
mem-util.go
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
package gotch
// helper to debug memory blow-up
import (
"fmt"
"os"
"runtime"
"strings"
"text/tabwriter"
)
func PrintMemStats(messageOpt ...string) {
message := "Memory Stats"
if len(messageOpt) > 0 {
message = fmt.Sprintf("%s: %s", message, messageOpt[0])
}
var rtm runtime.MemStats
runtime.ReadMemStats(&rtm)
tp := newTablePrinter()
tp.title = message
tp.AddRecord("|", "Allocated heap objects", padRight(fmt.Sprintf("%v", rtm.Mallocs), 10), "|")
tp.AddRecord("|", "Released heap objects", padRight(fmt.Sprintf("%v", rtm.Frees), 10), "|")
tp.AddRecord("|", "Living heap objects", padRight(fmt.Sprintf("%v", rtm.HeapObjects), 10), "|")
tp.AddRecord("|", "Memory in use by heap objects (bytes)", padRight(fmt.Sprintf("%v", rtm.HeapAlloc), 10), "|")
tp.AddRecord("|", "Reserved memory (by Go runtime for heap, stack,...) (bytes)", padRight(fmt.Sprintf("%v", rtm.Sys), 10), "|")
tp.AddRecord("|", "Total pause time by GC (nanoseconds)", padRight(fmt.Sprintf("%v", rtm.PauseTotalNs), 10), "|")
tp.AddRecord("|", "Number of GC called", padRight(fmt.Sprintf("%v", rtm.NumGC), 10), "|")
// tp.AddRecord("Last GC called", fmt.Sprintf("%v", time.UnixMilli(int64(rtm.LastGC/1_000_000))))
tp.Print()
}
type tablePrinter struct {
w *tabwriter.Writer
maxLength int
title string
}
type printItem struct {
val string
alignRight bool
}
func item(val string, alignRightOpt ...bool) printItem {
alignRight := false
if len(alignRightOpt) > 0 {
alignRight = alignRightOpt[0]
}
return printItem{
val: val,
alignRight: alignRight,
}
}
func newTablePrinter() *tablePrinter {
w := tabwriter.NewWriter(
os.Stdout, //output
0, // min width
1, // tabwidth
2, // padding
' ', // padding character
0, // align left
)
return &tablePrinter{
w: w,
maxLength: 0,
}
}
func (tp *tablePrinter) AddRecord(items ...string) {
tp.printRecord(items...)
}
func (tp *tablePrinter) AlignRight() {
tp.w.Init(
os.Stdout, //output
0, // min width
1, // tabwidth
2, // padding
' ', // padding character
tabwriter.AlignRight,
) // flags
}
func (tp *tablePrinter) AlignLeft() {
tp.w.Init(
os.Stdout, //output
0, // min width
1, // tabwidth
2, // padding
' ', // padding character
0, // align left
) // flags
}
func (tp *tablePrinter) printRecord(rec ...string) {
var val string
for i, item := range rec {
switch i {
case 0:
val = item
case len(rec) - 1:
val += fmt.Sprintf("\t%s\n", item)
default:
val += fmt.Sprintf("\t%s", item)
}
}
nbytes, err := tp.w.Write([]byte(val))
if err != nil {
panic(err)
}
if nbytes > tp.maxLength {
tp.maxLength = nbytes
}
}
func (tp *tablePrinter) Print() {
printBorder(tp.maxLength)
printLine(tp.maxLength, tp.title)
printBorder(tp.maxLength)
tp.w.Flush()
printBorder(tp.maxLength)
}
func padRight(val interface{}, rightEnd int) string {
value := fmt.Sprintf("%v", val)
pad := fmt.Sprintf("%s", strings.Repeat(" ", rightEnd-len(value)))
return fmt.Sprintf("%s%s", pad, value)
}
func printLine(lineLength int, value string) {
fmt.Printf("| %s %s\n", value, padRight("|", lineLength-len(value)-1))
}
func printBorder(length int) {
line := fmt.Sprintf("%s", strings.Repeat("-", length))
fmt.Printf("+%s+\n", line)
}