perfmonger 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/NEWS +10 -2
- data/core/Makefile +14 -2
- data/core/build.sh +1 -1
- data/core/perfmonger-plot-formatter.go +325 -0
- data/core/subsystem/usage.go +13 -1
- data/lib/perfmonger.rb +1 -0
- data/lib/perfmonger/command/core.rb +4 -0
- data/lib/perfmonger/command/fingerprint.rb +48 -0
- data/lib/perfmonger/command/init-shell.rb +51 -0
- data/lib/perfmonger/command/plot.rb +241 -195
- data/lib/perfmonger/command/summary.rb +1 -1
- data/lib/perfmonger/version.rb +1 -1
- data/misc/{perfmonger-completion.bash → perfmonger.bash} +0 -0
- data/misc/{_perfmonger → perfmonger.zsh} +24 -8
- data/perfmonger.gemspec +0 -1
- data/spec/fingerprint_spec.rb +7 -7
- data/spec/live_spec.rb +5 -4
- data/spec/perfmonger_spec.rb +7 -7
- data/spec/play_spec.rb +4 -3
- data/spec/plot_spec.rb +18 -17
- data/spec/record_spec.rb +3 -3
- data/spec/stat_spec.rb +2 -2
- data/spec/summary_spec.rb +4 -4
- data/spec/support/aruba.rb +1 -2
- metadata +9 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6c4a036c08d2f75fc25b25da1b773e025461880
|
4
|
+
data.tar.gz: 87182b819268cdcd289ea1cfb89f8672cc307947
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcb1dd5f6086bff622f66dc7eb15a835604d0ce63fb2ea7b3d6ab022d3b5724384ca54ec38525c31984bc06dc08c87ca89cb21da7a62696bfaf665df6474d8a8
|
7
|
+
data.tar.gz: cb33cd2fe403d279687a6ad680fbda8af96c778b65b485f6f4b6024eac8e80c8fc6efd79e4e225f1a02fcbfa2f79cfe5061857716ff62fc3b7c4a1a828ca2568
|
data/.gitignore
CHANGED
data/NEWS
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
##
|
2
|
-
*
|
1
|
+
## 2016-12-12: PerfMonger 0.9.0
|
2
|
+
* New features
|
3
|
+
* [init-shell] subcommand: Added for loading shell completion function from rcfile
|
4
|
+
* zsh support
|
5
|
+
* bash support
|
6
|
+
* [fingerprint]
|
7
|
+
* log LVM, fdisk, and lsblk info
|
8
|
+
* [plot]
|
9
|
+
* Fast plot data formatting with new core implementation
|
10
|
+
* Improved shell completion
|
3
11
|
|
4
12
|
## 2016-11-22: PerfMonger 0.8.2
|
5
13
|
* Bug fixes
|
data/core/Makefile
CHANGED
@@ -20,6 +20,10 @@ all: build
|
|
20
20
|
go build -o $@ perfmonger-summarizer.go
|
21
21
|
|
22
22
|
|
23
|
+
../lib/exec/perfmonger-plot-formatter_linux_386: perfmonger-plot-formatter.go $(GOSRC)
|
24
|
+
go build -o $@ perfmonger-plot-formatter.go
|
25
|
+
|
26
|
+
|
23
27
|
../lib/exec/perfmonger-recorder_linux_amd64: perfmonger-recorder.go $(GOSRC)
|
24
28
|
go build -o $@ perfmonger-recorder.go
|
25
29
|
|
@@ -32,6 +36,10 @@ all: build
|
|
32
36
|
go build -o $@ perfmonger-summarizer.go
|
33
37
|
|
34
38
|
|
39
|
+
../lib/exec/perfmonger-plot-formatter_linux_amd64: perfmonger-plot-formatter.go $(GOSRC)
|
40
|
+
go build -o $@ perfmonger-plot-formatter.go
|
41
|
+
|
42
|
+
|
35
43
|
../lib/exec/perfmonger-recorder_darwin_amd64: perfmonger-recorder.go $(GOSRC)
|
36
44
|
go build -o $@ perfmonger-recorder.go
|
37
45
|
|
@@ -44,8 +52,12 @@ all: build
|
|
44
52
|
go build -o $@ perfmonger-summarizer.go
|
45
53
|
|
46
54
|
|
47
|
-
|
55
|
+
../lib/exec/perfmonger-plot-formatter_darwin_amd64: perfmonger-plot-formatter.go $(GOSRC)
|
56
|
+
go build -o $@ perfmonger-plot-formatter.go
|
57
|
+
|
58
|
+
|
59
|
+
build: ../lib/exec/perfmonger-recorder_linux_386 ../lib/exec/perfmonger-player_linux_386 ../lib/exec/perfmonger-summarizer_linux_386 ../lib/exec/perfmonger-plot-formatter_linux_386 ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-summarizer_linux_amd64 ../lib/exec/perfmonger-plot-formatter_linux_amd64 ../lib/exec/perfmonger-recorder_darwin_amd64 ../lib/exec/perfmonger-player_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
|
48
60
|
|
49
61
|
clean:
|
50
|
-
rm -f ../lib/exec/perfmonger-recorder_linux_386 ../lib/exec/perfmonger-player_linux_386 ../lib/exec/perfmonger-summarizer_linux_386 ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-summarizer_linux_amd64 ../lib/exec/perfmonger-recorder_darwin_amd64 ../lib/exec/perfmonger-player_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64
|
62
|
+
rm -f ../lib/exec/perfmonger-recorder_linux_386 ../lib/exec/perfmonger-player_linux_386 ../lib/exec/perfmonger-summarizer_linux_386 ../lib/exec/perfmonger-plot-formatter_linux_386 ../lib/exec/perfmonger-recorder_linux_amd64 ../lib/exec/perfmonger-player_linux_amd64 ../lib/exec/perfmonger-summarizer_linux_amd64 ../lib/exec/perfmonger-plot-formatter_linux_amd64 ../lib/exec/perfmonger-recorder_darwin_amd64 ../lib/exec/perfmonger-player_darwin_amd64 ../lib/exec/perfmonger-summarizer_darwin_amd64 ../lib/exec/perfmonger-plot-formatter_darwin_amd64
|
51
63
|
|
data/core/build.sh
CHANGED
@@ -54,7 +54,7 @@ for idx in $(seq 0 $((${#TARGET[@]}-1))); do
|
|
54
54
|
export GOOS=$1
|
55
55
|
export GOARCH=$2
|
56
56
|
|
57
|
-
for subcmd in recorder player summarizer; do
|
57
|
+
for subcmd in recorder player summarizer plot-formatter; do
|
58
58
|
TARGETS+=(../lib/exec/perfmonger-${subcmd}_${GOOS}_${GOARCH})
|
59
59
|
|
60
60
|
cat <<EOF >> Makefile
|
@@ -0,0 +1,325 @@
|
|
1
|
+
//usr/bin/env go run $0 $@ ; exit
|
2
|
+
|
3
|
+
package main
|
4
|
+
|
5
|
+
import (
|
6
|
+
"bufio"
|
7
|
+
"encoding/gob"
|
8
|
+
"encoding/json"
|
9
|
+
"flag"
|
10
|
+
"fmt"
|
11
|
+
"io"
|
12
|
+
"io/ioutil"
|
13
|
+
"os"
|
14
|
+
"sort"
|
15
|
+
|
16
|
+
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
17
|
+
)
|
18
|
+
|
19
|
+
type CmdOption struct {
|
20
|
+
DiskFile string
|
21
|
+
CpuFile string
|
22
|
+
PerfmongerFile string
|
23
|
+
}
|
24
|
+
|
25
|
+
func parseArgs() *CmdOption {
|
26
|
+
opt := new(CmdOption)
|
27
|
+
|
28
|
+
flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk performance data file")
|
29
|
+
flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU performance data file")
|
30
|
+
flag.StringVar(&opt.PerfmongerFile, "perfmonger", "", "Perfmonger log file")
|
31
|
+
|
32
|
+
flag.Parse()
|
33
|
+
|
34
|
+
if opt.PerfmongerFile == "" {
|
35
|
+
os.Stderr.WriteString("[ERROR] perfmonger log file is required.\n")
|
36
|
+
os.Exit(1)
|
37
|
+
}
|
38
|
+
|
39
|
+
return opt
|
40
|
+
}
|
41
|
+
|
42
|
+
type DiskMetaEntry struct {
|
43
|
+
Name string `json:"name"`
|
44
|
+
Idx int `json:"idx"`
|
45
|
+
}
|
46
|
+
|
47
|
+
type DiskMeta struct {
|
48
|
+
Devices []DiskMetaEntry `json:"devices"`
|
49
|
+
}
|
50
|
+
|
51
|
+
type CpuMeta struct {
|
52
|
+
NumCore int `json:"num_core"`
|
53
|
+
}
|
54
|
+
|
55
|
+
type PlotMeta struct {
|
56
|
+
Disk DiskMeta `json:"disk"`
|
57
|
+
Cpu CpuMeta `json:"cpu"`
|
58
|
+
StartTime float64 `json:"start_time"`
|
59
|
+
EndTime float64 `json:"end_time"`
|
60
|
+
}
|
61
|
+
|
62
|
+
type DiskDatTmpFile struct {
|
63
|
+
Name string
|
64
|
+
Path string
|
65
|
+
File *os.File
|
66
|
+
Writer *bufio.Writer
|
67
|
+
Idx int
|
68
|
+
}
|
69
|
+
|
70
|
+
type CpuDatTmpFile struct {
|
71
|
+
CoreId int
|
72
|
+
Path string
|
73
|
+
File *os.File
|
74
|
+
Writer *bufio.Writer
|
75
|
+
}
|
76
|
+
|
77
|
+
func makeDiskDatTmpFile(dname string, idx int) *DiskDatTmpFile {
|
78
|
+
ret := new(DiskDatTmpFile)
|
79
|
+
ret.Name = dname
|
80
|
+
ret.Idx = idx
|
81
|
+
|
82
|
+
f, err := ioutil.TempFile("", "perfmonger-"+dname)
|
83
|
+
if err != nil {
|
84
|
+
panic(err)
|
85
|
+
}
|
86
|
+
ret.File = f
|
87
|
+
ret.Path = f.Name()
|
88
|
+
ret.Writer = bufio.NewWriter(f)
|
89
|
+
|
90
|
+
return ret
|
91
|
+
}
|
92
|
+
|
93
|
+
func makeCpuDatTmpFile(coreid int) *CpuDatTmpFile {
|
94
|
+
ret := new(CpuDatTmpFile)
|
95
|
+
ret.CoreId = coreid
|
96
|
+
|
97
|
+
f, err := ioutil.TempFile("", fmt.Sprintf("perfmonger-core%d-", coreid))
|
98
|
+
if err != nil {
|
99
|
+
panic(err)
|
100
|
+
}
|
101
|
+
ret.File = f
|
102
|
+
ret.Path = f.Name()
|
103
|
+
ret.Writer = bufio.NewWriter(f)
|
104
|
+
|
105
|
+
return ret
|
106
|
+
}
|
107
|
+
|
108
|
+
func printCoreUsage(writer *bufio.Writer, elapsed_time float64, coreusage *ss.CpuCoreUsage) {
|
109
|
+
writer.WriteString(
|
110
|
+
fmt.Sprintf("%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n",
|
111
|
+
elapsed_time,
|
112
|
+
coreusage.User,
|
113
|
+
coreusage.Nice,
|
114
|
+
coreusage.Sys,
|
115
|
+
coreusage.Iowait,
|
116
|
+
coreusage.Hardirq,
|
117
|
+
coreusage.Softirq,
|
118
|
+
coreusage.Steal,
|
119
|
+
coreusage.Guest,
|
120
|
+
coreusage.Idle))
|
121
|
+
}
|
122
|
+
|
123
|
+
func main() {
|
124
|
+
opt := parseArgs()
|
125
|
+
|
126
|
+
var in *os.File
|
127
|
+
|
128
|
+
f, err := os.Open(opt.PerfmongerFile)
|
129
|
+
if err != nil {
|
130
|
+
panic(err)
|
131
|
+
}
|
132
|
+
in = f
|
133
|
+
defer f.Close()
|
134
|
+
|
135
|
+
dec := gob.NewDecoder(bufio.NewReader(in))
|
136
|
+
|
137
|
+
var cheader ss.CommonHeader
|
138
|
+
var pheader ss.PlatformHeader
|
139
|
+
var records = make([]ss.StatRecord, 2)
|
140
|
+
curr := 0
|
141
|
+
|
142
|
+
err = dec.Decode(&cheader)
|
143
|
+
if err == io.EOF {
|
144
|
+
return
|
145
|
+
}
|
146
|
+
if err != nil {
|
147
|
+
panic(err)
|
148
|
+
}
|
149
|
+
err = dec.Decode(&pheader)
|
150
|
+
if err == io.EOF {
|
151
|
+
return
|
152
|
+
}
|
153
|
+
if err != nil {
|
154
|
+
panic(err)
|
155
|
+
}
|
156
|
+
|
157
|
+
// read first record
|
158
|
+
err = dec.Decode(&records[curr])
|
159
|
+
if err == io.EOF {
|
160
|
+
return
|
161
|
+
} else if err != nil {
|
162
|
+
panic(err)
|
163
|
+
}
|
164
|
+
t0 := records[curr].Time
|
165
|
+
curr ^= 1
|
166
|
+
|
167
|
+
meta_set := false
|
168
|
+
meta := PlotMeta{}
|
169
|
+
meta.StartTime = float64(records[0].Time.UnixNano()) / 1.0e9
|
170
|
+
|
171
|
+
disk_dat_files := map[string]*DiskDatTmpFile{}
|
172
|
+
cpu_dat_files := make([]*CpuDatTmpFile, records[0].Cpu.NumCore)
|
173
|
+
meta.Cpu.NumCore = records[0].Cpu.NumCore
|
174
|
+
|
175
|
+
f, err = os.Create(opt.CpuFile)
|
176
|
+
if err != nil {
|
177
|
+
panic(err)
|
178
|
+
}
|
179
|
+
defer f.Close()
|
180
|
+
cpu_writer := bufio.NewWriter(f)
|
181
|
+
|
182
|
+
cpu_writer.WriteString("# All cpu usage\n")
|
183
|
+
cpu_writer.WriteString("# elapsed_time %usr %nice %sys %iowait %hardirq %softirq %steal %guest %idle\n")
|
184
|
+
|
185
|
+
for {
|
186
|
+
prev_rec := &records[curr^1]
|
187
|
+
cur_rec := &records[curr]
|
188
|
+
|
189
|
+
err := dec.Decode(cur_rec)
|
190
|
+
if err == io.EOF {
|
191
|
+
break
|
192
|
+
} else if err != nil {
|
193
|
+
panic(err)
|
194
|
+
}
|
195
|
+
|
196
|
+
// Disk usage
|
197
|
+
dusage, err := ss.GetDiskUsage(prev_rec.Time, prev_rec.Disk, cur_rec.Time, cur_rec.Disk)
|
198
|
+
if err != nil {
|
199
|
+
panic(err)
|
200
|
+
}
|
201
|
+
didx := 0
|
202
|
+
|
203
|
+
var dnames []string
|
204
|
+
for dname, _ := range *dusage {
|
205
|
+
if dname != "total" {
|
206
|
+
dnames = append(dnames, dname)
|
207
|
+
}
|
208
|
+
}
|
209
|
+
sort.Strings(dnames)
|
210
|
+
dnames = append(dnames, "total")
|
211
|
+
|
212
|
+
// for dname, dusage_entry := range *dusage {
|
213
|
+
for _, dname := range dnames {
|
214
|
+
dusage_entry, ok := (*dusage)[dname]
|
215
|
+
if !ok {
|
216
|
+
panic("device '" + dname + "' not found")
|
217
|
+
}
|
218
|
+
|
219
|
+
if !meta_set {
|
220
|
+
meta.Disk.Devices =
|
221
|
+
append(meta.Disk.Devices,
|
222
|
+
DiskMetaEntry{Name: dname, Idx: didx})
|
223
|
+
}
|
224
|
+
|
225
|
+
disk_dat, ok := disk_dat_files[dname]
|
226
|
+
if !ok {
|
227
|
+
disk_dat = makeDiskDatTmpFile(dname, didx)
|
228
|
+
disk_dat_files[dname] = disk_dat
|
229
|
+
defer disk_dat.File.Close()
|
230
|
+
|
231
|
+
disk_dat.Writer.WriteString("\n\n\n")
|
232
|
+
disk_dat.Writer.WriteString("# device: " + disk_dat.Name + "\n")
|
233
|
+
disk_dat.Writer.WriteString(fmt.Sprintln(
|
234
|
+
"# elapsed_time r_iops w_iops r_MB/s w_MB/s r_latency w_latency r_avgsz w_avgsz qdepth"))
|
235
|
+
}
|
236
|
+
|
237
|
+
elapsed_time := prev_rec.Time.Sub(t0).Seconds()
|
238
|
+
disk_dat.Writer.WriteString(
|
239
|
+
fmt.Sprintf("%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n",
|
240
|
+
elapsed_time,
|
241
|
+
dusage_entry.RdIops,
|
242
|
+
dusage_entry.WrIops,
|
243
|
+
dusage_entry.RdSecps*512.0/1024.0/1024.0,
|
244
|
+
dusage_entry.WrSecps*512.0/1024.0/1024.0,
|
245
|
+
dusage_entry.RdLatency,
|
246
|
+
dusage_entry.WrLatency,
|
247
|
+
dusage_entry.AvgRdSize,
|
248
|
+
dusage_entry.AvgWrSize,
|
249
|
+
dusage_entry.ReqQlen))
|
250
|
+
|
251
|
+
didx += 1
|
252
|
+
}
|
253
|
+
|
254
|
+
// Cpu usage
|
255
|
+
cusage, err := ss.GetCpuUsage(prev_rec.Cpu, cur_rec.Cpu)
|
256
|
+
if err != nil {
|
257
|
+
panic(err)
|
258
|
+
}
|
259
|
+
for coreid, coreusage := range cusage.CoreUsages {
|
260
|
+
cpu_dat := cpu_dat_files[coreid]
|
261
|
+
if cpu_dat == nil {
|
262
|
+
cpu_dat = makeCpuDatTmpFile(coreid)
|
263
|
+
cpu_dat_files[coreid] = cpu_dat
|
264
|
+
defer cpu_dat.File.Close()
|
265
|
+
|
266
|
+
cpu_dat.Writer.WriteString(fmt.Sprintf("\n\n\n# core: %d\n", coreid))
|
267
|
+
cpu_dat.Writer.WriteString("# elapsed_time %usr %nice %sys %iowait %hardirq %softirq %steal %guest %idle\n")
|
268
|
+
}
|
269
|
+
|
270
|
+
printCoreUsage(cpu_dat.Writer, prev_rec.Time.Sub(t0).Seconds(), coreusage)
|
271
|
+
}
|
272
|
+
printCoreUsage(cpu_writer, prev_rec.Time.Sub(t0).Seconds(), cusage.All)
|
273
|
+
|
274
|
+
curr ^= 1
|
275
|
+
meta_set = true
|
276
|
+
}
|
277
|
+
|
278
|
+
meta.EndTime = float64(records[curr^1].Time.UnixNano()) / 1.0e9
|
279
|
+
|
280
|
+
for _, disk_dat := range disk_dat_files {
|
281
|
+
disk_dat.Writer.Flush()
|
282
|
+
disk_dat.File.Close()
|
283
|
+
}
|
284
|
+
|
285
|
+
f, err = os.Create(opt.DiskFile)
|
286
|
+
if err != nil {
|
287
|
+
panic(err)
|
288
|
+
}
|
289
|
+
defer f.Close()
|
290
|
+
df_writer := bufio.NewWriter(f)
|
291
|
+
|
292
|
+
for _, dev := range meta.Disk.Devices {
|
293
|
+
disk_dat, ok := disk_dat_files[dev.Name]
|
294
|
+
if !ok {
|
295
|
+
panic(dev.Name)
|
296
|
+
}
|
297
|
+
|
298
|
+
content, err := ioutil.ReadFile(disk_dat.Path)
|
299
|
+
if err != nil {
|
300
|
+
panic(err)
|
301
|
+
}
|
302
|
+
|
303
|
+
df_writer.Write(content)
|
304
|
+
|
305
|
+
os.Remove(disk_dat.Path)
|
306
|
+
}
|
307
|
+
df_writer.Flush()
|
308
|
+
|
309
|
+
for _, cpu_dat := range cpu_dat_files {
|
310
|
+
cpu_dat.Writer.Flush()
|
311
|
+
cpu_dat.File.Close()
|
312
|
+
|
313
|
+
content, err := ioutil.ReadFile(cpu_dat.Path)
|
314
|
+
if err != nil {
|
315
|
+
panic(err)
|
316
|
+
}
|
317
|
+
|
318
|
+
cpu_writer.Write(content)
|
319
|
+
os.Remove(cpu_dat.Path)
|
320
|
+
}
|
321
|
+
cpu_writer.Flush()
|
322
|
+
|
323
|
+
json_enc := json.NewEncoder(os.Stdout)
|
324
|
+
json_enc.Encode(meta)
|
325
|
+
}
|
data/core/subsystem/usage.go
CHANGED
@@ -96,7 +96,19 @@ func GetCpuCoreUsage(c1 *CpuCoreStat, c2 *CpuCoreStat) (*CpuCoreUsage, error) {
|
|
96
96
|
itv := c2.Uptime() - c1.Uptime()
|
97
97
|
|
98
98
|
if itv == 0 {
|
99
|
-
return nil, errors.New("uptime difference is zero")
|
99
|
+
// return nil, errors.New("uptime difference is zero")
|
100
|
+
usage.User = 0
|
101
|
+
usage.Nice = 0
|
102
|
+
usage.Sys = 0
|
103
|
+
usage.Idle = 0
|
104
|
+
usage.Iowait = 0
|
105
|
+
usage.Hardirq = 0
|
106
|
+
usage.Softirq = 0
|
107
|
+
usage.Steal = 0
|
108
|
+
usage.Guest = 0
|
109
|
+
usage.GuestNice = 0
|
110
|
+
|
111
|
+
return usage, nil
|
100
112
|
} else if itv < 0 {
|
101
113
|
return nil, errors.New("uptime difference is negative")
|
102
114
|
}
|
data/lib/perfmonger.rb
CHANGED