perfmonger 0.10.2 → 0.12.1
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 +5 -5
- data/.gitignore +3 -0
- data/.travis.yml +9 -8
- data/HOWTO.md +0 -1
- data/NEWS +49 -5
- data/README.md +77 -27
- data/Rakefile +33 -11
- data/core/Makefile +22 -31
- data/core/build.sh +6 -8
- data/core/cmd/perfmonger-player/perfmonger-player.go +247 -0
- data/core/{perfmonger-plot-formatter.go → cmd/perfmonger-plot-formatter/perfmonger-plot-formatter.go} +20 -5
- data/core/{perfmonger-recorder.go → cmd/perfmonger-recorder/perfmonger-recorder.go} +22 -2
- data/core/{perfmonger-summarizer.go → cmd/perfmonger-summarizer/perfmonger-summarizer.go} +22 -15
- data/core/cmd/perfmonger-viewer/perfmonger-viewer.go +164 -0
- data/core/go.mod +10 -0
- data/core/go.sum +17 -0
- data/core/subsystem/Makefile +4 -0
- data/core/subsystem/perfmonger_linux.go +95 -0
- data/core/subsystem/perfmonger_linux_test.go +40 -0
- data/core/subsystem/stat.go +70 -0
- data/core/subsystem/stat_test.go +9 -0
- data/core/subsystem/usage.go +223 -66
- data/core/subsystem/usage_test.go +62 -32
- data/core/utils.go +2 -2
- data/{bin → exe}/perfmonger +0 -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/exec/perfmonger-viewer_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-viewer_linux_amd64 +0 -0
- data/lib/perfmonger/command/fingerprint.rb +26 -1
- data/lib/perfmonger/command/live.rb +19 -0
- data/lib/perfmonger/command/play.rb +16 -0
- data/lib/perfmonger/command/plot.rb +23 -9
- data/lib/perfmonger/command/record.rb +24 -3
- data/lib/perfmonger/command/record_option.rb +16 -0
- data/lib/perfmonger/command/server.rb +1 -1
- data/lib/perfmonger/version.rb +1 -1
- data/misc/werker-box/Dockerfile +34 -0
- data/misc/werker-box/build-push.sh +7 -0
- data/perfmonger.gemspec +2 -1
- data/spec/data/busy100.pgr.played +3 -3
- data/spec/fingerprint_spec.rb +1 -1
- data/spec/live_spec.rb +2 -3
- data/spec/perfmonger_spec.rb +1 -1
- data/spec/play_spec.rb +1 -1
- data/spec/plot_spec.rb +16 -1
- data/spec/record_spec.rb +10 -1
- data/spec/spec_helper.rb +28 -3
- data/spec/stat_spec.rb +2 -2
- data/spec/summary_spec.rb +1 -1
- data/wercker.yml +29 -16
- metadata +34 -14
- data/core/perfmonger-player.go +0 -196
- data/lib/exec/perfmonger-player_linux_386 +0 -0
- data/lib/exec/perfmonger-plot-formatter_linux_386 +0 -0
- data/lib/exec/perfmonger-recorder_linux_386 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
//usr/bin/env go run $0 $@ ; exit
|
2
|
+
|
3
|
+
package main
|
4
|
+
|
5
|
+
import (
|
6
|
+
"bufio"
|
7
|
+
"encoding/gob"
|
8
|
+
"flag"
|
9
|
+
"fmt"
|
10
|
+
"io"
|
11
|
+
"os"
|
12
|
+
|
13
|
+
projson "github.com/hayamiz/go-projson"
|
14
|
+
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
15
|
+
core "github.com/hayamiz/perfmonger/core"
|
16
|
+
)
|
17
|
+
|
18
|
+
type PlayerOption struct {
|
19
|
+
logfile string
|
20
|
+
color bool
|
21
|
+
pretty bool
|
22
|
+
}
|
23
|
+
|
24
|
+
var option PlayerOption
|
25
|
+
var init_rec ss.StatRecord
|
26
|
+
|
27
|
+
func showCpuStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
28
|
+
cusage, err := ss.GetCpuUsage(prev_rec.Cpu, cur_rec.Cpu)
|
29
|
+
if err != nil {
|
30
|
+
return err
|
31
|
+
}
|
32
|
+
|
33
|
+
printer.PutKey("cpu")
|
34
|
+
cusage.WriteJsonTo(printer)
|
35
|
+
|
36
|
+
return nil
|
37
|
+
}
|
38
|
+
|
39
|
+
func showInterruptStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
40
|
+
intr_usage, err := ss.GetInterruptUsage(
|
41
|
+
prev_rec.Time, prev_rec.Interrupt,
|
42
|
+
cur_rec.Time, cur_rec.Interrupt)
|
43
|
+
if err != nil {
|
44
|
+
return err
|
45
|
+
}
|
46
|
+
|
47
|
+
printer.PutKey("intr")
|
48
|
+
intr_usage.WriteJsonTo(printer)
|
49
|
+
|
50
|
+
return nil
|
51
|
+
}
|
52
|
+
|
53
|
+
func showDiskStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
54
|
+
dusage, err := ss.GetDiskUsage(
|
55
|
+
prev_rec.Time, prev_rec.Disk,
|
56
|
+
cur_rec.Time, cur_rec.Disk)
|
57
|
+
if err != nil {
|
58
|
+
return err
|
59
|
+
}
|
60
|
+
|
61
|
+
printer.PutKey("disk")
|
62
|
+
|
63
|
+
dusage.WriteJsonTo(printer)
|
64
|
+
|
65
|
+
return nil
|
66
|
+
}
|
67
|
+
|
68
|
+
func showNetStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
69
|
+
dusage, err := ss.GetNetUsage(
|
70
|
+
prev_rec.Time, prev_rec.Net,
|
71
|
+
cur_rec.Time, cur_rec.Net,
|
72
|
+
)
|
73
|
+
if err != nil {
|
74
|
+
return err
|
75
|
+
}
|
76
|
+
|
77
|
+
printer.PutKey("net")
|
78
|
+
|
79
|
+
dusage.WriteJsonTo(printer)
|
80
|
+
|
81
|
+
return nil
|
82
|
+
}
|
83
|
+
|
84
|
+
func showMemStat(printer *projson.JsonPrinter, cur_rec *ss.StatRecord) error {
|
85
|
+
musage, err := ss.GetMemUsage(cur_rec.Mem)
|
86
|
+
if err != nil {
|
87
|
+
return err
|
88
|
+
}
|
89
|
+
|
90
|
+
printer.PutKey("mem")
|
91
|
+
|
92
|
+
musage.WriteJsonTo(printer)
|
93
|
+
|
94
|
+
return nil
|
95
|
+
}
|
96
|
+
|
97
|
+
func showStat(printer *projson.JsonPrinter, prev_rec *ss.StatRecord, cur_rec *ss.StatRecord) error {
|
98
|
+
printer.Reset()
|
99
|
+
if option.pretty {
|
100
|
+
printer.SetStyle(projson.SmartStyle)
|
101
|
+
}
|
102
|
+
if option.color {
|
103
|
+
printer.SetColor(true)
|
104
|
+
}
|
105
|
+
printer.BeginObject()
|
106
|
+
printer.PutKey("time")
|
107
|
+
printer.PutFloatFmt(float64(cur_rec.Time.UnixNano())/1e9, "%.3f")
|
108
|
+
printer.PutKey("elapsed_time")
|
109
|
+
printer.PutFloatFmt((float64(cur_rec.Time.UnixNano())-float64(init_rec.Time.UnixNano()))/1e9,
|
110
|
+
"%.3f")
|
111
|
+
|
112
|
+
if cur_rec.Cpu != nil {
|
113
|
+
err := showCpuStat(printer, prev_rec, cur_rec)
|
114
|
+
if err != nil {
|
115
|
+
return err
|
116
|
+
}
|
117
|
+
}
|
118
|
+
if cur_rec.Interrupt != nil {
|
119
|
+
err := showInterruptStat(printer, prev_rec, cur_rec)
|
120
|
+
if err != nil {
|
121
|
+
return err
|
122
|
+
}
|
123
|
+
}
|
124
|
+
if cur_rec.Disk != nil {
|
125
|
+
err := showDiskStat(printer, prev_rec, cur_rec)
|
126
|
+
if err != nil {
|
127
|
+
return err
|
128
|
+
}
|
129
|
+
}
|
130
|
+
if cur_rec.Net != nil {
|
131
|
+
err := showNetStat(printer, prev_rec, cur_rec)
|
132
|
+
if err != nil {
|
133
|
+
return err
|
134
|
+
}
|
135
|
+
}
|
136
|
+
if cur_rec.Mem != nil {
|
137
|
+
err := showMemStat(printer, cur_rec)
|
138
|
+
if err != nil {
|
139
|
+
return err
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
printer.FinishObject()
|
144
|
+
|
145
|
+
return nil
|
146
|
+
}
|
147
|
+
|
148
|
+
func parseArgs() {
|
149
|
+
flag.BoolVar(&option.color, "color", false, "Use colored JSON output")
|
150
|
+
flag.BoolVar(&option.pretty, "pretty", false, "Use human readable JSON output")
|
151
|
+
|
152
|
+
flag.Parse()
|
153
|
+
|
154
|
+
option.logfile = flag.Arg(0)
|
155
|
+
}
|
156
|
+
|
157
|
+
func main() {
|
158
|
+
var in *os.File
|
159
|
+
var out *bufio.Writer
|
160
|
+
|
161
|
+
parseArgs()
|
162
|
+
|
163
|
+
if option.logfile == "" {
|
164
|
+
in = os.Stdin
|
165
|
+
} else {
|
166
|
+
f, err := os.Open(option.logfile)
|
167
|
+
if err != nil {
|
168
|
+
panic(err)
|
169
|
+
}
|
170
|
+
in = f
|
171
|
+
defer f.Close()
|
172
|
+
}
|
173
|
+
input_reader := core.NewPerfmongerLogReader(in)
|
174
|
+
dec := gob.NewDecoder(input_reader)
|
175
|
+
|
176
|
+
out = bufio.NewWriter(os.Stdout)
|
177
|
+
|
178
|
+
var cheader ss.CommonHeader
|
179
|
+
var pheader ss.PlatformHeader
|
180
|
+
var records = make([]ss.StatRecord, 2)
|
181
|
+
curr := 0
|
182
|
+
|
183
|
+
var err error
|
184
|
+
|
185
|
+
err = dec.Decode(&cheader)
|
186
|
+
if err == io.EOF {
|
187
|
+
return
|
188
|
+
}
|
189
|
+
if err != nil {
|
190
|
+
panic(err)
|
191
|
+
}
|
192
|
+
err = dec.Decode(&pheader)
|
193
|
+
if err == io.EOF {
|
194
|
+
return
|
195
|
+
}
|
196
|
+
if err != nil {
|
197
|
+
panic(err)
|
198
|
+
}
|
199
|
+
|
200
|
+
// read first record
|
201
|
+
err = dec.Decode(&records[curr])
|
202
|
+
if err == io.EOF {
|
203
|
+
return
|
204
|
+
} else if err != nil {
|
205
|
+
panic(err)
|
206
|
+
}
|
207
|
+
init_rec = records[curr]
|
208
|
+
curr ^= 1
|
209
|
+
|
210
|
+
printer := projson.NewPrinter()
|
211
|
+
for {
|
212
|
+
prev_rec := &records[curr^1]
|
213
|
+
cur_rec := &records[curr]
|
214
|
+
|
215
|
+
err = dec.Decode(cur_rec)
|
216
|
+
if err == io.EOF {
|
217
|
+
break
|
218
|
+
} else if err != nil {
|
219
|
+
panic(err)
|
220
|
+
}
|
221
|
+
|
222
|
+
err = showStat(printer, prev_rec, cur_rec)
|
223
|
+
if err != nil {
|
224
|
+
printer.Reset()
|
225
|
+
fmt.Fprintln(os.Stderr, "skip by err")
|
226
|
+
continue
|
227
|
+
}
|
228
|
+
|
229
|
+
if str, err := printer.String(); err != nil {
|
230
|
+
fmt.Println("error", err)
|
231
|
+
fmt.Println(str)
|
232
|
+
} else {
|
233
|
+
_, err = out.WriteString(str + "\n")
|
234
|
+
}
|
235
|
+
err = out.Flush()
|
236
|
+
if err != nil {
|
237
|
+
// stdout is closed
|
238
|
+
break
|
239
|
+
}
|
240
|
+
|
241
|
+
printer.Reset()
|
242
|
+
|
243
|
+
curr ^= 1
|
244
|
+
}
|
245
|
+
|
246
|
+
return
|
247
|
+
}
|
@@ -11,23 +11,31 @@ import (
|
|
11
11
|
"io"
|
12
12
|
"io/ioutil"
|
13
13
|
"os"
|
14
|
+
"regexp"
|
14
15
|
"sort"
|
15
16
|
|
16
17
|
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
18
|
+
"github.com/hayamiz/perfmonger/core"
|
17
19
|
)
|
18
20
|
|
19
21
|
type CmdOption struct {
|
20
|
-
DiskFile
|
21
|
-
CpuFile
|
22
|
-
PerfmongerFile
|
22
|
+
DiskFile string
|
23
|
+
CpuFile string
|
24
|
+
PerfmongerFile string
|
25
|
+
disk_only string
|
26
|
+
disk_only_regex *regexp.Regexp
|
23
27
|
}
|
24
28
|
|
25
29
|
func parseArgs() *CmdOption {
|
30
|
+
var err error
|
31
|
+
|
26
32
|
opt := new(CmdOption)
|
27
33
|
|
28
34
|
flag.StringVar(&opt.DiskFile, "diskfile", "./disk.dat", "Disk performance data file")
|
29
35
|
flag.StringVar(&opt.CpuFile, "cpufile", "./cpu.dat", "CPU performance data file")
|
30
36
|
flag.StringVar(&opt.PerfmongerFile, "perfmonger", "", "Perfmonger log file")
|
37
|
+
flag.StringVar(&opt.disk_only, "disk-only",
|
38
|
+
"", "Select disk devices by regex")
|
31
39
|
|
32
40
|
flag.Parse()
|
33
41
|
|
@@ -36,6 +44,11 @@ func parseArgs() *CmdOption {
|
|
36
44
|
os.Exit(1)
|
37
45
|
}
|
38
46
|
|
47
|
+
opt.disk_only_regex, err = regexp.Compile(opt.disk_only)
|
48
|
+
if err != nil {
|
49
|
+
panic(err)
|
50
|
+
}
|
51
|
+
|
39
52
|
return opt
|
40
53
|
}
|
41
54
|
|
@@ -129,7 +142,7 @@ func main() {
|
|
129
142
|
}
|
130
143
|
defer f.Close()
|
131
144
|
|
132
|
-
input_reader :=
|
145
|
+
input_reader := core.NewPerfmongerLogReader(f)
|
133
146
|
dec := gob.NewDecoder(input_reader)
|
134
147
|
|
135
148
|
var cheader ss.CommonHeader
|
@@ -192,7 +205,9 @@ func main() {
|
|
192
205
|
}
|
193
206
|
|
194
207
|
// Disk usage
|
195
|
-
dusage, err := ss.
|
208
|
+
dusage, err := ss.GetDiskUsage1(prev_rec.Time, prev_rec.Disk,
|
209
|
+
cur_rec.Time, cur_rec.Disk,
|
210
|
+
opt.disk_only_regex)
|
196
211
|
if err != nil {
|
197
212
|
panic(err)
|
198
213
|
}
|
@@ -36,6 +36,7 @@ type RecorderOption struct {
|
|
36
36
|
no_intr bool
|
37
37
|
no_disk bool
|
38
38
|
no_net bool
|
39
|
+
no_mem bool
|
39
40
|
debug bool
|
40
41
|
listDevices bool
|
41
42
|
player_bin string
|
@@ -43,6 +44,8 @@ type RecorderOption struct {
|
|
43
44
|
targetDisks *map[string]bool
|
44
45
|
background bool
|
45
46
|
gzip bool
|
47
|
+
color bool
|
48
|
+
pretty bool
|
46
49
|
}
|
47
50
|
|
48
51
|
var option RecorderOption
|
@@ -74,6 +77,8 @@ func parseArgs() {
|
|
74
77
|
false, "Do not record disk usage")
|
75
78
|
flag.BoolVar(&option.no_net, "no-net",
|
76
79
|
false, "Do not record net usage")
|
80
|
+
flag.BoolVar(&option.no_mem, "no-mem",
|
81
|
+
false, "Do not record memory usage")
|
77
82
|
flag.BoolVar(&option.debug, "debug",
|
78
83
|
false, "Enable debug mode")
|
79
84
|
flag.BoolVar(&option.listDevices, "list-devices",
|
@@ -86,6 +91,10 @@ func parseArgs() {
|
|
86
91
|
"", "Run perfmonger-player to show JSON output")
|
87
92
|
flag.BoolVar(&option.gzip, "gzip",
|
88
93
|
false, "Save a logfile in gzipped format")
|
94
|
+
flag.BoolVar(&option.color, "color",
|
95
|
+
false, "Colored output (for live subcmd)")
|
96
|
+
flag.BoolVar(&option.pretty, "pretty",
|
97
|
+
false, "Pretty output (for live subcmd)")
|
89
98
|
|
90
99
|
flag.Parse()
|
91
100
|
|
@@ -190,7 +199,7 @@ func main() {
|
|
190
199
|
parseArgs()
|
191
200
|
|
192
201
|
hostname, _ := os.Hostname()
|
193
|
-
cheader := &ss.CommonHeader{ss.Linux, hostname, time.Now()}
|
202
|
+
cheader := &ss.CommonHeader{Platform: ss.Linux, Hostname: hostname, StartTime: time.Now()}
|
194
203
|
|
195
204
|
platform_header := ss.NewPlatformHeader()
|
196
205
|
|
@@ -206,7 +215,15 @@ func main() {
|
|
206
215
|
var player_stdout io.ReadCloser = nil
|
207
216
|
|
208
217
|
if option.player_bin != "" {
|
209
|
-
|
218
|
+
if option.color {
|
219
|
+
if option.pretty {
|
220
|
+
player_cmd = exec.Command(option.player_bin, "-color", "-pretty")
|
221
|
+
} else {
|
222
|
+
player_cmd = exec.Command(option.player_bin, "-color")
|
223
|
+
}
|
224
|
+
} else {
|
225
|
+
player_cmd = exec.Command(option.player_bin)
|
226
|
+
}
|
210
227
|
player_stdin, err = player_cmd.StdinPipe()
|
211
228
|
if err != nil {
|
212
229
|
fmt.Fprintf(os.Stderr, "Failed to get stdin of %s", option.player_bin)
|
@@ -326,6 +343,9 @@ func main() {
|
|
326
343
|
if !option.no_net {
|
327
344
|
ss.ReadNetStat(record)
|
328
345
|
}
|
346
|
+
if !option.no_mem {
|
347
|
+
ss.ReadMemStat(record)
|
348
|
+
}
|
329
349
|
|
330
350
|
err = enc.Encode(record)
|
331
351
|
if err != nil {
|
@@ -3,7 +3,6 @@
|
|
3
3
|
package main
|
4
4
|
|
5
5
|
import (
|
6
|
-
"bytes"
|
7
6
|
"encoding/gob"
|
8
7
|
"flag"
|
9
8
|
"fmt"
|
@@ -12,7 +11,9 @@ import (
|
|
12
11
|
"regexp"
|
13
12
|
"sort"
|
14
13
|
|
14
|
+
projson "github.com/hayamiz/go-projson"
|
15
15
|
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
16
|
+
"github.com/hayamiz/perfmonger/core"
|
16
17
|
)
|
17
18
|
|
18
19
|
type SummaryOption struct {
|
@@ -61,7 +62,7 @@ func main() {
|
|
61
62
|
}
|
62
63
|
defer f.Close()
|
63
64
|
|
64
|
-
input_reader :=
|
65
|
+
input_reader := core.NewPerfmongerLogReader(f)
|
65
66
|
dec := gob.NewDecoder(input_reader)
|
66
67
|
|
67
68
|
err = dec.Decode(&cheader)
|
@@ -128,7 +129,7 @@ func main() {
|
|
128
129
|
option.disk_only_regex)
|
129
130
|
}
|
130
131
|
|
131
|
-
if fst_record.
|
132
|
+
if fst_record.Net != nil && lst_record.Net != nil {
|
132
133
|
net_usage, err = ss.GetNetUsage(
|
133
134
|
fst_record.Time, fst_record.Net,
|
134
135
|
lst_record.Time, lst_record.Net)
|
@@ -137,32 +138,38 @@ func main() {
|
|
137
138
|
interval := lst_record.Time.Sub(fst_record.Time)
|
138
139
|
|
139
140
|
if option.json {
|
140
|
-
|
141
|
+
printer := projson.NewPrinter()
|
141
142
|
|
142
|
-
|
143
|
+
printer.BeginObject()
|
144
|
+
printer.PutKey("exectime")
|
145
|
+
printer.PutFloatFmt(interval.Seconds(), "%.3f")
|
143
146
|
if cpu_usage != nil {
|
144
|
-
|
145
|
-
cpu_usage.WriteJsonTo(
|
147
|
+
printer.PutKey("cpu")
|
148
|
+
cpu_usage.WriteJsonTo(printer)
|
146
149
|
}
|
147
150
|
|
148
151
|
if intr_usage != nil {
|
149
|
-
|
150
|
-
intr_usage.WriteJsonTo(
|
152
|
+
printer.PutKey("intr")
|
153
|
+
intr_usage.WriteJsonTo(printer)
|
151
154
|
}
|
152
155
|
|
153
156
|
if disk_usage != nil {
|
154
|
-
|
155
|
-
disk_usage.WriteJsonTo(
|
157
|
+
printer.PutKey("disk")
|
158
|
+
disk_usage.WriteJsonTo(printer)
|
156
159
|
}
|
157
160
|
|
158
161
|
if net_usage != nil {
|
159
|
-
|
160
|
-
net_usage.WriteJsonTo(
|
162
|
+
printer.PutKey("net")
|
163
|
+
net_usage.WriteJsonTo(printer)
|
161
164
|
}
|
162
165
|
|
163
|
-
|
166
|
+
printer.FinishObject()
|
164
167
|
|
165
|
-
|
168
|
+
if str, err := printer.String(); err != nil {
|
169
|
+
fmt.Println("skip by err")
|
170
|
+
} else {
|
171
|
+
fmt.Println(str)
|
172
|
+
}
|
166
173
|
} else {
|
167
174
|
if option.title == "" {
|
168
175
|
fmt.Println("== performance summary ==")
|