perfmonger 0.12.1 → 0.14.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS +25 -1
- data/core/cmd/perfmonger-player/perfmonger-player.go +34 -12
- data/core/cmd/perfmonger-plot-formatter/README.md +24 -0
- data/core/cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go +115 -3
- data/core/cmd/perfmonger-summarizer/perfmonger-summarizer.go +2 -1
- data/core/subsystem/perfmonger_linux.go +2 -0
- data/core/subsystem/stat.go +2 -0
- data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-player_linux_amd64 +0 -0
- data/lib/exec/perfmonger-plot-formatter_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-plot-formatter_linux_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
- data/lib/perfmonger/command/play.rb +10 -0
- data/lib/perfmonger/command/plot.rb +144 -2
- data/lib/perfmonger/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b1f5e883802377df1cc422ab0e100f2445bdaafb7d77da2ddcb279232cd63b4
|
4
|
+
data.tar.gz: b3cf4f9bd787f1b9b47dcff4da7480d8c30385c89a3785ad0793c5c40703dd06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cdca2aa8a3ad76a274cdc142f1738e12578dc06117de98a1e24e41aee5604452a113becdd506df19d49b5ccf7aa1e1d1eaa58ab8a52b1fd121181318f3fdad51
|
7
|
+
data.tar.gz: 76697490438d0b364be27504a7db0697d33b9f3bc5dc56f11db8dc89f5a1f682a270ad2d50bbedb40852ea759a0cf98708cc0fd159bc73568f17e11da2f43de7
|
data/NEWS
CHANGED
@@ -1,4 +1,28 @@
|
|
1
|
-
##
|
1
|
+
## 2021-XX-XX: PerfMonger 0.15.0
|
2
|
+
|
3
|
+
## 2021-12-01: PerfMonger 0.14.2
|
4
|
+
* Bugfix
|
5
|
+
* [player] subcommand:
|
6
|
+
* Read stdin if no argument is given (required behaviour for live subcommand)
|
7
|
+
|
8
|
+
## 2021-12-01: PerfMonger 0.14.1
|
9
|
+
* Changes
|
10
|
+
* [plot] subcommand:
|
11
|
+
* Skip plotting memory usage if it is not recorded
|
12
|
+
|
13
|
+
## 2021-07-27: PerfMonger 0.14.0
|
14
|
+
* New features
|
15
|
+
* [plot] subcommand:
|
16
|
+
* Added memory usage plot
|
17
|
+
* Changes
|
18
|
+
* [record] subcommand:
|
19
|
+
* Additionaly record 'Hugepagesize' in memory usage
|
20
|
+
|
21
|
+
## 2021-07-26: PerfMonger 0.13.1
|
22
|
+
* New features
|
23
|
+
* [play] subcommand:
|
24
|
+
* Added --disk-only option to filter results of not interesting disks
|
25
|
+
* Note: v0.13.0 is yanked from rubygems.org
|
2
26
|
|
3
27
|
## 2021-07-08: PerfMonger 0.12.1
|
4
28
|
* Bug fixes
|
@@ -9,16 +9,19 @@ import (
|
|
9
9
|
"fmt"
|
10
10
|
"io"
|
11
11
|
"os"
|
12
|
+
"regexp"
|
12
13
|
|
13
14
|
projson "github.com/hayamiz/go-projson"
|
15
|
+
core "github.com/hayamiz/perfmonger/core"
|
14
16
|
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
15
|
-
core "github.com/hayamiz/perfmonger/core"
|
16
17
|
)
|
17
18
|
|
18
19
|
type PlayerOption struct {
|
19
|
-
logfile
|
20
|
-
color
|
21
|
-
pretty
|
20
|
+
logfile string
|
21
|
+
color bool
|
22
|
+
pretty bool
|
23
|
+
disk_only string
|
24
|
+
disk_only_regex *regexp.Regexp
|
22
25
|
}
|
23
26
|
|
24
27
|
var option PlayerOption
|
@@ -50,10 +53,11 @@ func showInterruptStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cu
|
|
50
53
|
return nil
|
51
54
|
}
|
52
55
|
|
53
|
-
func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
54
|
-
dusage, err := ss.
|
56
|
+
func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord, disk_only_regex *regexp.Regexp) error {
|
57
|
+
dusage, err := ss.GetDiskUsage1(
|
55
58
|
prev_rec.Time, prev_rec.Disk,
|
56
|
-
cur_rec.Time, cur_rec.Disk
|
59
|
+
cur_rec.Time, cur_rec.Disk,
|
60
|
+
option.disk_only_regex)
|
57
61
|
if err != nil {
|
58
62
|
return err
|
59
63
|
}
|
@@ -94,7 +98,9 @@ func showMemStat(printer *projson.JsonPrinter, cur_rec *ss.StatRecord) error {
|
|
94
98
|
return nil
|
95
99
|
}
|
96
100
|
|
97
|
-
func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord
|
101
|
+
func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord,
|
102
|
+
disk_only_regex *regexp.Regexp) error {
|
103
|
+
|
98
104
|
printer.Reset()
|
99
105
|
if option.pretty {
|
100
106
|
printer.SetStyle(projson.SmartStyle)
|
@@ -102,6 +108,7 @@ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss
|
|
102
108
|
if option.color {
|
103
109
|
printer.SetColor(true)
|
104
110
|
}
|
111
|
+
|
105
112
|
printer.BeginObject()
|
106
113
|
printer.PutKey("time")
|
107
114
|
printer.PutFloatFmt(float64(cur_rec.Time.UnixNano())/1e9, "%.3f")
|
@@ -122,7 +129,7 @@ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss
|
|
122
129
|
}
|
123
130
|
}
|
124
131
|
if cur_rec.Disk != nil {
|
125
|
-
err := showDiskStat(printer, prev_rec, cur_rec)
|
132
|
+
err := showDiskStat(printer, prev_rec, cur_rec, disk_only_regex)
|
126
133
|
if err != nil {
|
127
134
|
return err
|
128
135
|
}
|
@@ -148,10 +155,25 @@ func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss
|
|
148
155
|
func parseArgs() {
|
149
156
|
flag.BoolVar(&option.color, "color", false, "Use colored JSON output")
|
150
157
|
flag.BoolVar(&option.pretty, "pretty", false, "Use human readable JSON output")
|
158
|
+
flag.StringVar(&option.disk_only, "disk-only", "", "Select disk devices by regex")
|
151
159
|
|
152
160
|
flag.Parse()
|
153
161
|
|
154
|
-
option.
|
162
|
+
option.disk_only_regex = nil
|
163
|
+
|
164
|
+
if option.disk_only != "" {
|
165
|
+
var err error
|
166
|
+
option.disk_only_regex, err = regexp.Compile(option.disk_only)
|
167
|
+
if err != nil {
|
168
|
+
panic(err)
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
if len(flag.Args()) < 1 {
|
173
|
+
option.logfile = "-"
|
174
|
+
} else {
|
175
|
+
option.logfile = flag.Arg(0)
|
176
|
+
}
|
155
177
|
}
|
156
178
|
|
157
179
|
func main() {
|
@@ -160,7 +182,7 @@ func main() {
|
|
160
182
|
|
161
183
|
parseArgs()
|
162
184
|
|
163
|
-
if option.logfile == "" {
|
185
|
+
if option.logfile == "-" {
|
164
186
|
in = os.Stdin
|
165
187
|
} else {
|
166
188
|
f, err := os.Open(option.logfile)
|
@@ -219,7 +241,7 @@ func main() {
|
|
219
241
|
panic(err)
|
220
242
|
}
|
221
243
|
|
222
|
-
err = showStat(printer, prev_rec, cur_rec)
|
244
|
+
err = showStat(printer, prev_rec, cur_rec, option.disk_only_regex)
|
223
245
|
if err != nil {
|
224
246
|
printer.Reset()
|
225
247
|
fmt.Fprintln(os.Stderr, "skip by err")
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# perfmonger-plot-formatter
|
2
|
+
|
3
|
+
`perfmonger-plot-formatter` is a command to generate data files for plotting
|
4
|
+
various metrices recorded by `perfmonger-recorder`.
|
5
|
+
|
6
|
+
## Notes on memory usage records
|
7
|
+
|
8
|
+
### `free(1)` compatible summarization
|
9
|
+
|
10
|
+
- total: `MemStat.MemTotal`
|
11
|
+
- used: `if (memUsed < 0) { MemStat.MemTotal - MemStat.MemFree } else { memUsed }`
|
12
|
+
- memUsed := `MemStat.MemTotal - MemStat.MemFree - mainCached - MemStat.Buffers`
|
13
|
+
- mainCached := `MemStat.Cached + MemStat.SReclaimable`
|
14
|
+
- free: `MemStat.MemFree`
|
15
|
+
- shared: `MemStat.Shmem`
|
16
|
+
- buffers: `MemStat.Buffers`
|
17
|
+
- cache: `mainCached`
|
18
|
+
- mainCached := `MemStat.Cached + MemStat.SReclaimable`
|
19
|
+
- available: `MemStat.MemAvailable`
|
20
|
+
|
21
|
+
### Additional info
|
22
|
+
|
23
|
+
- hugeTotal: `MemStat.HugePages_Total`
|
24
|
+
- hugeUsed: `MemStat.HugePages_Total - MemStat.HugePages_Free`
|
@@ -13,14 +13,16 @@ import (
|
|
13
13
|
"os"
|
14
14
|
"regexp"
|
15
15
|
"sort"
|
16
|
+
"strings"
|
16
17
|
|
17
|
-
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
18
18
|
"github.com/hayamiz/perfmonger/core"
|
19
|
+
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
19
20
|
)
|
20
21
|
|
21
22
|
type CmdOption struct {
|
22
23
|
DiskFile string
|
23
24
|
CpuFile string
|
25
|
+
MemFile string
|
24
26
|
PerfmongerFile string
|
25
27
|
disk_only string
|
26
28
|
disk_only_regex *regexp.Regexp
|
@@ -31,8 +33,9 @@ func parseArgs() *CmdOption {
|
|
31
33
|
|
32
34
|
opt := new(CmdOption)
|
33
35
|
|
34
|
-
flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk
|
35
|
-
flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU
|
36
|
+
flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk usage data file for gnuplot")
|
37
|
+
flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU usage data file for gnuplot")
|
38
|
+
flag.StringVar(&opt.MemFile, "memfile", "./mem.dat", "Memory usage data file for gnuplot")
|
36
39
|
flag.StringVar(&opt.PerfmongerFile, "perfmonger", "", "Perfmonger log file")
|
37
40
|
flag.StringVar(&opt.disk_only, "disk-only",
|
38
41
|
"", "Select disk devices by regex")
|
@@ -80,6 +83,13 @@ type DiskDatTmpFile struct {
|
|
80
83
|
Idx int
|
81
84
|
}
|
82
85
|
|
86
|
+
type MemDatTmpFile struct {
|
87
|
+
Name string
|
88
|
+
Path string
|
89
|
+
File *os.File
|
90
|
+
Writer *bufio.Writer
|
91
|
+
}
|
92
|
+
|
83
93
|
type CpuDatTmpFile struct {
|
84
94
|
CoreId int
|
85
95
|
Path string
|
@@ -118,6 +128,20 @@ func makeCpuDatTmpFile(coreid int) *CpuDatTmpFile {
|
|
118
128
|
return ret
|
119
129
|
}
|
120
130
|
|
131
|
+
func makeMemDatTmpFile() *MemDatTmpFile {
|
132
|
+
ret := new(MemDatTmpFile)
|
133
|
+
|
134
|
+
f, err := ioutil.TempFile("", "perfmonger-mem")
|
135
|
+
if err != nil {
|
136
|
+
panic(err)
|
137
|
+
}
|
138
|
+
ret.File = f
|
139
|
+
ret.Path = f.Name()
|
140
|
+
ret.Writer = bufio.NewWriter(f)
|
141
|
+
|
142
|
+
return ret
|
143
|
+
}
|
144
|
+
|
121
145
|
func printCoreUsage(writer *bufio.Writer, elapsed_time float64, coreusage *ss.CpuCoreUsage) {
|
122
146
|
writer.WriteString(
|
123
147
|
fmt.Sprintf("%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n",
|
@@ -133,6 +157,80 @@ func printCoreUsage(writer *bufio.Writer, elapsed_time float64, coreusage *ss.Cp
|
|
133
157
|
coreusage.Idle))
|
134
158
|
}
|
135
159
|
|
160
|
+
func printMemUsage(writer *bufio.Writer, elapsed_time float64, mem *ss.MemStat) {
|
161
|
+
if mem == nil {
|
162
|
+
writer.WriteString("#")
|
163
|
+
writer.WriteString(
|
164
|
+
strings.Join([]string{
|
165
|
+
"elapsed_time", // 1
|
166
|
+
"mem_total", // 2
|
167
|
+
"mem_used", // 3
|
168
|
+
"mem_free", // 4
|
169
|
+
"buffers", // 5
|
170
|
+
"cached", // 6
|
171
|
+
"swap_cached", // 7
|
172
|
+
"active", // 8
|
173
|
+
"inactive", // 9
|
174
|
+
"swap_total", // 10
|
175
|
+
"swap_free", // 11
|
176
|
+
"dirty", // 12
|
177
|
+
"writeback", // 13
|
178
|
+
"anon_pages", // 14
|
179
|
+
"mapped", // 15
|
180
|
+
"shmem", // 16
|
181
|
+
"slab", // 17
|
182
|
+
"s_reclaimable", // 18
|
183
|
+
"s_unreclaim", // 19
|
184
|
+
"kernel_stack", // 20
|
185
|
+
"page_tables", // 21
|
186
|
+
"nfs_unstable", // 22
|
187
|
+
"bounce", // 23
|
188
|
+
"commit_limit", // 24
|
189
|
+
"committed_as", // 25
|
190
|
+
"anon_huge_pages", // 26
|
191
|
+
"huge_pages_total", // 27
|
192
|
+
"huge_pages_free", // 28
|
193
|
+
"huge_pages_rsvd", // 29
|
194
|
+
"huge_pages_surp", // 30
|
195
|
+
"hugepagesize"}, // 31
|
196
|
+
"\t"))
|
197
|
+
writer.WriteString("\n")
|
198
|
+
} else {
|
199
|
+
writer.WriteString(fmt.Sprintf("%f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
|
200
|
+
elapsed_time,
|
201
|
+
mem.MemTotal,
|
202
|
+
mem.MemTotal-mem.MemFree-mem.Buffers-mem.Cached-mem.SReclaimable,
|
203
|
+
mem.MemFree,
|
204
|
+
mem.Buffers,
|
205
|
+
mem.Cached,
|
206
|
+
mem.SwapCached,
|
207
|
+
mem.Active,
|
208
|
+
mem.Inactive,
|
209
|
+
mem.SwapTotal,
|
210
|
+
mem.SwapFree,
|
211
|
+
mem.Dirty,
|
212
|
+
mem.Writeback,
|
213
|
+
mem.AnonPages,
|
214
|
+
mem.Mapped,
|
215
|
+
mem.Shmem,
|
216
|
+
mem.Slab,
|
217
|
+
mem.SReclaimable,
|
218
|
+
mem.SUnreclaim,
|
219
|
+
mem.KernelStack,
|
220
|
+
mem.PageTables,
|
221
|
+
mem.NFS_Unstable,
|
222
|
+
mem.Bounce,
|
223
|
+
mem.CommitLimit,
|
224
|
+
mem.Committed_AS,
|
225
|
+
mem.AnonHugePages,
|
226
|
+
mem.HugePages_Total,
|
227
|
+
mem.HugePages_Free,
|
228
|
+
mem.HugePages_Rsvd,
|
229
|
+
mem.HugePages_Surp,
|
230
|
+
mem.Hugepagesize))
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
136
234
|
func main() {
|
137
235
|
opt := parseArgs()
|
138
236
|
|
@@ -193,6 +291,13 @@ func main() {
|
|
193
291
|
cpu_writer.WriteString("# All cpu usage\n")
|
194
292
|
cpu_writer.WriteString("# elapsed_time %usr %nice %sys %iowait %hardirq %softirq %steal %guest %idle\n")
|
195
293
|
|
294
|
+
f, err = os.Create(opt.MemFile)
|
295
|
+
if err != nil {
|
296
|
+
panic(err)
|
297
|
+
}
|
298
|
+
defer f.Close()
|
299
|
+
mem_writer := bufio.NewWriter(f)
|
300
|
+
|
196
301
|
for {
|
197
302
|
prev_rec := &records[curr^1]
|
198
303
|
cur_rec := &records[curr]
|
@@ -284,6 +389,12 @@ func main() {
|
|
284
389
|
}
|
285
390
|
printCoreUsage(cpu_writer, prev_rec.Time.Sub(t0).Seconds(), cusage.All)
|
286
391
|
|
392
|
+
if !meta_set {
|
393
|
+
// print column labels
|
394
|
+
printMemUsage(mem_writer, prev_rec.Time.Sub(t0).Seconds(), nil)
|
395
|
+
}
|
396
|
+
printMemUsage(mem_writer, prev_rec.Time.Sub(t0).Seconds(), cur_rec.Mem)
|
397
|
+
|
287
398
|
curr ^= 1
|
288
399
|
meta_set = true
|
289
400
|
}
|
@@ -332,6 +443,7 @@ func main() {
|
|
332
443
|
os.Remove(cpu_dat.Path)
|
333
444
|
}
|
334
445
|
cpu_writer.Flush()
|
446
|
+
mem_writer.Flush()
|
335
447
|
|
336
448
|
json_enc := json.NewEncoder(os.Stdout)
|
337
449
|
json_enc.Encode(meta)
|
@@ -12,8 +12,8 @@ import (
|
|
12
12
|
"sort"
|
13
13
|
|
14
14
|
projson "github.com/hayamiz/go-projson"
|
15
|
-
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
16
15
|
"github.com/hayamiz/perfmonger/core"
|
16
|
+
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
17
17
|
)
|
18
18
|
|
19
19
|
type SummaryOption struct {
|
@@ -39,6 +39,7 @@ func parseArgs() {
|
|
39
39
|
flag.Parse()
|
40
40
|
|
41
41
|
if len(flag.Args()) < 1 {
|
42
|
+
fmt.Fprintln(os.Stderr, "Insufficient argument")
|
42
43
|
os.Exit(1)
|
43
44
|
}
|
44
45
|
|
@@ -469,6 +469,8 @@ func ReadMemStat(record *StatRecord) error {
|
|
469
469
|
mem_stat.HugePages_Free = val
|
470
470
|
case "HugePages_Total:":
|
471
471
|
mem_stat.HugePages_Total = val
|
472
|
+
case "Hugepagesize:":
|
473
|
+
mem_stat.Hugepagesize = val
|
472
474
|
case "AnonHugePages:":
|
473
475
|
mem_stat.AnonHugePages = val
|
474
476
|
case "Committed_AS:":
|
data/core/subsystem/stat.go
CHANGED
@@ -132,6 +132,7 @@ type MemStat struct {
|
|
132
132
|
HugePages_Free int64
|
133
133
|
HugePages_Rsvd int64
|
134
134
|
HugePages_Surp int64
|
135
|
+
Hugepagesize int64
|
135
136
|
}
|
136
137
|
|
137
138
|
type StatRecord struct {
|
@@ -286,6 +287,7 @@ func (entry *MemStat) Clear() {
|
|
286
287
|
entry.HugePages_Free = 0
|
287
288
|
entry.HugePages_Rsvd = 0
|
288
289
|
entry.HugePages_Surp = 0
|
290
|
+
entry.Hugepagesize = 0
|
289
291
|
}
|
290
292
|
|
291
293
|
func NewStatRecord() *StatRecord {
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -26,6 +26,10 @@ EOS
|
|
26
26
|
@pretty = true
|
27
27
|
end
|
28
28
|
|
29
|
+
@disk_only_regex = nil
|
30
|
+
@parser.on('--disk-only REGEX', "Select disk devices that matches REGEX (Ex. 'sd[b-d]')") do |regex|
|
31
|
+
@disk_only_regex = regex
|
32
|
+
end
|
29
33
|
end
|
30
34
|
|
31
35
|
def parse_args(argv)
|
@@ -62,6 +66,12 @@ EOS
|
|
62
66
|
if @pretty
|
63
67
|
cmd << "-pretty"
|
64
68
|
end
|
69
|
+
|
70
|
+
if @disk_only_regex
|
71
|
+
cmd << "-disk-only"
|
72
|
+
cmd << @disk_only_regex
|
73
|
+
end
|
74
|
+
|
65
75
|
cmd << @logfile
|
66
76
|
|
67
77
|
Process.exec(*cmd)
|
@@ -145,10 +145,13 @@ EOS
|
|
145
145
|
|
146
146
|
@disk_dat = File.expand_path("disk.dat", @tmpdir)
|
147
147
|
@cpu_dat = File.expand_path("cpu.dat", @tmpdir)
|
148
|
+
@mem_dat = File.expand_path("mem.dat", @tmpdir)
|
148
149
|
|
149
150
|
meta_json = nil
|
150
|
-
cmd = [formatter_bin, "-perfmonger", @data_file,
|
151
|
-
|
151
|
+
cmd = [formatter_bin, "-perfmonger", @data_file,
|
152
|
+
"-cpufile", @cpu_dat,
|
153
|
+
"-diskfile", @disk_dat,
|
154
|
+
"-memfile", @mem_dat]
|
152
155
|
if @disk_only_regex
|
153
156
|
cmd << "-disk-only"
|
154
157
|
cmd << @disk_only
|
@@ -164,6 +167,7 @@ EOS
|
|
164
167
|
|
165
168
|
plot_disk(meta)
|
166
169
|
plot_cpu(meta)
|
170
|
+
plot_mem(meta)
|
167
171
|
|
168
172
|
FileUtils.rm_rf(@tmpdir)
|
169
173
|
|
@@ -508,6 +512,144 @@ EOS
|
|
508
512
|
end
|
509
513
|
end # def
|
510
514
|
|
515
|
+
def plot_mem(meta)
|
516
|
+
pdf_filename = @output_prefix + 'mem.pdf'
|
517
|
+
gp_filename = @output_prefix + 'mem.gp'
|
518
|
+
dat_filename = @output_prefix + 'mem.dat'
|
519
|
+
|
520
|
+
unless File.exists?(dat_filename)
|
521
|
+
$stderr.puts("WARN: memory usage info is not available.")
|
522
|
+
return
|
523
|
+
end
|
524
|
+
|
525
|
+
if @output_type != 'pdf'
|
526
|
+
img_filename = @output_prefix + 'cpu.' + @output_type
|
527
|
+
else
|
528
|
+
img_filename = nil
|
529
|
+
end
|
530
|
+
|
531
|
+
start_time = meta["start_time"]
|
532
|
+
end_time = meta["end_time"]
|
533
|
+
|
534
|
+
mem_scaling = 2.0**20 # KB -> GB
|
535
|
+
|
536
|
+
# "elapsed_time", // 1
|
537
|
+
# "mem_total", // 2
|
538
|
+
# "mem_used", // 3
|
539
|
+
# "mem_free", // 4
|
540
|
+
# "buffers", // 5
|
541
|
+
# "cached", // 6
|
542
|
+
# "swap_cached", // 7
|
543
|
+
# "active", // 8
|
544
|
+
# "inactive", // 9
|
545
|
+
# "swap_total", // 10
|
546
|
+
# "swap_free", // 11
|
547
|
+
# "dirty", // 12
|
548
|
+
# "writeback", // 13
|
549
|
+
# "anon_pages", // 14
|
550
|
+
# "mapped", // 15
|
551
|
+
# "shmem", // 16
|
552
|
+
# "slab", // 17
|
553
|
+
# "s_reclaimable", // 18
|
554
|
+
# "s_unreclaim", // 19
|
555
|
+
# "kernel_stack", // 20
|
556
|
+
# "page_tables", // 21
|
557
|
+
# "nfs_unstable", // 22
|
558
|
+
# "bounce", // 23
|
559
|
+
# "commit_limit", // 24
|
560
|
+
# "committed_as", // 25
|
561
|
+
# "anon_huge_pages", // 26
|
562
|
+
# "huge_pages_total", // 27
|
563
|
+
# "huge_pages_free", // 28
|
564
|
+
# "huge_pages_rsvd", // 29
|
565
|
+
# "huge_pages_surp"}, // 30
|
566
|
+
# "hugepagesize"}, // 31
|
567
|
+
|
568
|
+
Dir.chdir(@tmpdir) do
|
569
|
+
total = `tail -n+2 #{dat_filename}|head -n1`.split[1].to_f
|
570
|
+
if total == 0.0
|
571
|
+
raise RuntimeError.new("Failed to get MemTotal value from mem.dat file: #{dat_filename}")
|
572
|
+
end
|
573
|
+
|
574
|
+
gpfile = File.open(gp_filename, 'w')
|
575
|
+
|
576
|
+
pdf_file = File.join(@output_dir, "mem.pdf")
|
577
|
+
gpfile.puts <<EOS
|
578
|
+
set term pdfcairo enhanced color size 6in,2.5in
|
579
|
+
set title "Memory usage"
|
580
|
+
set output "#{pdf_filename}"
|
581
|
+
set key outside center bottom horizontal
|
582
|
+
set size 1.0, 1.0
|
583
|
+
|
584
|
+
set xlabel "elapsed time [sec]"
|
585
|
+
set ylabel "memory usage [GB]"
|
586
|
+
|
587
|
+
# scaling
|
588
|
+
s = #{mem_scaling}
|
589
|
+
|
590
|
+
set grid
|
591
|
+
set xrange [#{@offset_time}:#{end_time - start_time}]
|
592
|
+
set yrange [0:#{total * 1.2}/s]
|
593
|
+
|
594
|
+
# line styles
|
595
|
+
set style line 1 lt 1 lc rgb '#66C2A5' # teal
|
596
|
+
set style line 2 lt 1 lc rgb '#FC8D62' # orange
|
597
|
+
set style line 3 lt 1 lc rgb '#8DA0CB' # lilac
|
598
|
+
set style line 4 lt 1 lc rgb '#E78AC3' # magentat
|
599
|
+
set style line 5 lt 1 lc rgb '#A6D854' # lime green
|
600
|
+
set style line 6 lt 1 lc rgb '#FFD92F' # banana
|
601
|
+
set style line 7 lt 1 lc rgb '#E5C494' # tan
|
602
|
+
set style line 8 lt 1 lc rgb '#B3B3B3' # grey
|
603
|
+
|
604
|
+
# palette
|
605
|
+
set palette maxcolors 8
|
606
|
+
set palette defined ( 0 '#66C2A5',\
|
607
|
+
1 '#FC8D62',\
|
608
|
+
2 '#8DA0CB',\
|
609
|
+
3 '#E78AC3',\
|
610
|
+
4 '#A6D854',\
|
611
|
+
5 '#FFD92F',\
|
612
|
+
6 '#E5C494',\
|
613
|
+
7 '#B3B3B3' )
|
614
|
+
|
615
|
+
used(total, free, cached, buffers, srecl) = \\
|
616
|
+
( (total - free - cache(cached, srecl) - buffers < 0) ? \\
|
617
|
+
(total - free) : \\
|
618
|
+
(total - free - cache(cached, srecl) - buffers) )
|
619
|
+
|
620
|
+
cache(cached, srecl) = cached + srecl
|
621
|
+
|
622
|
+
plot "#{dat_filename}" usi 1:($4/s+$5/s+cache($6, $18)/s+$16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 8 ti "free", \\
|
623
|
+
"#{dat_filename}" usi 1:($5/s+cache($6, $18)/s+$16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 3 ti "buffers", \\
|
624
|
+
"#{dat_filename}" usi 1:(cache($6, $18)/s+$16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 5 ti "cached", \\
|
625
|
+
"#{dat_filename}" usi 1:($16/s+used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 6 ti "shared", \\
|
626
|
+
"#{dat_filename}" usi 1:(used($2, $4, $6, $5, $18)/s) wi filledcurves x1 ls 2 ti "used", \\
|
627
|
+
"#{dat_filename}" usi 1:(($27-$28)*$31/s) wi lines dt (4,4) lc rgb 'black' lw 2.5 ti 'used (hugepage)'
|
628
|
+
|
629
|
+
EOS
|
630
|
+
|
631
|
+
gpfile.close
|
632
|
+
system("gnuplot #{gpfile.path}")
|
633
|
+
|
634
|
+
if @output_type != 'pdf'
|
635
|
+
system("convert -density 150 -background white #{pdf_filename} #{img_filename}")
|
636
|
+
end
|
637
|
+
end # chdir
|
638
|
+
|
639
|
+
copy_targets = []
|
640
|
+
copy_targets << pdf_filename
|
641
|
+
copy_targets << img_filename if img_filename
|
642
|
+
|
643
|
+
if @save_gpfiles
|
644
|
+
copy_targets << gp_filename
|
645
|
+
copy_targets << dat_filename
|
646
|
+
end
|
647
|
+
|
648
|
+
copy_targets.each do |target|
|
649
|
+
FileUtils.copy(File.join(@tmpdir, target), @output_dir)
|
650
|
+
end
|
651
|
+
end # def
|
652
|
+
|
511
653
|
private
|
512
654
|
def factors(n)
|
513
655
|
(2..([n, n / 2].max).to_i).select do |x|
|
data/lib/perfmonger/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perfmonger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuto HAYAMIZU
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- core/Makefile
|
103
103
|
- core/build.sh
|
104
104
|
- core/cmd/perfmonger-player/perfmonger-player.go
|
105
|
+
- core/cmd/perfmonger-plot-formatter/README.md
|
105
106
|
- core/cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go
|
106
107
|
- core/cmd/perfmonger-recorder/perfmonger-recorder.go
|
107
108
|
- core/cmd/perfmonger-summarizer/perfmonger-summarizer.go
|