perfmonger 0.10.2 → 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 ==")
|